~ubuntu-branches/ubuntu/natty/linux-ti-omap/natty

« back to all changes in this revision

Viewing changes to ubuntu/aufs/hnotify.c

  • Committer: Bazaar Package Importer
  • Author(s): Andy Whitcroft, Amit Kucheria, Imre Deak, Upstream Kernel Changes
  • Date: 2010-03-31 21:50:49 UTC
  • Revision ID: james.westby@ubuntu.com-20100331215049-8sypya8mpk81gun6
Tags: 2.6.33-500.4
[ Amit Kucheria ]

* [Config] Compile-in display subsystem
* Merge the DSS2 stack from 2.6.34-rc2 mainline tree
* SAUCE: Upgrade aufs2 to latest version for 2.6.33
  - LP: #548924
* [Config] Update configuration for new aufs2
* [Config] Fix d-i modules
* [Config] USB_STORAGE and ATA drivers can be a modules
* [Upstream] DSS2 support for Beagleboard
* [Config] Configure DSS2 based on beagle defconfig
* [Config] Enable USB OTG mode
* [Config] Enable various ethernet drivers

[ Imre Deak ]

* SAUCE: ARM: VFP: add support to sync the VFP state of the current
  thread
  - LP: #507503
* SAUCE: ARM: VFP: preserve the HW context when calling signal handlers
  - LP: #507503

[ Upstream Kernel Changes ]

* OMAP: DSS2: Add Sharp LQ043T1DG01 panel driver
* OMAP: DSS2: add Toppoly TDO35S panel
* OMAP: DSS: add TPO TD043MTEA1 panel
* OMAP: DSS2: Improve Kconfig help texts
* OMAP: DSS2: enable VDDS_DSI when using DPI
* OMAP: 3430SDP: remove vdvi regulator
* OMAP: DSS: Taal: fix error returns in taal_probe()
* OMAP: DSS2: OMAPFB: implement OMAPFB_GET_DISPLAY_INFO
* OMAP: DSS2: fix irq-stats compilation
* OMAP: DSS2: OMAPFB: Add omapfb_update_window prototype
* OMAP: DSS2: improve DSS clk src selection
* OMAP: DSS2: DSI: add dsi_bus_is_locked()
* OMAP: DSS2: DSI: add helpers for DCS read/write
* OMAP: DSS2: DSI: export dsi_vc_enable_hs()
* OMAP: DSS2: DSI: configure all DSI VCs
* OMAP: DSS2: DSI: remove dsi_vc_print_status()
* OMAP: DSS2: Check ctx loss count only when starting the first clock
* OMAP: DSS2: remove sub-panel system
* OMAP: DSS2: fix driver probe error handling
* OMAP: DSS2: OMAPFB: fix dssdev cleanup on error
* OMAP: DSS2: OMAPFB: fix cleanup on dssdev enable error
* OMAP: DSS2: fix get_dsi/dispc_clk_source() usage
* OMAP: DSS2: DSI: change DSI bus_lock to semaphore
* OMAP: DSS2: DSI: remove auto-update perf measurement
* OMAP: DSS2: move run_test()
* OMAP: DSS2: move memory_read()
* OMAP: DSS2: move set/get_mirror()
* OMAP: DSS2: move get/set_rotate()
* OMAP: DSS2: move wait_vsync()
* OMAP: DSS2: move enable/disable_channel to overlay manager
* OMAP: DSS2: move get_resolution()
* OMAP: DSS2: move get_recommended_bpp()
* OMAP: DSS2: move enable/get_te()
* OMAP: DSS2: move set/get_update_mode()
* OMAP: DSS2: move update() and sync()
* OMAP: DSS2: move enable/disable/suspend/resume
* OMAP: DSS2: move set/get_wss()
* OMAP: DSS2: move timing functions
* OMAP: DSS2: DSI: remove external TE support
* OMAP: DSS2: OMAPFB: Remove FB_OMAP2_FORCE_AUTO_UPDATE
* OMAP: DSS2: DSI: add dsi_vc_dcs_read_2() helper
* OMAP: DSS2: TPO-TD03MTEA1: fix function names
* OMAP: DSS2: DSI: add error prints
* OMAP: DSS2: OMAPFB: Constify some function parameters
* OMAP: DSS2: Taal: Fix ESD check
* OMAP: DSS2: Taal: Fix TE when resuming
* OMAP: DSS2: VRAM: Fix early_param for vram
* OMAP: DSS2: initialize dss clk sources properly
* OMAP: DSS2: panel-generic: re-implement mode changing

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2005-2010 Junjiro R. Okajima
 
