]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/notify/fsnotify.c
xps: Transmit Packet Steering
[net-next-2.6.git] / fs / notify / fsnotify.c
index 36802420d69a94024eefde05f1eab9f6a9932241..20dc218707ca59afc4c5b42de6cd7d614ca49340 100644 (file)
@@ -84,59 +84,39 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
 }
 
 /* Notify this dentry's parent about a child's events. */
-void __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
+int __fsnotify_parent(struct path *path, struct dentry *dentry, __u32 mask)
 {
        struct dentry *parent;
        struct inode *p_inode;
-       bool send = false;
-       bool should_update_children = false;
+       int ret = 0;
 
        if (!dentry)
                dentry = path->dentry;
 
        if (!(dentry->d_flags & DCACHE_FSNOTIFY_PARENT_WATCHED))
-               return;
+               return 0;
 
-       spin_lock(&dentry->d_lock);
-       parent = dentry->d_parent;
+       parent = dget_parent(dentry);
        p_inode = parent->d_inode;
 
-       if (fsnotify_inode_watches_children(p_inode)) {
-               if (p_inode->i_fsnotify_mask & mask) {
-                       dget(parent);
-                       send = true;
-               }
-       } else {
-               /*
-                * The parent doesn't care about events on it's children but
-                * at least one child thought it did.  We need to run all the
-                * children and update their d_flags to let them know p_inode
-                * doesn't care about them any more.
-                */
-               dget(parent);
-               should_update_children = true;
-       }
-
-       spin_unlock(&dentry->d_lock);
-
-       if (send) {
+       if (unlikely(!fsnotify_inode_watches_children(p_inode)))
+               __fsnotify_update_child_dentry_flags(p_inode);
+       else if (p_inode->i_fsnotify_mask & mask) {
                /* we are notifying a parent so come up with the new mask which
                 * specifies these are events which came from a child. */
                mask |= FS_EVENT_ON_CHILD;
 
                if (path)
-                       fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH,
-                                dentry->d_name.name, 0);
+                       ret = fsnotify(p_inode, mask, path, FSNOTIFY_EVENT_PATH,
+                                      dentry->d_name.name, 0);
                else
-                       fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
-                                dentry->d_name.name, 0);
-               dput(parent);
+                       ret = fsnotify(p_inode, mask, dentry->d_inode, FSNOTIFY_EVENT_INODE,
+                                      dentry->d_name.name, 0);
        }
 
-       if (unlikely(should_update_children)) {
-               __fsnotify_update_child_dentry_flags(p_inode);
-               dput(parent);
-       }
+       dput(parent);
+
+       return ret;
 }
 EXPORT_SYMBOL_GPL(__fsnotify_parent);
 
@@ -275,20 +255,23 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
 
                if (inode_group > vfsmount_group) {
                        /* handle inode */
-                       send_to_group(to_tell, NULL, inode_mark, NULL, mask, data,
-                                     data_is, cookie, file_name, &event);
+                       ret = send_to_group(to_tell, NULL, inode_mark, NULL, mask, data,
+                                           data_is, cookie, file_name, &event);
                        /* we didn't use the vfsmount_mark */
                        vfsmount_group = NULL;
                } else if (vfsmount_group > inode_group) {
-                       send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data,
-                                     data_is, cookie, file_name, &event);
+                       ret = send_to_group(to_tell, mnt, NULL, vfsmount_mark, mask, data,
+                                           data_is, cookie, file_name, &event);
                        inode_group = NULL;
                } else {
-                       send_to_group(to_tell, mnt, inode_mark, vfsmount_mark,
-                                     mask, data, data_is, cookie, file_name,
-                                     &event);
+                       ret = send_to_group(to_tell, mnt, inode_mark, vfsmount_mark,
+                                           mask, data, data_is, cookie, file_name,
+                                           &event);
                }
 
+               if (ret && (mask & ALL_FSNOTIFY_PERM_EVENTS))
+                       goto out;
+
                if (inode_group)
                        inode_node = srcu_dereference(inode_node->next,
                                                      &fsnotify_mark_srcu);
@@ -296,7 +279,8 @@ int fsnotify(struct inode *to_tell, __u32 mask, void *data, int data_is,
                        vfsmount_node = srcu_dereference(vfsmount_node->next,
                                                         &fsnotify_mark_srcu);
        }
-
+       ret = 0;
+out:
        srcu_read_unlock(&fsnotify_mark_srcu, idx);
        /*
         * fsnotify_create_event() took a reference so the event can't be cleaned