Merge git://git.kernel.org/pub/scm/linux/kernel/git/steve/gfs2-2.6-nmw
[linux-2.6] / fs / gfs2 / ops_dentry.c
1 /*
2  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
3  * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
4  *
5  * This copyrighted material is made available to anyone wishing to use,
6  * modify, copy, or redistribute it subject to the terms and conditions
7  * of the GNU General Public License version 2.
8  */
9
10 #include <linux/slab.h>
11 #include <linux/spinlock.h>
12 #include <linux/completion.h>
13 #include <linux/buffer_head.h>
14 #include <linux/gfs2_ondisk.h>
15 #include <linux/crc32.h>
16
17 #include "gfs2.h"
18 #include "incore.h"
19 #include "dir.h"
20 #include "glock.h"
21 #include "super.h"
22 #include "util.h"
23 #include "inode.h"
24
25 /**
26  * gfs2_drevalidate - Check directory lookup consistency
27  * @dentry: the mapping to check
28  * @nd:
29  *
30  * Check to make sure the lookup necessary to arrive at this inode from its
31  * parent is still good.
32  *
33  * Returns: 1 if the dentry is ok, 0 if it isn't
34  */
35
36 static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
37 {
38         struct dentry *parent = dget_parent(dentry);
39         struct gfs2_sbd *sdp = GFS2_SB(parent->d_inode);
40         struct gfs2_inode *dip = GFS2_I(parent->d_inode);
41         struct inode *inode = dentry->d_inode;
42         struct gfs2_holder d_gh;
43         struct gfs2_inode *ip = NULL;
44         int error;
45         int had_lock = 0;
46
47         if (inode) {
48                 if (is_bad_inode(inode))
49                         goto invalid;
50                 ip = GFS2_I(inode);
51         }
52
53         if (sdp->sd_args.ar_localcaching)
54                 goto valid;
55
56         had_lock = (gfs2_glock_is_locked_by_me(dip->i_gl) != NULL);
57         if (!had_lock) {
58                 error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
59                 if (error)
60                         goto fail;
61         } 
62
63         error = gfs2_dir_check(parent->d_inode, &dentry->d_name, ip);
64         switch (error) {
65         case 0:
66                 if (!inode)
67                         goto invalid_gunlock;
68                 break;
69         case -ENOENT:
70                 if (!inode)
71                         goto valid_gunlock;
72                 goto invalid_gunlock;
73         default:
74                 goto fail_gunlock;
75         }
76
77 valid_gunlock:
78         if (!had_lock)
79                 gfs2_glock_dq_uninit(&d_gh);
80 valid:
81         dput(parent);
82         return 1;
83
84 invalid_gunlock:
85         if (!had_lock)
86                 gfs2_glock_dq_uninit(&d_gh);
87 invalid:
88         if (inode && S_ISDIR(inode->i_mode)) {
89                 if (have_submounts(dentry))
90                         goto valid;
91                 shrink_dcache_parent(dentry);
92         }
93         d_drop(dentry);
94         dput(parent);
95         return 0;
96
97 fail_gunlock:
98         gfs2_glock_dq_uninit(&d_gh);
99 fail:
100         dput(parent);
101         return 0;
102 }
103
104 static int gfs2_dhash(struct dentry *dentry, struct qstr *str)
105 {
106         str->hash = gfs2_disk_hash(str->name, str->len);
107         return 0;
108 }
109
110 struct dentry_operations gfs2_dops = {
111         .d_revalidate = gfs2_drevalidate,
112         .d_hash = gfs2_dhash,
113 };
114