3
 *
 
4
 * This program, aufs is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or
 
7
 * (at your option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful,
 
10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
12
 * GNU General Public License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU General Public License
 
15
 * along with this program; if not, write to the Free Software
 
16
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 */
 
18
 
 
19
/*
 
20
 * abstraction to notify the direct changes on lower directories
 
21
 */
 
22
 
 
23
#include "aufs.h"
 
24
 
 
25
int au_hn_alloc(struct au_hinode *hinode, struct inode *inode,
 
26
                struct inode *h_inode)
 
27
{
 
28
        int err;
 
29
        struct au_hnotify *hn;
 
30
 
 
31
        err = -ENOMEM;
 
32
        hn = au_cache_alloc_hnotify();
 
33
        if (hn) {
 
34
                hn->hn_aufs_inode = inode;
 
35
                err = au_hnotify_op.alloc(hn, h_inode);
 
36
                if (!err)
 
37
                        hinode->hi_notify = hn;
 
38
                else {
 
39
                        au_cache_free_hnotify(hn);
 
40
                        /*
 
41
                         * The upper dir was removed by udba, but the same named
 
42
                         * dir left. In this case, aufs assignes a new inode
 
43
                         * number and set the monitor again.
 
44
                         * For the lower dir, the old monitnor is still left.
 
45
                         */
 
46
                        if (err == -EEXIST)
 
47
                                err = 0;
 
48
                }
 
49
        }
 
50
 
 
51
        return err;
 
52
}
 
53
 
 
54
void au_hn_free(struct au_hinode *hinode)
 
55
{
 
56
        struct au_hnotify *hn;
 
57
 
 
58
        hn = hinode->hi_notify;
 
59
        if (hn) {
 
60
                au_hnotify_op.free(hn);
 
61
                au_cache_free_hnotify(hn);
 
62
                hinode->hi_notify = NULL;
 
63
        }
 
64
}
 
65
 
 
66
/* ---------------------------------------------------------------------- */
 
67
 
 
68
void au_hn_ctl(struct au_hinode *hinode, int do_set)
 
69
{
 
70
        if (hinode->hi_notify)
 
71
                au_hnotify_op.ctl(hinode, do_set);
 
72
}
 
73
 
 
74
void au_hn_reset(struct inode *inode, unsigned int flags)
 
75
{
 
76
        aufs_bindex_t bindex, bend;
 
77
        struct inode *hi;
 
78
        struct dentry *iwhdentry;
 
79
 
 
80
        bend = au_ibend(inode);
 
81
        for (bindex = au_ibstart(inode); bindex <= bend; bindex++) {
 
82
                hi = au_h_iptr(inode, bindex);
 
83
                if (!hi)
 
84
                        continue;
 
85
 
 
86
                /* mutex_lock_nested(&hi->i_mutex, AuLsc_I_CHILD); */
 
87
                iwhdentry = au_hi_wh(inode, bindex);
 
88
                if (iwhdentry)
 
89
                        dget(iwhdentry);
 
90
                au_igrab(hi);
 
91
                au_set_h_iptr(inode, bindex, NULL, 0);
 
92
                au_set_h_iptr(inode, bindex, au_igrab(hi),
 
93
                              flags & ~AuHi_XINO);
 
94
                iput(hi);
 
95
                dput(iwhdentry);
 
96
                /* mutex_unlock(&hi->i_mutex); */
 
97
        }
 
98
}
 
99
 
 
100
/* ---------------------------------------------------------------------- */
 
101
 
 
102
static int hn_xino(struct inode *inode, struct inode *h_inode)
 
103
{
 
104
        int err;
 
105
        aufs_bindex_t bindex, bend, bfound, bstart;
 
106
        struct inode *h_i;
 
107
 
 
108
        err = 0;
 
109
        if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
 
110
                pr_warning("branch root dir was changed\n");
 
111
                goto out;
 
112
        }
 
113
 
 
114
        bfound = -1;
 
115
        bend = au_ibend(inode);
 
116
        bstart = au_ibstart(inode);
 
117
#if 0 /* reserved for future use */
 
118
        if (bindex == bend) {
 
119
                /* keep this ino in rename case */
 
120
                goto out;
 
121
        }
 
122
#endif
 
123
        for (bindex = bstart; bindex <= bend; bindex++)
 
124
                if (au_h_iptr(inode, bindex) == h_inode) {
 
125
                        bfound = bindex;
 
126
                        break;
 
127
                }
 
128
        if (bfound < 0)
 
129
                goto out;
 
130
 
 
131
        for (bindex = bstart; bindex <= bend; bindex++) {
 
132
                h_i = au_h_iptr(inode, bindex);
 
133
                if (!h_i)
 
134
                        continue;
 
135
 
 
136
                err = au_xino_write(inode->i_sb, bindex, h_i->i_ino, /*ino*/0);
 
137
                /* ignore this error */
 
138
                /* bad action? */
 
139
        }
 
140
 
 
141
        /* children inode number will be broken */
 
142
 
 
143
 out:
 
144
        AuTraceErr(err);
 
145
        return err;
 
146
}
 
