]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/vfs/vfs_fsevents.c
xnu-792.25.20.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_fsevents.c
index 5949b796ad1790168c259c60d27390feee63332f..801faa3c10644068d6f0af5c6273bc0c606b7fc0 100644 (file)
@@ -41,7 +41,6 @@
 #include <miscfs/specfs/specdev.h>
 #include <miscfs/devfs/devfs.h>
 #include <sys/filio.h>
-#include <architecture/byte_order.h>
 #include <kern/locks.h>
 #include <libkern/OSAtomic.h>
 
@@ -88,6 +87,7 @@ typedef struct fs_event_watcher {
     int32_t      eventq_size;            // number of event pointers in queue
     int32_t      rd, wr;                 // indices to the event_queue
     int32_t      blockers;
+    int32_t      num_readers;
 } fs_event_watcher;
 
 // fs_event_watcher flags
@@ -249,7 +249,7 @@ add_fsevent(int type, vfs_context_t ctx, ...)
     kfs_event        *kfse;
     fs_event_watcher *watcher;
     va_list           ap;
-    int              error = 0;
+    int              error = 0, base;
     dev_t             dev = 0;
 
     va_start(ap, ctx);
@@ -267,8 +267,9 @@ add_fsevent(int type, vfs_context_t ctx, ...)
     //       the lock is dropped.
     lock_fs_event_buf();
     
+    base = free_event_idx;
     for(i=0; i < MAX_KFS_EVENTS; i++) {
-       if (fs_event_buf[(free_event_idx + i) % MAX_KFS_EVENTS].type == FSE_INVALID) {
+       if (fs_event_buf[(base + i) % MAX_KFS_EVENTS].type == FSE_INVALID) {
            break;
        }
     }
@@ -290,12 +291,12 @@ add_fsevent(int type, vfs_context_t ctx, ...)
        return ENOSPC;
     }
 
-    kfse = &fs_event_buf[(free_event_idx + i) % MAX_KFS_EVENTS];
+    kfse = &fs_event_buf[(base + i) % MAX_KFS_EVENTS];
 
-    free_event_idx++;
+    free_event_idx = ((base + i) % MAX_KFS_EVENTS) + 1;
     
     kfse->type     = type;
-    kfse->refcount = 0;
+    kfse->refcount = 1;
     kfse->pid      = p->p_pid;
 
     unlock_fs_event_buf();  // at this point it's safe to unlock
@@ -462,9 +463,8 @@ add_fsevent(int type, vfs_context_t ctx, ...)
     
   clean_up:
     // just in case no one was interested after all...
-    if (num_deliveries == 0) {
+    if (OSAddAtomic(-1, (SInt32 *)&kfse->refcount) == 1) {
        do_free_event(kfse);
-       free_event_idx = (int)(kfse - &fs_event_buf[0]);
     }  
 
     lck_rw_done(&fsevent_big_lock);
@@ -479,8 +479,10 @@ do_free_event(kfs_event *kfse)
     
     lock_fs_event_buf();
     
-    // mark this fsevent as invalid
-    kfse->type = FSE_INVALID;
+    if (kfse->refcount > 0) {
+       panic("do_free_event: free'ing a kfsevent w/refcount == %d (kfse %p)\n",
+           kfse->refcount, kfse);
+    }
 
     // make a copy of this so we can free things without
     // holding the fs_event_buf lock
@@ -490,6 +492,9 @@ do_free_event(kfs_event *kfse)
     // and just to be anal, set this so that there are no args
     kfse->args[0].type = FSE_ARG_DONE;
     
+    // mark this fsevent as invalid
+    kfse->type = FSE_INVALID;
+
     free_event_idx = (kfse - fs_event_buf);
 
     unlock_fs_event_buf();
@@ -542,6 +547,7 @@ add_watcher(int8_t *event_list, int32_t num_events, int32_t eventq_size, fs_even
     watcher->rd           = 0;
     watcher->wr           = 0;
     watcher->blockers     = 0;
+    watcher->num_readers  = 0;
 
     lock_watch_list();
 
@@ -650,9 +656,15 @@ fmod_watch(fs_event_watcher *watcher, struct uio *uio)
        return EINVAL;
     }
 
+    if (OSAddAtomic(1, (SInt32 *)&watcher->num_readers) != 0) {
+       // don't allow multiple threads to read from the fd at the same time
+       OSAddAtomic(-1, (SInt32 *)&watcher->num_readers);
+       return EAGAIN;
+    }
 
     if (watcher->rd == watcher->wr) {
        if (watcher->flags & WATCHER_CLOSING) {
+           OSAddAtomic(-1, (SInt32 *)&watcher->num_readers);
            return 0;
        }
        OSAddAtomic(1, (SInt32 *)&watcher->blockers);
@@ -663,6 +675,7 @@ fmod_watch(fs_event_watcher *watcher, struct uio *uio)
        OSAddAtomic(-1, (SInt32 *)&watcher->blockers);
 
        if (error != 0 || (watcher->flags & WATCHER_CLOSING)) {
+           OSAddAtomic(-1, (SInt32 *)&watcher->num_readers);
            return error;
        }
     }
@@ -681,6 +694,7 @@ fmod_watch(fs_event_watcher *watcher, struct uio *uio)
        } 
 
        if (error) {
+           OSAddAtomic(-1, (SInt32 *)&watcher->num_readers);
            return error;
        }
        
