1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
4 | * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. |
5 | */ |
6 | |
7 | #include <linux/spinlock.h> |
8 | #include <linux/completion.h> |
9 | #include <linux/buffer_head.h> |
10 | #include <linux/gfs2_ondisk.h> |
11 | #include <linux/namei.h> |
12 | #include <linux/crc32.h> |
13 | |
14 | #include "gfs2.h" |
15 | #include "incore.h" |
16 | #include "dir.h" |
17 | #include "glock.h" |
18 | #include "super.h" |
19 | #include "util.h" |
20 | #include "inode.h" |
21 | |
22 | /** |
23 | * gfs2_drevalidate - Check directory lookup consistency |
24 | * @dentry: the mapping to check |
25 | * @flags: lookup flags |
26 | * |
27 | * Check to make sure the lookup necessary to arrive at this inode from its |
28 | * parent is still good. |
29 | * |
30 | * Returns: 1 if the dentry is ok, 0 if it isn't |
31 | */ |
32 | |
33 | static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags) |
34 | { |
35 | struct dentry *parent; |
36 | struct gfs2_sbd *sdp; |
37 | struct gfs2_inode *dip; |
38 | struct inode *inode; |
39 | struct gfs2_holder d_gh; |
40 | struct gfs2_inode *ip = NULL; |
41 | int error, valid = 0; |
42 | int had_lock = 0; |
43 | |
44 | if (flags & LOOKUP_RCU) |
45 | return -ECHILD; |
46 | |
47 | parent = dget_parent(dentry); |
48 | sdp = GFS2_SB(inode: d_inode(dentry: parent)); |
49 | dip = GFS2_I(inode: d_inode(dentry: parent)); |
50 | inode = d_inode(dentry); |
51 | |
52 | if (inode) { |
53 | if (is_bad_inode(inode)) |
54 | goto out; |
55 | ip = GFS2_I(inode); |
56 | } |
57 | |
58 | if (sdp->sd_lockstruct.ls_ops->lm_mount == NULL) { |
59 | valid = 1; |
60 | goto out; |
61 | } |
62 | |
63 | had_lock = (gfs2_glock_is_locked_by_me(gl: dip->i_gl) != NULL); |
64 | if (!had_lock) { |
65 | error = gfs2_glock_nq_init(gl: dip->i_gl, LM_ST_SHARED, flags: 0, gh: &d_gh); |
66 | if (error) |
67 | goto out; |
68 | } |
69 | |
70 | error = gfs2_dir_check(dir: d_inode(dentry: parent), filename: &dentry->d_name, ip); |
71 | valid = inode ? !error : (error == -ENOENT); |
72 | |
73 | if (!had_lock) |
74 | gfs2_glock_dq_uninit(gh: &d_gh); |
75 | out: |
76 | dput(parent); |
77 | return valid; |
78 | } |
79 | |
80 | static int gfs2_dhash(const struct dentry *dentry, struct qstr *str) |
81 | { |
82 | str->hash = gfs2_disk_hash(data: str->name, len: str->len); |
83 | return 0; |
84 | } |
85 | |
86 | static int gfs2_dentry_delete(const struct dentry *dentry) |
87 | { |
88 | struct gfs2_inode *ginode; |
89 | |
90 | if (d_really_is_negative(dentry)) |
91 | return 0; |
92 | |
93 | ginode = GFS2_I(inode: d_inode(dentry)); |
94 | if (!gfs2_holder_initialized(gh: &ginode->i_iopen_gh)) |
95 | return 0; |
96 | |
97 | if (test_bit(GLF_DEMOTE, &ginode->i_iopen_gh.gh_gl->gl_flags)) |
98 | return 1; |
99 | |
100 | return 0; |
101 | } |
102 | |
103 | const struct dentry_operations gfs2_dops = { |
104 | .d_revalidate = gfs2_drevalidate, |
105 | .d_hash = gfs2_dhash, |
106 | .d_delete = gfs2_dentry_delete, |
107 | }; |
108 | |
109 | |