]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/notify/inotify/inotify_user.c
fsnotify: fsnotify_add_notify_event should return an event
[net-next-2.6.git] / fs / notify / inotify / inotify_user.c
index a12315a7553ddcab9cb5555639a0889fa03d0d94..a4cd227c4c76fd06b65b761f453e7a053ca7c9e4 100644 (file)
@@ -46,7 +46,7 @@
 /* these are configurable via /proc/sys/fs/inotify/ */
 static int inotify_max_user_instances __read_mostly;
 static int inotify_max_queued_events __read_mostly;
-int inotify_max_user_watches __read_mostly;
+static int inotify_max_user_watches __read_mostly;
 
 static struct kmem_cache *inotify_inode_mark_cachep __read_mostly;
 struct kmem_cache *event_priv_cachep __read_mostly;
@@ -90,11 +90,14 @@ static inline __u32 inotify_arg_to_mask(u32 arg)
 {
        __u32 mask;
 
-       /* everything should accept their own ignored and cares about children */
-       mask = (FS_IN_IGNORED | FS_EVENT_ON_CHILD);
+       /*
+        * everything should accept their own ignored, cares about children,
+        * and should receive events when the inode is unmounted
+        */
+       mask = (FS_IN_IGNORED | FS_EVENT_ON_CHILD | FS_UNMOUNT);
 
        /* mask off the flags used to open the fd */
-       mask |= (arg & (IN_ALL_EVENTS | IN_ONESHOT));
+       mask |= (arg & (IN_ALL_EVENTS | IN_ONESHOT | IN_EXCL_UNLINK));
 
        return mask;
 }