147
 
 
148
static int hn_gen_tree(struct dentry *dentry)
 
149
{
 
150
        int err, i, j, ndentry;
 
151
        struct au_dcsub_pages dpages;
 
152
        struct au_dpage *dpage;
 
153
        struct dentry **dentries;
 
154
 
 
155
        err = au_dpages_init(&dpages, GFP_NOFS);
 
156
        if (unlikely(err))
 
157
                goto out;
 
158
        err = au_dcsub_pages(&dpages, dentry, NULL, NULL);
 
159
        if (unlikely(err))
 
160
                goto out_dpages;
 
161
 
 
162
        for (i = 0; i < dpages.ndpage; i++) {
 
163
                dpage = dpages.dpages + i;
 
164
                dentries = dpage->dentries;
 
165
                ndentry = dpage->ndentry;
 
166
                for (j = 0; j < ndentry; j++) {
 
167
                        struct dentry *d;
 
168
 
 
169
                        d = dentries[j];
 
170
                        if (IS_ROOT(d))
 
171
                                continue;
 
172
 
 
173
                        d_drop(d);
 
174
                        au_digen_dec(d);
 
175
                        if (d->d_inode)
 
176
                                /* todo: reset children xino?
 
177
                                   cached children only? */
 
178
                                au_iigen_dec(d->d_inode);
 
179
                }
 
180
        }
 
181
 
 
182
 out_dpages:
 
183
        au_dpages_free(&dpages);
 
184
 
 
185
        /* discard children */
 
186
        dentry_unhash(dentry);
 
187
        dput(dentry);
 
188
 out:
 
189
        return err;
 
190
}
 
191
 
 
192
/*
 
193
 * return 0 if processed.
 
194
 */
 
195
static int hn_gen_by_inode(char *name, unsigned int nlen, struct inode *inode,
 
196
                           const unsigned int isdir)
 
197
{
 
198
        int err;
 
199
        struct dentry *d;
 
200
        struct qstr *dname;
 
201
 
 
202
        err = 1;
 
203
        if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
 
204
                pr_warning("branch root dir was changed\n");
 
205
                err = 0;
 
206
                goto out;
 
207
        }
 
