]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/vfs/vfs_fsevents.c
xnu-3789.60.24.tar.gz
[apple/xnu.git] / bsd / vfs / vfs_fsevents.c
index d2f32bd7489478e3af593ded542aacb3ed933dea..143f3cc11004f84fb6c499d1eca8b3a7cc2fb914 100644 (file)
@@ -121,7 +121,7 @@ typedef struct fs_event_watcher {
 #define WATCHER_CLOSING                0x0002
 #define WATCHER_WANTS_COMPACT_EVENTS   0x0004
 #define WATCHER_WANTS_EXTENDED_INFO    0x0008
-#define WATCHER_APPLE_SYSTEM_SERVICE   0x0010   // fseventsd, coreservicesd, mds
+#define WATCHER_APPLE_SYSTEM_SERVICE   0x0010   // fseventsd, coreservicesd, mds, revisiond
 
 #define MAX_WATCHERS  8
 static fs_event_watcher *watcher_table[MAX_WATCHERS];
@@ -140,6 +140,11 @@ static int        fs_event_init = 0;
 //
 static int16_t     fs_event_type_watchers[FSE_MAX_EVENTS];
 
+// the device currently being unmounted:
+static dev_t fsevent_unmount_dev = 0;
+// how many ACKs are still outstanding:
+static int fsevent_unmount_ack_count = 0;
+
 static int  watcher_add_event(fs_event_watcher *watcher, kfs_event *kfse);
 static void fsevents_wakeup(fs_event_watcher *watcher);
 
@@ -619,6 +624,19 @@ add_fsevent(int type, vfs_context_t ctx, ...)
            goto done_with_args;
     }
 