@@ -138,6 +141,8 @@ static struct fsnotify_event *get_one_event(struct fsnotify_group *group,
 
        event = fsnotify_peek_notify_event(group);
 
+       pr_debug("%s: group=%p event=%p\n", __func__, group, event);
+
        if (event->name_len)
                event_size += roundup(event->name_len + 1, event_size);
 
@@ -167,6 +172,8 @@ static ssize_t copy_event_to_user(struct fsnotify_group *group,
        size_t event_size = sizeof(struct inotify_event);
        size_t name_len = 0;
 
+       pr_debug("%s: group=%p event=%p\n", __func__, group, event);
+
        /* we get the inotify watch descriptor from the event private data */
        spin_lock(&event->lock);
        fsn_priv = fsnotify_remove_priv_from_event(group, event);
@@ -239,6 +246,8 @@ static ssize_t inotify_read(struct file *file, char __user *buf,
                kevent = get_one_event(group, count);
                mutex_unlock(&group->notification_mutex);
 
+               pr_debug("%s: group=%p kevent=%p\n", __func__, group, kevent);
+
                if (kevent) {
                        ret = PTR_ERR(kevent);
                        if (IS_ERR(kevent))
@@ -283,6 +292,8 @@ static int inotify_release(struct inode *ignored, struct file *file)
        struct fsnotify_group *group = file->private_data;
        struct user_struct *user = group->inotify_data.user;
 
+       pr_debug("%s: group=%p\n", __func__, group);
+
        fsnotify_clear_marks_by_group(group);
 
        /* free this group, matching get was inotify_init->fsnotify_obtain_group */
@@ -306,6 +317,8 @@ static long inotify_ioctl(struct file *file, unsigned int cmd,
        group = file->private_data;
        p = (void __user *) arg;
 
+       pr_debug("%s: group=%p cmd=%u\n", __func__, group, cmd);
+
        switch (cmd) {
        case FIONREAD:
                mutex_lock(&group->notification_mutex);
@@ -503,7 +516,7 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
                                    struct fsnotify_group *group)
 {
        struct inotify_inode_mark *i_mark;
-       struct fsnotify_event *ignored_event;
+       struct fsnotify_event *ignored_event, *notify_event;
        struct inotify_event_private_data *event_priv;
        struct fsnotify_event_private_data *fsn_event_priv;
        int ret;
@@ -525,9 +538,14 @@ void inotify_ignored_and_remove_idr(struct fsnotify_mark *fsn_mark,
        fsn_event_priv->group = group;
        event_priv->wd = i_mark->wd;
 
-       ret = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv, NULL);
-       if (ret)
+       notify_event = fsnotify_add_notify_event(group, ignored_event, fsn_event_priv, NULL);
+       if (notify_event) {
+               if (IS_ERR(notify_event))
+                       ret = PTR_ERR(notify_event);
+               else
+                       fsnotify_put_event(notify_event);
                inotify_free_event_priv(fsn_event_priv);
+       }
 
 skip_send_ignore:
 
@@ -563,7 +581,7 @@ static int inotify_update_existing_watch(struct fsnotify_group *group,
 
        /* don't allow invalid bits: we don't want flags set */
        mask = inotify_arg_to_mask(arg);
-       if (unlikely(!mask))
+       if (unlikely(!(mask & IN_ALL_EVENTS)))
                return -EINVAL;
 
        fsn_mark = fsnotify_find_inode_mark(group, inode);
@@ -575,13 +593,11 @@ static int inotify_update_existing_watch(struct fsnotify_group *group,
        spin_lock(&fsn_mark->lock);
 
        old_mask = fsn_mark->mask;
-       if (add) {
-               fsn_mark->mask |= mask;
-               new_mask = fsn_mark->mask;
-       } else {
-               fsn_mark->mask = mask;
-               new_mask = fsn_mark->mask;
-       }
+       if (add)
+               fsnotify_set_mark_mask_locked(fsn_mark, (fsn_mark->mask | mask));
+       else
+               fsnotify_set_mark_mask_locked(fsn_mark, mask);
+       new_mask = fsn_mark->mask;
 
        spin_unlock(&fsn_mark->lock);
 
@@ -623,7 +639,7 @@ static int inotify_new_watch(struct fsnotify_group *group,
 
        /* don't allow invalid bits: we don't want flags set */
        mask = inotify_arg_to_mask(arg);
-       if (unlikely(!mask))
+       if (unlikely(!(mask & IN_ALL_EVENTS)))
                return -EINVAL;
 
        tmp_i_mark = kmem_cache_alloc(inotify_inode_mark_cachep, GFP_KERNEL);
@@ -838,6 +854,27 @@ out:
  */
 static int __init inotify_user_setup(void)
 {
+       BUILD_BUG_ON(IN_ACCESS != FS_ACCESS);
+       BUILD_BUG_ON(IN_MODIFY != FS_MODIFY);
+       BUILD_BUG_ON(IN_ATTRIB != FS_ATTRIB);
+       BUILD_BUG_ON(IN_CLOSE_WRITE != FS_CLOSE_WRITE);
+       BUILD_BUG_ON(IN_CLOSE_NOWRITE != FS_CLOSE_NOWRITE);
+       BUILD_BUG_ON(IN_OPEN != FS_OPEN);
+       BUILD_BUG_ON(IN_MOVED_FROM != FS_MOVED_FROM);
+       BUILD_BUG_ON(IN_MOVED_TO != FS_MOVED_TO);
+       BUILD_BUG_ON(IN_CREATE != FS_CREATE);
+       BUILD_BUG_ON(IN_DELETE != FS_DELETE);
+       BUILD_BUG_ON(IN_DELETE_SELF != FS_DELETE_SELF);
+       BUILD_BUG_ON(IN_MOVE_SELF != FS_MOVE_SELF);
+       BUILD_BUG_ON(IN_UNMOUNT != FS_UNMOUNT);
+       BUILD_BUG_ON(IN_Q_OVERFLOW != FS_Q_OVERFLOW);
+       BUILD_BUG_ON(IN_IGNORED != FS_IN_IGNORED);
+       BUILD_BUG_ON(IN_EXCL_UNLINK != FS_EXCL_UNLINK);
+       BUILD_BUG_ON(IN_ISDIR != FS_IN_ISDIR);
+       BUILD_BUG_ON(IN_ONESHOT != FS_IN_ONESHOT);
+
+       BUG_ON(hweight32(ALL_INOTIFY_BITS) != 21);
+
        inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark, SLAB_PANIC);
        event_priv_cachep = KMEM_CACHE(inotify_event_private_data, SLAB_PANIC);