208
 
 
209
        if (!isdir) {
 
210
                AuDebugOn(!name);
 
211
                au_iigen_dec(inode);
 
212
                spin_lock(&dcache_lock);
 
213
                list_for_each_entry(d, &inode->i_dentry, d_alias) {
 
214
                        dname = &d->d_name;
 
215
                        if (dname->len != nlen
 
216
                            && memcmp(dname->name, name, nlen))
 
217
                                continue;
 
218
                        err = 0;
 
219
                        spin_lock(&d->d_lock);
 
220
                        __d_drop(d);
 
221
                        au_digen_dec(d);
 
222
                        spin_unlock(&d->d_lock);
 
223
                        break;
 
224
                }
 
225
                spin_unlock(&dcache_lock);
 
226
        } else {
 
227
                au_fset_si(au_sbi(inode->i_sb), FAILED_REFRESH_DIRS);
 
228
                d = d_find_alias(inode);
 
229
                if (!d) {
 
230
                        au_iigen_dec(inode);
 
231
                        goto out;
 
232
                }
 
233
 
 
234
                dname = &d->d_name;
 
235
                if (dname->len == nlen && !memcmp(dname->name, name, nlen))
 
236
                        err = hn_gen_tree(d);
 
237
                dput(d);
 
238
        }
 
239
 
 
240
 out:
 
241
        AuTraceErr(err);
 
242
        return err;
 
243
}
 
244
 
 
245
static int hn_gen_by_name(struct dentry *dentry, const unsigned int isdir)
 
246
{
 
247
        int err;
 
248
        struct inode *inode;
 
249
 
 
250
        inode = dentry->d_inode;
 
251
        if (IS_ROOT(dentry)
 
252
            /* || (inode && inode->i_ino == AUFS_ROOT_INO) */
 
253
                ) {
 
254
                pr_warning("branch root dir was changed\n");
 
255
                return 0;
 
256
        }
 
257
 
 
258
        err = 0;
 
259
        if (!isdir) {
 
260
                d_drop(dentry);
 
261
                au_digen_dec(dentry);
 
262
                if (inode)
 
263
                        au_iigen_dec(inode);
 
264
        } else {
 
265
                au_fset_si(au_sbi(dentry->d_sb), FAILED_REFRESH_DIRS);
 
266
                if (inode)
 
267
                        err = hn_gen_tree(dentry);
 
268
        }
 
269
 
 
270
        AuTraceErr(err);
 
271
        return err;
 
272
}
 
273
 
 
274
/* ---------------------------------------------------------------------- */
 
275
 
 
276
/* hnotify job flags */
 
277
#define AuHnJob_XINO0           1
 
278
#define AuHnJob_GEN             (1 << 1)
 
279
#define AuHnJob_DIRENT          (1 << 2)
 
280
#define AuHnJob_ISDIR           (1 << 3)
 
281
#define AuHnJob_TRYXINO0        (1 << 4)
 
282
#define AuHnJob_MNTPNT          (1 << 5)
 
283
#define au_ftest_hnjob(flags, name)     ((flags) & AuHnJob_##name)
 
284
#define au_fset_hnjob(flags, name)      { (flags) |= AuHnJob_##name; }
 
285
#define au_fclr_hnjob(flags, name)      { (flags) &= ~AuHnJob_##name; }
 
286
 
 
287
enum {
 
288
        AuHn_CHILD,
 
289
        AuHn_PARENT,
 
290
        AuHnLast
 
291
};
 
292
 
 
293
struct au_hnotify_args {
 
294
        struct inode *h_dir, *dir, *h_child_inode;
 
295
        u32 mask;
 
296
        unsigned int flags[AuHnLast];
 
297
        unsigned int h_child_nlen;
 
298
        char h_child_name[];
 
299
};
 
300
 
 
301
struct hn_job_args {
 
302
        unsigned int flags;
 
303
        struct inode *inode, *h_inode, *dir, *h_dir;
 
304
        struct dentry *dentry;
 
305
        char *h_name;
 
306
        int h_nlen;
 
307
};
 
