~ubuntu-branches/debian/wheezy/linux-2.6/wheezy

« back to all changes in this revision

Viewing changes to fs/notify/inotify/inotify_fsnotify.c

  • Committer: Bazaar Package Importer
  • Author(s): Ben Hutchings, Ben Hutchings, Aurelien Jarno, Martin Michlmayr
  • Date: 2011-04-06 13:53:30 UTC
  • mfrom: (43.1.5 sid)
  • Revision ID: james.westby@ubuntu.com-20110406135330-wjufxhd0tvn3zx4z
Tags: 2.6.38-3
[ Ben Hutchings ]
* [ppc64] Add to linux-tools package architectures (Closes: #620124)
* [amd64] Save cr4 to mmu_cr4_features at boot time (Closes: #620284)
* appletalk: Fix bugs introduced when removing use of BKL
* ALSA: Fix yet another race in disconnection
* cciss: Fix lost command issue
* ath9k: Fix kernel panic in AR2427
* ses: Avoid kernel panic when lun 0 is not mapped
* PCI/ACPI: Report ASPM support to BIOS if not disabled from command line

[ Aurelien Jarno ]
* rtlwifi: fix build when PCI is not enabled.

[ Martin Michlmayr ]
* rtlwifi: Eliminate udelay calls with too large values (Closes: #620204)

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
 * General Public License for more details.
23
23
 */
24
24
 
 
25
#include <linux/dcache.h> /* d_unlinked */
25
26
#include <linux/fs.h> /* struct inode */
26
27
#include <linux/fsnotify_backend.h>
27
28
#include <linux/inotify.h>
28
29
#include <linux/path.h> /* struct path */
29
30
#include <linux/slab.h> /* kmem_* */
30
31
#include <linux/types.h>
 
32
#include <linux/sched.h>
31
33
 
32
34
#include "inotify.h"
33
35
 
34
 
static int inotify_handle_event(struct fsnotify_group *group, struct fsnotify_event *event)
35
 
{
36
 
        struct fsnotify_mark_entry *entry;
37
 
        struct inotify_inode_mark_entry *ientry;
 
36
/*
 
37
 * Check if 2 events contain the same information.  We do not compare private data
 
38
 * but at this moment that isn't a problem for any know fsnotify listeners.
 
39
 */
 
40
static bool event_compare(struct fsnotify_event *old, struct fsnotify_event *new)
 
41
{
 
42
        if ((old->mask == new->mask) &&
 
43
            (old->to_tell == new->to_tell) &&
 
44
            (old->data_type == new->data_type) &&
 
45
            (old->name_len == new->name_len)) {
 
46
                switch (old->data_type) {
 
47
                case (FSNOTIFY_EVENT_INODE):
 
48
                        /* remember, after old was put on the wait_q we aren't
 
49
                         * allowed to look at the inode any more, only thing
 
50
                         * left to check was if the file_name is the same */
 
51
                        if (!old->name_len ||
 
52
                            !strcmp(old->file_name, new->file_name))
 
53
                                return true;
 
54
                        break;
 
55
                case (FSNOTIFY_EVENT_PATH):
 
56
                        if ((old->path.mnt == new->path.mnt) &&
 
57
                            (old->path.dentry == new->path.dentry))
 
58
                                return true;
 
59
                        break;
 
60
                case (FSNOTIFY_EVENT_NONE):
 
61
                        if (old->mask & FS_Q_OVERFLOW)
 
62
                                return true;
 
63
                        else if (old->mask & FS_IN_IGNORED)
 
64
                                return false;
 
65
                        return true;
 
66
                };
 
67
        }
 
68
        return false;
 
69
}
 
70
 
 
71
static struct fsnotify_event *inotify_merge(struct list_head *list,
 
72
                                            struct fsnotify_event *event)
 
73
{
 
74
        struct fsnotify_event_holder *last_holder;
 
75
        struct fsnotify_event *last_event;
 
76
 
 
77
        /* and the list better be locked by something too */
 
78
        spin_lock(&event->lock);
 
79
 
 
80
        last_holder = list_entry(list->prev, struct fsnotify_event_holder, event_list);
 
81
        last_event = last_holder->event;
 
82
        if (event_compare(last_event, event))
 
83
                fsnotify_get_event(last_event);
 
84
        else
 
85
                last_event = NULL;
 
86
 
 
87
        spin_unlock(&event->lock);
 
88
 
 
89
        return last_event;
 
90
}
 
91
 
 
92
static int inotify_handle_event(struct fsnotify_group *group,
 
93
                                struct fsnotify_mark *inode_mark,
 
94
                                struct fsnotify_mark *vfsmount_mark,
 
95
                                struct fsnotify_event *event)
 
96
{
 
97
        struct inotify_inode_mark *i_mark;
38
98
        struct inode *to_tell;
39
99
        struct inotify_event_private_data *event_priv;
40
100
        struct fsnotify_event_private_data *fsn_event_priv;
41
 
        int wd, ret;
 
101
        struct fsnotify_event *added_event;
 
102
        int wd, ret = 0;
 
103
 
 
104
        BUG_ON(vfsmount_mark);
 
105
 
 
106
        pr_debug("%s: group=%p event=%p to_tell=%p mask=%x\n", __func__, group,
 
107
                 event, event->to_tell, event->mask);
42
108
 
43
109
        to_tell = event->to_tell;
44
110
 
45
 
        spin_lock(&to_tell->i_lock);
46
 
        entry = fsnotify_find_mark_entry(group, to_tell);
47
 
        spin_unlock(&to_tell->i_lock);
48
 
        /* race with watch removal?  We already passes should_send */
49
 
        if (unlikely(!entry))
50
 
                return 0;
51
 
        ientry = container_of(entry, struct inotify_inode_mark_entry,
52
 
                              fsn_entry);
53
 
        wd = ientry->wd;
 
111
        i_mark = container_of(inode_mark, struct inotify_inode_mark,
 
112
                              fsn_mark);
 
113
        wd = i_mark->wd;
54
114
 
55
115
        event_priv = kmem_cache_alloc(event_priv_cachep, GFP_KERNEL);
56
116
        if (unlikely(!event_priv))
61
121
        fsn_event_priv->group = group;
62
122
        event_priv->wd = wd;
63
123
 
64
 
        ret = fsnotify_add_notify_event(group, event, fsn_event_priv);
65
 
        if (ret) {
 
124
        added_event = fsnotify_add_notify_event(group, event, fsn_event_priv, inotify_merge);
 
125
        if (added_event) {
66
126
                inotify_free_event_priv(fsn_event_priv);
67
 
                /* EEXIST says we tail matched, EOVERFLOW isn't something
68
 
                 * to report up the stack. */
69
 
                if ((ret == -EEXIST) ||
70
 
                    (ret == -EOVERFLOW))
71
 
                        ret = 0;
 
127
                if (!IS_ERR(added_event))
 
128
                        fsnotify_put_event(added_event);
 
129
                else
 
130
                        ret = PTR_ERR(added_event);
72
131
        }
73
132
 
74
 
        /*
75
 
         * If we hold the entry until after the event is on the queue
76
 
         * IN_IGNORED won't be able to pass this event in the queue
77
 
         */
78
 
        fsnotify_put_mark(entry);
 
133
        if (inode_mark->mask & IN_ONESHOT)
 
134
                fsnotify_destroy_mark(inode_mark);
79
135
 
80
136
        return ret;
81
137
}
82
138
 
83
 
static void inotify_freeing_mark(struct fsnotify_mark_entry *entry, struct fsnotify_group *group)
 
139
static void inotify_freeing_mark(struct fsnotify_mark *fsn_mark, struct fsnotify_group *group)
84
140
{
85
 
        inotify_ignored_and_remove_idr(entry, group);
 
141
        inotify_ignored_and_remove_idr(fsn_mark, group);
86
142
}
87
143
 
88
 
static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode, __u32 mask)
 
144
static bool inotify_should_send_event(struct fsnotify_group *group, struct inode *inode,
 
145
                                      struct fsnotify_mark *inode_mark,
 
146
                                      struct fsnotify_mark *vfsmount_mark,
 
147
                                      __u32 mask, void *data, int data_type)
89
148
{
90
 
        struct fsnotify_mark_entry *entry;
91
 
        bool send;
92
 
 
93
 
        spin_lock(&inode->i_lock);
94
 
        entry = fsnotify_find_mark_entry(group, inode);
95
 
        spin_unlock(&inode->i_lock);
96
 
        if (!entry)
97
 
                return false;
98
 
 
99
 
        mask = (mask & ~FS_EVENT_ON_CHILD);
100
 
        send = (entry->mask & mask);
101
 
 
102
 
        /* find took a reference */
103
 
        fsnotify_put_mark(entry);
104
 
 
105
 
        return send;
 
149
        if ((inode_mark->mask & FS_EXCL_UNLINK) &&
 
150
            (data_type == FSNOTIFY_EVENT_PATH)) {
 
151
                struct path *path = data;
 
152
 
 
153
                if (d_unlinked(path->dentry))
 
154
                        return false;
 
155
        }
 
156
 
 
157
        return true;
106
158
}
107
159
 
108
160
/*
114
166
 */
115
167
static int idr_callback(int id, void *p, void *data)
116
168
{
117
 
        struct fsnotify_mark_entry *entry;
118
 
        struct inotify_inode_mark_entry *ientry;
 
169
        struct fsnotify_mark *fsn_mark;
 
170
        struct inotify_inode_mark *i_mark;
119
171
        static bool warned = false;
120
172
 
121
173
        if (warned)
122
174
                return 0;
123
175
 
124
 
        warned = false;
125
 
        entry = p;
126
 
        ientry = container_of(entry, struct inotify_inode_mark_entry, fsn_entry);
 
176
        warned = true;
 
177
        fsn_mark = p;
 
178
        i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);
127
179
 
128
 
        WARN(1, "inotify closing but id=%d for entry=%p in group=%p still in "
 
180
        WARN(1, "inotify closing but id=%d for fsn_mark=%p in group=%p still in "
129
181
                "idr.  Probably leaking memory\n", id, p, data);
130
182
 
131
183
        /*
134
186
         * out why we got here and the panic is no worse than the original
135
187
         * BUG() that was here.
136
188
         */
137
 
        if (entry)
138
 
                printk(KERN_WARNING "entry->group=%p inode=%p wd=%d\n",
139
 
                        entry->group, entry->inode, ientry->wd);
 
189
        if (fsn_mark)
 
190
                printk(KERN_WARNING "fsn_mark->group=%p inode=%p wd=%d\n",
 
191
                        fsn_mark->group, fsn_mark->i.inode, i_mark->wd);
140
192
        return 0;
141
193
}
142
194
 
146
198
        idr_for_each(&group->inotify_data.idr, idr_callback, group);
147
199
        idr_remove_all(&group->inotify_data.idr);
148
200
        idr_destroy(&group->inotify_data.idr);
 
201
        free_uid(group->inotify_data.user);
149
202
}
150
203
 
151
204
void inotify_free_event_priv(struct fsnotify_event_private_data *fsn_event_priv)