Skip to content

Commit 5be1fa8

Browse files
author
Al Viro
committed
Pass parent directory inode and expected name to ->d_revalidate()
->d_revalidate() often needs to access dentry parent and name; that has to be done carefully, since the locking environment varies from caller to caller. We are not guaranteed that dentry in question will not be moved right under us - not unless the filesystem is such that nothing on it ever gets renamed. It can be dealt with, but that results in boilerplate code that isn't even needed - the callers normally have just found the dentry via dcache lookup and want to verify that it's in the right place; they already have the values of ->d_parent and ->d_name stable. There is a couple of exceptions (overlayfs and, to less extent, ecryptfs), but for the majority of calls that song and dance is not needed at all. It's easier to make ecryptfs and overlayfs find and pass those values if there's a ->d_revalidate() instance to be called, rather than doing that in the instances. This commit only changes the calling conventions; making use of supplied values is left to followups. NOTE: some instances need more than just the parent - things like CIFS may need to build an entire path from filesystem root, so they need more precautions than the usual boilerplate. This series doesn't do anything to that need - these filesystems have to keep their locking mechanisms (rename_lock loops, use of dentry_path_raw(), private rwsem a-la v9fs). One thing to keep in mind when using name is that name->name will normally point into the pathname being resolved; the filename in question occupies name->len bytes starting at name->name, and there is NUL somewhere after it, but it the next byte might very well be '/' rather than '\0'. Do not ignore name->len. Reviewed-by: Jeff Layton <[email protected]> Reviewed-by: Gabriel Krisman Bertazi <[email protected]> Signed-off-by: Al Viro <[email protected]>
1 parent 4c43ab1 commit 5be1fa8

File tree

30 files changed

+136
-51
lines changed

30 files changed

+136
-51
lines changed

Documentation/filesystems/locking.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@ dentry_operations
1717

1818
prototypes::
1919