308
 
 
309
static int hn_job(struct hn_job_args *a)
 
310
{
 
311
        const unsigned int isdir = au_ftest_hnjob(a->flags, ISDIR);
 
312
 
 
313
        /* reset xino */
 
314
        if (au_ftest_hnjob(a->flags, XINO0) && a->inode)
 
315
                hn_xino(a->inode, a->h_inode); /* ignore this error */
 
316
 
 
317
        if (au_ftest_hnjob(a->flags, TRYXINO0)
 
318
            && a->inode
 
319
            && a->h_inode) {
 
320
                mutex_lock_nested(&a->h_inode->i_mutex, AuLsc_I_CHILD);
 
321
                if (!a->h_inode->i_nlink)
 
322
                        hn_xino(a->inode, a->h_inode); /* ignore this error */
 
323
                mutex_unlock(&a->h_inode->i_mutex);
 
324
        }
 
325
 
 
326
        /* make the generation obsolete */
 
327
        if (au_ftest_hnjob(a->flags, GEN)) {
 
328
                int err = -1;
 
329
                if (a->inode)
 
330
                        err = hn_gen_by_inode(a->h_name, a->h_nlen, a->inode,
 
331
                                              isdir);
 
332
                if (err && a->dentry)
 
333
                        hn_gen_by_name(a->dentry, isdir);
 
334
                /* ignore this error */
 
335
        }
 
336
 
 
337
        /* make dir entries obsolete */
 
338
        if (au_ftest_hnjob(a->flags, DIRENT) && a->inode) {
 
339
                struct au_vdir *vdir;
 
340
 
 
341
                vdir = au_ivdir(a->inode);
 
342
                if (vdir)
 
343
                        vdir->vd_jiffy = 0;
 
344
                /* IMustLock(a->inode); */
 
345
                /* a->inode->i_version++; */
 
346
        }
 
347
 
 
348
        /* can do nothing but warn */
 
349
        if (au_ftest_hnjob(a->flags, MNTPNT)
 
350
            && a->dentry
 
351
            && d_mountpoint(a->dentry))
 
352
                pr_warning("mount-point %.*s is removed or renamed\n",
 
353
                           AuDLNPair(a->dentry));
 
354
 
 
355
        return 0;
 
356
}
 
357
 
 
358
/* ---------------------------------------------------------------------- */
 
359
 
 
360
static struct dentry *lookup_wlock_by_name(char *name, unsigned int nlen,
 
361
                                           struct inode *dir)
 
362
{
 
363
        struct dentry *dentry, *d, *parent;
 
364
        struct qstr *dname;
 
365
 
 
366
        parent = d_find_alias(dir);
 
367
        if (!parent)
 
368
                return NULL;
 
369
 
 
370
        dentry = NULL;
 
371
        spin_lock(&dcache_lock);
 
372
        list_for_each_entry(d, &parent->d_subdirs, d_u.d_child) {
 
373
                /* AuDbg("%.*s\n", AuDLNPair(d)); */
 
374
                dname = &d->d_name;
 
375
                if (dname->len != nlen || memcmp(dname->name, name, nlen))
 
376
                        continue;
 
377
                if (!atomic_read(&d->d_count) || !d->d_fsdata) {
 
378
                        spin_lock(&d->d_lock);
 
379
                        __d_drop(d);
 
380
                        spin_unlock(&d->d_lock);
 
381
                        continue;
 
382
                }
 
383
 
 
384
                dentry = dget(d);
 
385
                break;
 
386
        }
 
387
        spin_unlock(&dcache_lock);
 
388
        dput(parent);
 
389
 
 
390
        if (dentry)
 
391
                di_write_lock_child(dentry);
 
392
 
 
393
        return dentry;
 
394
}
 
395
 
 
396
static struct inode *lookup_wlock_by_ino(struct super_block *sb,
 
397
                                         aufs_bindex_t bindex, ino_t h_ino)
 