+    if (type == FSE_UNMOUNT_PENDING) {
+
+           // Just a dev_t
+           arg_type = va_arg(ap, int32_t);
+           if (arg_type == FSE_ARG_DEV) {
+                   cur->dev = (dev_t)(va_arg(ap, dev_t));
+           } else {
+                   cur->dev = (dev_t)0xbadc0de1;
+           }
+
+           goto done_with_args;
+    }
+
     for(arg_type=va_arg(ap, int32_t); arg_type != FSE_ARG_DONE; arg_type=va_arg(ap, int32_t))
 
        switch(arg_type) {
@@ -857,8 +875,8 @@ release_event_ref(kfs_event *kfse)
     // holding the fs_event_buf lock
     //
     copy = *kfse;
-    if (kfse->dest && OSAddAtomic(-1, &kfse->dest->refcount) == 1) {
-       dest_copy = *kfse->dest;
+    if (kfse->type != FSE_DOCID_CREATED && kfse->type != FSE_DOCID_CHANGED && kfse->dest && OSAddAtomic(-1, &kfse->dest->refcount) == 1) {
+           dest_copy = *kfse->dest;
     } else {
        dest_copy.str  = NULL;
        dest_copy.len  = 0;
@@ -906,7 +924,7 @@ release_event_ref(kfs_event *kfse)
     unlock_fs_event_list();
     
     // if we have a pointer in the union
-    if (copy.str && copy.type != FSE_DOCID_CHANGED) {
+    if (copy.str && copy.type != FSE_DOCID_CREATED && copy.type != FSE_DOCID_CHANGED) {
        if (copy.len == 0) {    // and it's not a string
            panic("%s:%d: no more fref.vp!\n", __FILE__, __LINE__);
            // vnode_rele_ext(copy.fref.vp, O_EVTONLY, 0);
@@ -965,6 +983,7 @@ add_watcher(int8_t *event_list, int32_t num_events, int32_t eventq_size, fs_even
 
     if (!strncmp(watcher->proc_name, "fseventsd", sizeof(watcher->proc_name)) ||
        !strncmp(watcher->proc_name, "coreservicesd", sizeof(watcher->proc_name)) ||
+       !strncmp(watcher->proc_name, "revisiond", sizeof(watcher->proc_name)) ||
        !strncmp(watcher->proc_name, "mds", sizeof(watcher->proc_name))) {
        watcher->flags |= WATCHER_APPLE_SYSTEM_SERVICE;
     } else {
@@ -1323,7 +1342,7 @@ copy_out_kfse(fs_event_watcher *watcher, kfs_event *kfse, struct uio *uio)
 
     if (kfse->type == FSE_DOCID_CHANGED || kfse->type == FSE_DOCID_CREATED) {
        dev_t    dev  = cur->dev;
-       ino_t    ino  = cur->ino;
+       ino64_t    ino  = cur->ino;
        uint64_t ival;
 
        error = fill_buff(FSE_ARG_DEV, sizeof(dev_t), &dev, evbuff, &evbuff_idx, sizeof(evbuff), uio);
@@ -1331,13 +1350,13 @@ copy_out_kfse(fs_event_watcher *watcher, kfs_event *kfse, struct uio *uio)
            goto get_out;
        }
 
-       error = fill_buff(FSE_ARG_INO, sizeof(ino_t), &ino, evbuff, &evbuff_idx, sizeof(evbuff), uio);
+       error = fill_buff(FSE_ARG_INO, sizeof(ino64_t), &ino, evbuff, &evbuff_idx, sizeof(evbuff), uio);
        if (error != 0) {
            goto get_out;
        }
 
-       memcpy(&ino, &cur->str, sizeof(ino_t));
-       error = fill_buff(FSE_ARG_INO, sizeof(ino_t), &ino, evbuff, &evbuff_idx, sizeof(evbuff), uio);
+       memcpy(&ino, &cur->str, sizeof(ino64_t));
+       error = fill_buff(FSE_ARG_INO, sizeof(ino64_t), &ino, evbuff, &evbuff_idx, sizeof(evbuff), uio);
        if (error != 0) {
            goto get_out;
        }
@@ -1351,6 +1370,17 @@ copy_out_kfse(fs_event_watcher *watcher, kfs_event *kfse, struct uio *uio)
        goto done;
     }
 
+    if (kfse->type == FSE_UNMOUNT_PENDING) {
+       dev_t    dev  = cur->dev;
+
+       error = fill_buff(FSE_ARG_DEV, sizeof(dev_t), &dev, evbuff, &evbuff_idx, sizeof(evbuff), uio);
+       if (error != 0) {
+           goto get_out;
+       }
+
+       goto done;
+    }
+
     if (cur->str == NULL || cur->str[0] == '\0') {
        printf("copy_out_kfse:2: empty/short path (%s)\n", cur->str);
        error = fill_buff(FSE_ARG_STRING, 2, "/", evbuff, &evbuff_idx, sizeof(evbuff), uio);
@@ -1379,15 +1409,12 @@ copy_out_kfse(fs_event_watcher *watcher, kfs_event *kfse, struct uio *uio)
            goto get_out;
        }
     } else {
-       ino_t ino;
-       
        error = fill_buff(FSE_ARG_DEV, sizeof(dev_t), &cur->dev, evbuff, &evbuff_idx, sizeof(evbuff), uio);
        if (error != 0) {
            goto get_out;
        }
 
-       ino = (ino_t)cur->ino;
-       error = fill_buff(FSE_ARG_INO, sizeof(ino_t), &ino, evbuff, &evbuff_idx, sizeof(evbuff), uio);
+       error = fill_buff(FSE_ARG_INO, sizeof(ino64_t), &cur->ino, evbuff, &evbuff_idx, sizeof(evbuff), uio);
        if (error != 0) {
            goto get_out;
        }
@@ -1541,7 +1568,7 @@ fmod_watch(fs_event_watcher *watcher, struct uio *uio)
 
        if (watcher->event_list[kfse->type] == FSE_REPORT && watcher_cares_about_dev(watcher, kfse->dev)) {
 
-         if (!(watcher->flags & WATCHER_APPLE_SYSTEM_SERVICE) && kfse->type != FSE_DOCID_CHANGED && is_ignored_directory(kfse->str)) {
+         if (!(watcher->flags & WATCHER_APPLE_SYSTEM_SERVICE) && kfse->type != FSE_DOCID_CREATED && kfse->type != FSE_DOCID_CHANGED && is_ignored_directory(kfse->str)) {
            // If this is not an Apple System Service, skip specified directories
            // radar://12034844
            error = 0;
@@ -1591,18 +1618,13 @@ fmod_watch(fs_event_watcher *watcher, struct uio *uio)
 }
 
 
-// release any references we might have on vnodes which are 
-// the mount point passed to us (so that it can be cleanly
-// unmounted).
 //
-// since we don't want to lose the events we'll convert the
-// vnode refs to full paths.
+// Shoo watchers away from a volume that's about to be unmounted
+// (so that it can be cleanly unmounted).
 //
 void
-fsevent_unmount(__unused struct mount *mp)
+fsevent_unmount(__unused struct mount *mp, __unused vfs_context_t ctx)
 {
-    // we no longer maintain pointers to vnodes so
-    // there is nothing to do... 
 }
 
 
@@ -1722,13 +1744,13 @@ fseventsf_ioctl(struct fileproc *fp, u_long cmd, caddr_t data, vfs_context_t ctx
            
            new_num_devices = devfilt_args->num_devices;
            if (new_num_devices == 0) {
-               tmp = fseh->watcher->devices_not_to_watch;
-
                lock_watch_table();
+
+               tmp = fseh->watcher->devices_not_to_watch;
                fseh->watcher->devices_not_to_watch = NULL;
                fseh->watcher->num_devices = new_num_devices;
-               unlock_watch_table();
 
+               unlock_watch_table();
                if (tmp) {
                    FREE(tmp, M_TEMP);
                }
@@ -1764,6 +1786,22 @@ fseventsf_ioctl(struct fileproc *fp, u_long cmd, caddr_t data, vfs_context_t ctx
            break;
        }           
 
+       case FSEVENTS_UNMOUNT_PENDING_ACK: {
+           lock_watch_table();
+           dev_t dev = *(dev_t *)data;
+           if (fsevent_unmount_dev == dev) {
+               if (--fsevent_unmount_ack_count <= 0) {
+                       fsevent_unmount_dev = 0;
+                       wakeup((caddr_t)&fsevent_unmount_dev);
+               }
+           } else {
+               printf("unexpected unmount pending ack %d (%d)\n", dev, fsevent_unmount_dev);
+               ret = EINVAL;
+           }
+           unlock_watch_table();
+           break;
+       }
+
        default:
            ret = EINVAL;
            break;
@@ -1895,28 +1933,84 @@ filt_fsevent(struct knote *kn, long hint)
 }
 
 
+static int
+filt_fsevent_touch(struct knote *kn, struct kevent_internal_s *kev)
+{
+       int res;
+
+       lock_watch_table();
+
+       /* accept new fflags/data as saved */
+       kn->kn_sfflags = kev->fflags;
+       kn->kn_sdata = kev->data;
+       if ((kn->kn_status & KN_UDATA_SPECIFIC) == 0)
+               kn->kn_udata = kev->udata;
+
+       /* restrict the current results to the (smaller?) set of new interest */
+       /*
+        * For compatibility with previous implementations, we leave kn_fflags
+        * as they were before.
+        */
+       //kn->kn_fflags &= kev->fflags;
+
+       /* determine if the filter is now fired */
+       res = filt_fsevent(kn, 0);
+
+       unlock_watch_table();
+
+       return res;
+}
+
+static int
+filt_fsevent_process(struct knote *kn, struct filt_process_s *data, struct kevent_internal_s *kev)
+{
+#pragma unused(data)
+       int res;
+
+       lock_watch_table();
+
+       res = filt_fsevent(kn, 0);
+       if (res) {
+               *kev = kn->kn_kevent;
+               if (kev->flags & EV_CLEAR) {
+                       kn->kn_data = 0;
+                       kn->kn_fflags = 0;
+               }
+       }
+
+       unlock_watch_table();
+       return res;
+}
+
 struct  filterops fsevent_filtops = { 
        .f_isfd = 1, 
        .f_attach = NULL, 
        .f_detach = filt_fsevent_detach, 
-       .f_event = filt_fsevent
+       .f_event = filt_fsevent,
+       .f_touch = filt_fsevent_touch,
+       .f_process = filt_fsevent_process,
 };
 
 static int
 fseventsf_kqfilter(__unused struct fileproc *fp, __unused struct knote *kn, __unused vfs_context_t ctx)
 {
     fsevent_handle *fseh = (struct fsevent_handle *)fp->f_fglob->fg_data;
+    int res;
 
     kn->kn_hook = (void*)fseh;
     kn->kn_hookid = 1;
-    kn->kn_fop = &fsevent_filtops;
-    
+       kn->kn_filtid = EVFILTID_FSEVENT;
+
     lock_watch_table();
 
     KNOTE_ATTACH(&fseh->knotes, kn);
 
+    /* check to see if it is fired already */
+    res = filt_fsevent(kn, 0);
+
     unlock_watch_table();
-    return 0;
+
+    return res;
 }
 
 
@@ -2147,14 +2241,14 @@ fseventswrite(__unused dev_t dev, struct uio *uio, __unused int ioflag)
 
 
 static const struct fileops fsevents_fops = {
-    DTYPE_FSEVENTS,
-    fseventsf_read,
-    fseventsf_write,
-    fseventsf_ioctl,
-    fseventsf_select,
-    fseventsf_close,
-    fseventsf_kqfilter,
-    fseventsf_drain
+    .fo_type = DTYPE_FSEVENTS,
+    .fo_read = fseventsf_read,
+    .fo_write = fseventsf_write,
+    .fo_ioctl = fseventsf_ioctl,
+    .fo_select = fseventsf_select,
+    .fo_close = fseventsf_close,
+    .fo_kqfilter = fseventsf_kqfilter,
+    .fo_drain = fseventsf_drain,
 };
 
 typedef struct fsevent_clone_args32 {
@@ -2461,6 +2555,9 @@ create_fsevent_from_kevent(vnode_t vp, uint32_t kevents, struct vnode_attr *vap)
 }
 
 #else /* CONFIG_FSE */
+
+#include <sys/fsevents.h>
+
 /*
  * The get_pathbuff and release_pathbuff routines are used in places not
  * related to fsevents, and it's a handy abstraction, so define trivial
@@ -2481,4 +2578,16 @@ release_pathbuff(char *path)
 {
        FREE_ZONE(path, MAXPATHLEN, M_NAMEI);
 }
+
+int
+add_fsevent(__unused int type, __unused vfs_context_t ctx, ...)
+{
+       return 0;
+}
+
+int need_fsevent(__unused int type, __unused vnode_t vp)
+{
+       return 0;
+}
+
 #endif /* CONFIG_FSE */