20-
int (*d_revalidate)(struct dentry *, unsigned int);
20+
int (*d_revalidate)(struct inode *, const struct qstr *,
21+
struct dentry *, unsigned int);
2122
int (*d_weak_revalidate)(struct dentry *, unsigned int);
2223
int (*d_hash)(const struct dentry *, struct qstr *);
2324
int (*d_compare)(const struct dentry *,

Documentation/filesystems/porting.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,3 +1141,19 @@ pointer are gone.
11411141

11421142
set_blocksize() takes opened struct file instead of struct block_device now
11431143
and it *must* be opened exclusive.
1144+
1145+
---
1146+
1147+
** mandatory**
1148+
1149+
->d_revalidate() gets two extra arguments - inode of parent directory and
1150+
name our dentry is expected to have. Both are stable (dir is pinned in
1151+
non-RCU case and will stay around during the call in RCU case, and name
1152+
is guaranteed to stay unchanging). Your instance doesn't have to use
1153+
either, but it often helps to avoid a lot of painful boilerplate.
1154+
Note that while name->name is stable and NUL-terminated, it may (and
1155+
often will) have name->name[name->len] equal to '/' rather than '\0' -
1156+
in normal case it points into the pathname being looked up.
1157+
NOTE: if you need something like full path from the root of filesystem,
1158+
you are still on your own - this assists with simple cases, but it's not
1159+
magic.

Documentation/filesystems/vfs.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1251,7 +1251,8 @@ defined:
12511251
.. code-block:: c
12521252
12531253
struct dentry_operations {
1254-
int (*d_revalidate)(struct dentry *, unsigned int);
1254+
int (*d_revalidate)(struct inode *, const struct qstr *,
1255+
struct dentry *, unsigned int);
12551256
int (*d_weak_revalidate)(struct dentry *, unsigned int);
12561257
int (*d_hash)(const struct dentry *, struct qstr *);
12571258
int (*d_compare)(const struct dentry *,

fs/9p/vfs_dentry.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ static void v9fs_dentry_release(struct dentry *dentry)
6161
p9_fid_put(hlist_entry(p, struct p9_fid, dlist));
6262
}
6363

64-
static int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
64+
static int __v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
6565
{
6666
struct p9_fid *fid;
6767
struct inode *inode;
@@ -99,9 +99,15 @@ static int v9fs_lookup_revalidate(struct dentry *dentry, unsigned int flags)
9999
return 1;
100100
}
101101

102+
static int v9fs_lookup_revalidate(struct inode *dir, const struct qstr *name,
103+
struct dentry *dentry, unsigned int flags)
104+
{
105+
return __v9fs_lookup_revalidate(dentry, flags);
106+
}
107+
102108
const struct dentry_operations v9fs_cached_dentry_operations = {
103109
.d_revalidate = v9fs_lookup_revalidate,
104-
.d_weak_revalidate = v9fs_lookup_revalidate,
110+
.d_weak_revalidate = __v9fs_lookup_revalidate,
105111
.d_delete = v9fs_cached_dentry_delete,
106112
.d_release = v9fs_dentry_release,
107113
};

fs/afs/dir.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
2222
unsigned int flags);
2323
static int afs_dir_open(struct inode *inode, struct file *file);
2424
static int afs_readdir(struct file *file, struct dir_context *ctx);
25-
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
25+
static int afs_d_revalidate(struct inode *dir, const struct qstr *name,
26+
struct dentry *dentry, unsigned int flags);
2627
static int afs_d_delete(const struct dentry *dentry);
2728
static void afs_d_iput(struct dentry *dentry, struct inode *inode);
2829
static bool afs_lookup_one_filldir(struct dir_context *ctx, const char *name, int nlen,
@@ -1093,7 +1094,8 @@ static int afs_d_revalidate_rcu(struct dentry *dentry)
10931094
* - NOTE! the hit can be a negative hit too, so we can't assume we have an
10941095
* inode
10951096
*/
1096-
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
1097+
static int afs_d_revalidate(struct inode *parent_dir, const struct qstr *name,
1098+
struct dentry *dentry, unsigned int flags)
10971099
{
10981100
struct afs_vnode *vnode, *dir;
10991101
struct afs_fid fid;

fs/ceph/dir.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1940,15 +1940,16 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry,
19401940
/*
19411941
* Check if cached dentry can be trusted.
19421942
*/
1943-
static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
1943+
static int ceph_d_revalidate(struct inode *parent_dir, const struct qstr *name,
1944+
struct dentry *dentry, unsigned int flags)
19441945
{
19451946
struct ceph_mds_client *mdsc = ceph_sb_to_fs_client(dentry->d_sb)->mdsc;
19461947
struct ceph_client *cl = mdsc->fsc->client;
19471948
int valid = 0;
19481949
struct dentry *parent;
19491950
struct inode *dir, *inode;
19501951

1951-
valid = fscrypt_d_revalidate(dentry, flags);
1952+
valid = fscrypt_d_revalidate(parent_dir, name, dentry, flags);
19521953
if (valid <= 0)
19531954
return valid;
19541955

fs/coda/dir.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,8 @@ static int coda_readdir(struct file *coda_file, struct dir_context *ctx)
445445
}
446446

447447
/* called when a cache lookup succeeds */
448-
static int coda_dentry_revalidate(struct dentry *de, unsigned int flags)
448+
static int coda_dentry_revalidate(struct inode *dir, const struct qstr *name,
449+
struct dentry *de, unsigned int flags)
449450
{
450451
struct inode *inode;
451452
struct coda_inode_info *cii;

fs/crypto/fname.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -574,7 +574,8 @@ EXPORT_SYMBOL_GPL(fscrypt_fname_siphash);
574574
* Validate dentries in encrypted directories to make sure we aren't potentially
575575
* caching stale dentries after a key has been added.
576576
*/
577-
int fscrypt_d_revalidate(struct dentry *dentry, unsigned int flags)
577+
int fscrypt_d_revalidate(struct inode *parent_dir, const struct qstr *name,
578+
struct dentry *dentry, unsigned int flags)
578579
{
579580
struct dentry *dir;
580581
int err;

fs/ecryptfs/dentry.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717

1818
/**
1919
* ecryptfs_d_revalidate - revalidate an ecryptfs dentry
20-
* @dentry: The ecryptfs dentry
20+
* @dir: inode of expected parent
21+
* @name: expected name
22+
* @dentry: dentry to revalidate
2123
* @flags: lookup flags
2224
*
2325
* Called when the VFS needs to revalidate a dentry. This
@@ -28,16 +30,24 @@
2830
* Returns 1 if valid, 0 otherwise.
2931
*
3032
*/
31-
static int ecryptfs_d_revalidate(struct dentry *dentry, unsigned int flags)
33+
static int ecryptfs_d_revalidate(struct inode *dir, const struct qstr *name,
34+
struct dentry *dentry, unsigned int flags)
3235
{
3336
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
3437
int rc = 1;
3538

3639
if (flags & LOOKUP_RCU)
3740
return -ECHILD;
3841

39-
if (lower_dentry->d_flags & DCACHE_OP_REVALIDATE)
40-
rc = lower_dentry->d_op->d_revalidate(lower_dentry, flags);
42+
if (lower_dentry->d_flags & DCACHE_OP_REVALIDATE) {
43+
struct inode *lower_dir = ecryptfs_inode_to_lower(dir);
44+
struct name_snapshot n;
45+
46+
take_dentry_name_snapshot(&n, lower_dentry);
47+
rc = lower_dentry->d_op->d_revalidate(lower_dir, &n.name,
48+
lower_dentry, flags);
49+
release_dentry_name_snapshot(&n);
50+
}
4151

4252
if (d_really_is_positive(dentry)) {
4353
struct inode *inode = d_inode(dentry);

fs/exfat/namei.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ static inline void exfat_d_version_set(struct dentry *dentry,
3131
* If it happened, the negative dentry isn't actually negative anymore. So,
3232
* drop it.
3333
*/
34-
static int exfat_d_revalidate(struct dentry *dentry, unsigned int flags)
34+
static int exfat_d_revalidate(struct inode *dir, const struct qstr *name,
35+
struct dentry *dentry, unsigned int flags)
3536
{
3637
int ret;
3738

0 commit comments

Comments
 (0)