398
{
 
399
        struct inode *inode;
 
400
        ino_t ino;
 
401
        int err;
 
402
 
 
403
        inode = NULL;
 
404
        err = au_xino_read(sb, bindex, h_ino, &ino);
 
405
        if (!err && ino)
 
406
                inode = ilookup(sb, ino);
 
407
        if (!inode)
 
408
                goto out;
 
409
 
 
410
        if (unlikely(inode->i_ino == AUFS_ROOT_INO)) {
 
411
                pr_warning("wrong root branch\n");
 
412
                iput(inode);
 
413
                inode = NULL;
 
414
                goto out;
 
415
        }
 
416
 
 
417
        ii_write_lock_child(inode);
 
418
 
 
419
 out:
 
420
        return inode;
 
421
}
 
422
 
 
423
static void au_hn_bh(void *_args)
 
424
{
 
425
        struct au_hnotify_args *a = _args;
 
426
        struct super_block *sb;
 
427
        aufs_bindex_t bindex, bend, bfound;
 
428
        unsigned char xino, try_iput;
 
429
        int err;
 
430
        struct inode *inode;
 
431
        ino_t h_ino;
 
432
        struct hn_job_args args;
 
433
        struct dentry *dentry;
 
434
        struct au_sbinfo *sbinfo;
 
435
 
 
436
        AuDebugOn(!_args);
 
437
        AuDebugOn(!a->h_dir);
 
438
        AuDebugOn(!a->dir);
 
439
        AuDebugOn(!a->mask);
 
440
        AuDbg("mask 0x%x, i%lu, hi%lu, hci%lu\n",
 
441
              a->mask, a->dir->i_ino, a->h_dir->i_ino,
 
442
              a->h_child_inode ? a->h_child_inode->i_ino : 0);
 
443
 
 
444
        inode = NULL;
 
445
        dentry = NULL;
 
446
        /*
 
447
         * do not lock a->dir->i_mutex here
 
448
         * because of d_revalidate() may cause a deadlock.
 
449
         */
 
450
        sb = a->dir->i_sb;
 
451
        AuDebugOn(!sb);
 
452
        sbinfo = au_sbi(sb);
 
453
        AuDebugOn(!sbinfo);
 
454
        /* big aufs lock */
 
455
        si_noflush_write_lock(sb);
 
456
 
 
457
        ii_read_lock_parent(a->dir);
 
458
        bfound = -1;
 
459
        bend = au_ibend(a->dir);
 
460
        for (bindex = au_ibstart(a->dir); bindex <= bend; bindex++)
 
461
                if (au_h_iptr(a->dir, bindex) == a->h_dir) {
 
462
                        bfound = bindex;
 
463
                        break;
 
464
                }
 
465
        ii_read_unlock(a->dir);
 
466
        if (unlikely(bfound < 0))
 
467
                goto out;
 
468
 
 
469
        xino = !!au_opt_test(au_mntflags(sb), XINO);
 
470
        h_ino = 0;
 
471
        if (a->h_child_inode)
 
472
                h_ino = a->h_child_inode->i_ino;
 
473
 
 
474
        if (a->h_child_nlen
 
475
            && (au_ftest_hnjob(a->flags[AuHn_CHILD], GEN)
 
476
                || au_ftest_hnjob(a->flags[AuHn_CHILD], MNTPNT)))
 
477
                dentry = lookup_wlock_by_name(a->h_child_name, a->h_child_nlen,
 
478
                                              a->dir);
 
479
        try_iput = 0;
 
480
        if (dentry)
 
481
                inode = dentry->d_inode;
 
482
        if (xino && !inode && h_ino
 
483
            && (au_ftest_hnjob(a->flags[AuHn_CHILD], XINO0)
 
484
                || au_ftest_hnjob(a->flags[AuHn_CHILD], TRYXINO0)
 
485
                || au_ftest_hnjob(a->flags[AuHn_CHILD], GEN))) {
 
486
                inode = lookup_wlock_by_ino(sb, bfound, h_ino);
 
487
                try_iput = 1;
 
488
            }
 
489
 
 
490
        args.flags = a->flags[AuHn_CHILD];
 
491
        args.dentry = dentry;
 
492
        args.inode = inode;
 
493
        args.h_inode = a->h_child_inode;
 
494
        args.dir = a->dir;
 
495
        args.h_dir = a->h_dir;
 
496
        args.h_name = a->h_child_name;
 
497
        args.h_nlen = a->h_child_nlen;
 
498
        err = hn_job(&args);
 
499
        if (dentry) {
 
500
                if (dentry->d_fsdata)
 
501
                        di_write_unlock(dentry);
 
502
                dput(dentry);
 
503
        }
 
504
        if (inode && try_iput) {
 
505
                ii_write_unlock(inode);
 
506
                iput(inode);
 
507
        }
 
508
 
 
509
        ii_write_lock_parent(a->dir);
 
510
        args.flags = a->flags[AuHn_PARENT];
 
511
        args.dentry = NULL;
 
512
        args.inode = a->dir;
 
513
        args.h_inode = a->h_dir;
 
514
        args.dir = NULL;
 
515
        args.h_dir = NULL;
 
516
        args.h_name = NULL;
 
517
        args.h_nlen = 0;
 
518
        err = hn_job(&args);
 
519
        ii_write_unlock(a->dir);
 
520
 
 
521
 out:
 
522
        au_nwt_done(&sbinfo->si_nowait);
 
523
        si_write_unlock(sb);
 
524
 
 
525
        iput(a->h_child_inode);
 
526
        iput(a->h_dir);
 
527
        iput(a->dir);
 
528
        kfree(a);
 
529
}
 
