blob: 7f61392885194b2505411e15fe0704e1aa41fe9f [file] [log] [blame]
David Teiglandb3b94fa2006-01-16 16:50:04 +00001/*
2 * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved.
3 * Copyright (C) 2004-2005 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 v.2.
8 */
9
10#include <linux/sched.h>
11#include <linux/slab.h>
12#include <linux/spinlock.h>
13#include <linux/completion.h>
14#include <linux/buffer_head.h>
15#include <linux/smp_lock.h>
Steven Whitehouse5c676f62006-02-27 17:23:27 -050016#include <linux/gfs2_ondisk.h>
David Teiglandb3b94fa2006-01-16 16:50:04 +000017#include <asm/semaphore.h>
18
19#include "gfs2.h"
Steven Whitehouse5c676f62006-02-27 17:23:27 -050020#include "lm_interface.h"
21#include "incore.h"
David Teiglandb3b94fa2006-01-16 16:50:04 +000022#include "dir.h"
23#include "glock.h"
24#include "ops_dentry.h"
Steven Whitehouse5c676f62006-02-27 17:23:27 -050025#include "util.h"
David Teiglandb3b94fa2006-01-16 16:50:04 +000026
27/**
28 * gfs2_drevalidate - Check directory lookup consistency
29 * @dentry: the mapping to check
30 * @nd:
31 *
32 * Check to make sure the lookup necessary to arrive at this inode from its
33 * parent is still good.
34 *
35 * Returns: 1 if the dentry is ok, 0 if it isn't
36 */
37
38static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
39{
40 struct dentry *parent = dget_parent(dentry);
Steven Whitehouse5c676f62006-02-27 17:23:27 -050041 struct gfs2_inode *dip = parent->d_inode->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +000042 struct inode *inode;
43 struct gfs2_holder d_gh;
44 struct gfs2_inode *ip;
45 struct gfs2_inum inum;
46 unsigned int type;
47 int error;
48
49 lock_kernel();
50
David Teiglandb3b94fa2006-01-16 16:50:04 +000051 inode = dentry->d_inode;
52 if (inode && is_bad_inode(inode))
53 goto invalid;
54
55 error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &d_gh);
56 if (error)
57 goto fail;
58
59 error = gfs2_dir_search(dip, &dentry->d_name, &inum, &type);
60 switch (error) {
61 case 0:
62 if (!inode)
63 goto invalid_gunlock;
64 break;
65 case -ENOENT:
66 if (!inode)
67 goto valid_gunlock;
68 goto invalid_gunlock;
69 default:
70 goto fail_gunlock;
71 }
72
Steven Whitehouse5c676f62006-02-27 17:23:27 -050073 ip = inode->u.generic_ip;
David Teiglandb3b94fa2006-01-16 16:50:04 +000074
75 if (!gfs2_inum_equal(&ip->i_num, &inum))
76 goto invalid_gunlock;
77
78 if (IF2DT(ip->i_di.di_mode) != type) {
79 gfs2_consist_inode(dip);
80 goto fail_gunlock;
81 }
82
83 valid_gunlock:
84 gfs2_glock_dq_uninit(&d_gh);
85
86 valid:
87 unlock_kernel();
88 dput(parent);
89 return 1;
90
91 invalid_gunlock:
92 gfs2_glock_dq_uninit(&d_gh);
93
94 invalid:
95 if (inode && S_ISDIR(inode->i_mode)) {
96 if (have_submounts(dentry))
97 goto valid;
98 shrink_dcache_parent(dentry);
99 }
100 d_drop(dentry);
101
102 unlock_kernel();
103 dput(parent);
104 return 0;
105
106 fail_gunlock:
107 gfs2_glock_dq_uninit(&d_gh);
108
109 fail:
110 unlock_kernel();
111 dput(parent);
112 return 0;
113}
114
115struct dentry_operations gfs2_dops = {
116 .d_revalidate = gfs2_drevalidate,
117};
118