@@ -850,6 +864,7 @@ fmod_watch(fs_event_watcher *watcher, struct uio *uio)
     }
 
   get_out:
+    OSAddAtomic(-1, (SInt32 *)&watcher->num_readers);
     return error;
 }
 
@@ -902,6 +917,9 @@ fsevent_unmount(struct mount *mp)
 
                        if (vname)
                                vnode_putname(vname);
+
+                       strcpy(pathbuff, "UNKNOWN-FILE");
+                       pathbuff_len = strlen(pathbuff) + 1;
                }
 
                // switch the type of the string
@@ -928,10 +946,13 @@ static int fsevents_installed = 0;
 static struct lock__bsd__ fsevents_lck;
 
 typedef struct fsevent_handle {
+    UInt32            flags;
+    SInt32            active;
     fs_event_watcher *watcher;
     struct selinfo    si;
 } fsevent_handle;
 
+#define FSEH_CLOSING   0x0001
 
 static int
 fseventsf_read(struct fileproc *fp, struct uio *uio,
@@ -963,15 +984,27 @@ fseventsf_ioctl(struct fileproc *fp, u_long cmd, caddr_t data, struct proc *p)
     pid_t pid = 0;
     fsevent_dev_filter_args *devfilt_args=(fsevent_dev_filter_args *)data;
 
+    OSAddAtomic(1, &fseh->active);
+    if (fseh->flags & FSEH_CLOSING) {
+       OSAddAtomic(-1, &fseh->active);
+       return 0;
+    }
+
     switch (cmd) {
        case FIONBIO:
        case FIOASYNC:
-           return 0;
+           ret = 0;
+           break;
 
        case FSEVENTS_DEVICE_FILTER: {
            int new_num_devices;
            dev_t *devices_to_watch, *tmp=NULL;
            
+           if (fseh->flags & FSEH_CLOSING) {
+               ret = 0;
+               break;
+           }
+
            if (devfilt_args->num_devices > 256) {
                ret = EINVAL;
                break;
@@ -1026,6 +1059,7 @@ fseventsf_ioctl(struct fileproc *fp, u_long cmd, caddr_t data, struct proc *p)
            break;
     }
 
+    OSAddAtomic(-1, &fseh->active);
     return (ret);
 }
 
@@ -1067,11 +1101,18 @@ static int
 fseventsf_close(struct fileglob *fg, struct proc *p)
 {
     fsevent_handle *fseh = (struct fsevent_handle *)fg->fg_data;
+    fs_event_watcher *watcher;
+    
+    OSBitOrAtomic(FSEH_CLOSING, &fseh->flags);
+    while (OSAddAtomic(0, &fseh->active) > 0) {
+       tsleep((caddr_t)fseh->watcher, PRIBIO, "fsevents-close", 1);
+    }
 
-    remove_watcher(fseh->watcher);
-
-    fg->fg_data = NULL;
+    watcher = fseh->watcher;
     fseh->watcher = NULL;
+    fg->fg_data = NULL;
+
+    remove_watcher(watcher);
     FREE(fseh, M_TEMP);
 
     return 0;
@@ -1210,7 +1251,7 @@ fseventsioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p)
                proc_fdunlock(p);
            copyout((void *)&fd, CAST_USER_ADDR_T(fse_clone_args->fd), sizeof(int32_t));
                proc_fdlock(p);
-           *fdflags(p, fd) &= ~UF_RESERVED;
+               procfdtbl_releasefd(p, fd, NULL);
                fp_drop(p, fd, f, 1);
                proc_fdunlock(p);
            break;