530
 
 
531
/* ---------------------------------------------------------------------- */
 
532
 
 
533
int au_hnotify(struct inode *h_dir, struct au_hnotify *hnotify, u32 mask,
 
534
               struct qstr *h_child_qstr, struct inode *h_child_inode)
 
535
{
 
536
        int err, len;
 
537
        unsigned int flags[AuHnLast];
 
538
        unsigned char isdir, isroot, wh;
 
539
        struct inode *dir;
 
540
        struct au_hnotify_args *args;
 
541
        char *p, *h_child_name;
 
542
 
 
543
        err = 0;
 
544
        AuDebugOn(!hnotify || !hnotify->hn_aufs_inode);
 
545
        dir = igrab(hnotify->hn_aufs_inode);
 
546
        if (!dir)
 
547
                goto out;
 
548
 
 
549
        isroot = (dir->i_ino == AUFS_ROOT_INO);
 
550
        wh = 0;
 
551
        h_child_name = (void *)h_child_qstr->name;
 
552
        len = h_child_qstr->len;
 
553
        if (h_child_name) {
 
554
                if (len > AUFS_WH_PFX_LEN
 
555
                    && !memcmp(h_child_name, AUFS_WH_PFX, AUFS_WH_PFX_LEN)) {
 
556
                        h_child_name += AUFS_WH_PFX_LEN;
 
557
                        len -= AUFS_WH_PFX_LEN;
 
558
                        wh = 1;
 
559
                }
 
560
        }
 
561
 
 
562
        isdir = 0;
 
563
        if (h_child_inode)
 
564
                isdir = !!S_ISDIR(h_child_inode->i_mode);
 
565
        flags[AuHn_PARENT] = AuHnJob_ISDIR;
 
566
        flags[AuHn_CHILD] = 0;
 
567
        if (isdir)
 
568
                flags[AuHn_CHILD] = AuHnJob_ISDIR;
 
569
        au_fset_hnjob(flags[AuHn_PARENT], DIRENT);
 
570
        au_fset_hnjob(flags[AuHn_CHILD], GEN);
 
571
        switch (mask & FS_EVENTS_POSS_ON_CHILD) {
 
572
        case FS_MOVED_FROM:
 
573
        case FS_MOVED_TO:
 
574
                au_fset_hnjob(flags[AuHn_CHILD], XINO0);
 
575
                au_fset_hnjob(flags[AuHn_CHILD], MNTPNT);
 
576
                /*FALLTHROUGH*/
 
577
        case FS_CREATE:
 
578
                AuDebugOn(!h_child_name || !h_child_inode);
 
579
                break;
 
580
 
 
581
        case FS_DELETE:
 
582
                /*
 
583
                 * aufs never be able to get this child inode.
 
584
                 * revalidation should be in d_revalidate()
 
585
                 * by checking i_nlink, i_generation or d_unhashed().
 
586
                 */
 
587
                AuDebugOn(!h_child_name);
 
588
                au_fset_hnjob(flags[AuHn_CHILD], TRYXINO0);
 
589
                au_fset_hnjob(flags[AuHn_CHILD], MNTPNT);
 
590
                break;
 
591
 
 
592
        default:
 
593
                AuDebugOn(1);
 
594
        }
 
595
 
 
596
        if (wh)
 
597
                h_child_inode = NULL;
 
598
 
 
599
        err = -ENOMEM;
 
600
        /* iput() and kfree() will be called in au_hnotify() */
 
601
        /*
 
602
         * inotify_mutex is already acquired and kmalloc/prune_icache may lock
 
603
         * iprune_mutex. strange.
 
604
         */
 
605
        /* lockdep_off(); */
 
606
        args = kmalloc(sizeof(*args) + len + 1, GFP_NOFS);
 
607
        /* lockdep_on(); */
 
608
        if (unlikely(!args)) {
 
609
                AuErr1("no memory\n");
 
610
                iput(dir);
 
611
                goto out;
 
612
        }
 
613
        args->flags[AuHn_PARENT] = flags[AuHn_PARENT];
 
614
        args->flags[AuHn_CHILD] = flags[AuHn_CHILD];
 
615
        args->mask = mask;
 
616
        args->dir = dir;
 
617
        args->h_dir = igrab(h_dir);
 
618
        if (h_child_inode)
 
619
                h_child_inode = igrab(h_child_inode); /* can be NULL */
 
620
        args->h_child_inode = h_child_inode;
 
621
        args->h_child_nlen = len;
 
622
        if (len) {
 
623
                p = (void *)args;
 
624
                p += sizeof(*args);
 
625
                memcpy(p, h_child_name, len);
 
626
                p[len] = 0;
 
627
        }
 
628
 
 
629
        /* lockdep_off(); */
 
630
        err = au_wkq_nowait(au_hn_bh, args, dir->i_sb);
 
631
        /* lockdep_on(); */
 
632
        if (unlikely(err)) {
 
633
                pr_err("wkq %d\n", err);
 
634
                iput(args->h_child_inode);
 
635
                iput(args->h_dir);
 
636
                iput(args->dir);
 
637
                kfree(args);
 
638
        }
 
639
 
 
640
out:
 
641
        return err;
 
642
}
 
643
 
 
644
static void au_hn_destroy_cache(void)
 
645
{
 
646
        kmem_cache_destroy(au_cachep[AuCache_HNOTIFY]);
 
647
        au_cachep[AuCache_HNOTIFY] = NULL;
 
648
}
 
649
 
 
650
int __init au_hnotify_init(void)
 
651
{
 
652
        int err;
 
653
 
 
654
        err = -ENOMEM;
 
655
        au_cachep[AuCache_HNOTIFY] = AuCache(au_hnotify);
 
656
        if (au_cachep[AuCache_HNOTIFY]) {
 
657
                err = au_hnotify_op.init();
 
658
                if (unlikely(err))
 
659
                        au_hn_destroy_cache();
 
660
        }
 
661
        AuTraceErr(err);
 
662
        return err;
 
663
}
 
664
 
 
665
void au_hnotify_fin(void)
 
666
{
 
667
        au_hnotify_op.fin();
 
668
        /* cf. au_cache_fin() */
 
669
        if (au_cachep[AuCache_HNOTIFY])
 
670
                au_hn_destroy_cache();
 
671
}