Skip to content

Commit fe497f0

Browse files
neilbrownbrauner
authored andcommitted
VFS: change vfs_mkdir() to unlock on failure.
vfs_mkdir() already drops the reference to the dentry on failure but it leaves the parent locked. This complicates end_creating() which needs to unlock the parent even though the dentry is no longer available. If we change vfs_mkdir() to unlock on failure as well as releasing the dentry, we can remove the "parent" arg from end_creating() and simplify the rules for calling it. Note that cachefiles_get_directory() can choose to substitute an error instead of actually calling vfs_mkdir(), for fault injection. In that case it needs to call end_creating(), just as vfs_mkdir() now does on error. ovl_create_real() will now unlock on error. So the conditional end_creating() after the call is removed, and end_creating() is called internally on error. Reviewed-by: Amir Goldstein <amir73il@gmail.com> Reviewed-by: Jeff Layton <jlayton@kernel.org> Tested-by: syzbot@syzkaller.appspotmail.com Signed-off-by: NeilBrown <neil@brown.name> Link: https://patch.msgid.link/20251113002050.676694-15-neilb@ownmail.net Signed-off-by: Christian Brauner <brauner@kernel.org>
1 parent f046fbb commit fe497f0

16 files changed

Lines changed: 61 additions & 58 deletions

File tree

Documentation/filesystems/porting.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1309,3 +1309,16 @@ a different length, use
13091309
vfs_parse_fs_qstr(fc, key, &QSTR_LEN(value, len))
13101310

13111311
instead.
1312+
1313+
---
1314+
1315+
**mandatory**
1316+
1317+
vfs_mkdir() now returns a dentry - the one returned by ->mkdir(). If
1318+
that dentry is different from the dentry passed in, including if it is
1319+
an IS_ERR() dentry pointer, the original dentry is dput().
1320+
1321+
When vfs_mkdir() returns an error, and so both dputs() the original
1322+
dentry and doesn't provide a replacement, it also unlocks the parent.
1323+
Consequently the return value from vfs_mkdir() can be passed to
1324+
end_creating() and the parent will be unlocked precisely when necessary.

fs/btrfs/ioctl.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -935,7 +935,7 @@ static noinline int btrfs_mksubvol(struct dentry *parent,
935935
out_up_read:
936936
up_read(&fs_info->subvol_sem);
937937
out_dput:
938-
end_creating(dentry, parent);
938+
end_creating(dentry);
939939
return ret;
940940
}
941941

fs/cachefiles/namei.c

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,12 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
128128
if (ret < 0)
129129
goto mkdir_error;
130130
ret = cachefiles_inject_write_error();
131-
if (ret == 0)
131+
if (ret == 0) {
132132
subdir = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), subdir, 0700);
133-
else
133+
} else {
134+
end_creating(subdir);
134135
subdir = ERR_PTR(ret);
136+
}
135137
if (IS_ERR(subdir)) {
136138
trace_cachefiles_vfs_error(NULL, d_inode(dir), ret,
137139
cachefiles_trace_mkdir_error);
@@ -140,7 +142,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
140142
trace_cachefiles_mkdir(dir, subdir);
141143

142144
if (unlikely(d_unhashed(subdir) || d_is_negative(subdir))) {
143-
end_creating(subdir, dir);
145+
end_creating(subdir);
144146
goto retry;
145147
}
146148
ASSERT(d_backing_inode(subdir));
@@ -154,7 +156,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
154156
/* Tell rmdir() it's not allowed to delete the subdir */
155157
inode_lock(d_inode(subdir));
156158
dget(subdir);
157-
end_creating(subdir, dir);
159+
end_creating(subdir);
158160

159161
if (!__cachefiles_mark_inode_in_use(NULL, d_inode(subdir))) {
160162
pr_notice("cachefiles: Inode already in use: %pd (B=%lx)\n",
@@ -196,7 +198,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
196198
return ERR_PTR(-EBUSY);
197199

198200
mkdir_error:
199-
end_creating(subdir, dir);
201+
end_creating(subdir);
200202
pr_err("mkdir %s failed with error %d\n", dirname, ret);
201203
return ERR_PTR(ret);
202204

@@ -699,7 +701,7 @@ bool cachefiles_commit_tmpfile(struct cachefiles_cache *cache,
699701
if (ret < 0)
700702
goto out_end;
701703

702-
end_creating(dentry, fan);
704+
end_creating(dentry);
703705

704706
ret = cachefiles_inject_read_error();
705707
if (ret == 0)
@@ -733,7 +735,7 @@ bool cachefiles_commit_tmpfile(struct cachefiles_cache *cache,
733735
}
734736

735737
out_end:
736-
end_creating(dentry, fan);
738+
end_creating(dentry);
737739
out:
738740
_leave(" = %u", success);
739741
return success;

fs/ecryptfs/inode.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ ecryptfs_do_create(struct inode *directory_inode,
211211
fsstack_copy_attr_times(directory_inode, lower_dir);
212212
fsstack_copy_inode_size(directory_inode, lower_dir);
213213
out_lock:
214-
end_creating(lower_dentry, NULL);
214+
end_creating(lower_dentry);
215215
return inode;
216216
}
217217

@@ -456,7 +456,7 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
456456
ecryptfs_inode_to_lower(d_inode(old_dentry))->i_nlink);
457457
i_size_write(d_inode(new_dentry), file_size_save);
458458
out_lock:
459-
end_creating(lower_new_dentry, NULL);
459+
end_creating(lower_new_dentry);
460460
return rc;
461461
}
462462

@@ -500,7 +500,7 @@ static int ecryptfs_symlink(struct mnt_idmap *idmap,
500500
fsstack_copy_attr_times(dir, lower_dir);
501501
fsstack_copy_inode_size(dir, lower_dir);
502502
out_lock:
503-
end_creating(lower_dentry, NULL);
503+
end_creating(lower_dentry);
504504
if (d_really_is_negative(dentry))
505505
d_drop(dentry);
506506
return rc;
@@ -534,7 +534,7 @@ static struct dentry *ecryptfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
534534
fsstack_copy_inode_size(dir, lower_dir);
535535
set_nlink(dir, lower_dir->i_nlink);
536536
out:
537-
end_creating(lower_dentry, lower_dir_dentry);
537+
end_creating(lower_dentry);
538538
if (d_really_is_negative(dentry))
539539
d_drop(dentry);
540540
return ERR_PTR(rc);

fs/namei.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4832,7 +4832,7 @@ EXPORT_SYMBOL(start_creating_path);
48324832
*/
48334833
void end_creating_path(const struct path *path, struct dentry *dentry)
48344834
{
4835-
end_creating(dentry, path->dentry);
4835+
end_creating(dentry);
48364836
mnt_drop_write(path->mnt);
48374837
path_put(path);
48384838
}
@@ -5034,7 +5034,7 @@ struct dentry *vfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
50345034
return dentry;
50355035

50365036
err:
5037-
dput(dentry);
5037+
end_creating(dentry);
50385038
return ERR_PTR(error);
50395039
}
50405040
EXPORT_SYMBOL(vfs_mkdir);

fs/nfsd/nfs3proc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ nfsd3_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
364364
status = nfsd_create_setattr(rqstp, fhp, resfhp, &attrs);
365365

366366
out:
367-
end_creating(child, parent);
367+
end_creating(child);
368368
out_write:
369369
fh_drop_write(fhp);
370370
return status;

fs/nfsd/nfs4proc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -376,7 +376,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
376376
if (attrs.na_aclerr)
377377
open->op_bmval[0] &= ~FATTR4_WORD0_ACL;
378378
out:
379-
end_creating(child, parent);
379+
end_creating(child);
380380
nfsd_attrs_free(&attrs);
381381
out_write:
382382
fh_drop_write(fhp);

fs/nfsd/nfs4recover.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,7 @@ nfsd4_create_clid_dir(struct nfs4_client *clp)
215215
if (IS_ERR(dentry))
216216
status = PTR_ERR(dentry);
217217
out_end:
218-
end_creating(dentry, dir);
218+
end_creating(dentry);
219219
out:
220220
if (status == 0) {
221221
if (nn->in_grace)

fs/nfsd/nfsproc.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ nfsd_proc_create(struct svc_rqst *rqstp)
421421
}
422422

423423
out_unlock:
424-
end_creating(dchild, dirfhp->fh_dentry);
424+
end_creating(dchild);
425425
out_write:
426426
fh_drop_write(dirfhp);
427427
done:

fs/nfsd/vfs.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1589,7 +1589,7 @@ nfsd_create_locked(struct svc_rqst *rqstp, struct svc_fh *fhp,
15891589
out:
15901590
if (!err)
15911591
fh_fill_post_attrs(fhp);
1592-
end_creating(dchild, dentry);
1592+
end_creating(dchild);
15931593
return err;
15941594

15951595
out_nfserr:
@@ -1646,7 +1646,7 @@ nfsd_create(struct svc_rqst *rqstp, struct svc_fh *fhp,
16461646
return err;
16471647

16481648
out_unlock:
1649-
end_creating(dchild, dentry);
1649+
end_creating(dchild);
16501650
return err;
16511651
}
16521652

@@ -1747,7 +1747,7 @@ nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
17471747
nfsd_create_setattr(rqstp, fhp, resfhp, attrs);
17481748
fh_fill_post_attrs(fhp);
17491749
out_unlock:
1750-
end_creating(dnew, dentry);
1750+
end_creating(dnew);
17511751
if (!err)
17521752
err = nfserrno(commit_metadata(fhp));
17531753
if (!err)
@@ -1824,7 +1824,7 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
18241824
host_err = vfs_link(dold, &nop_mnt_idmap, dirp, dnew, NULL);
18251825
fh_fill_post_attrs(ffhp);
18261826
out_unlock:
1827-
end_creating(dnew, ddir);
1827+
end_creating(dnew);
18281828
if (!host_err) {
18291829
host_err = commit_metadata(ffhp);
18301830
if (!host_err)

0 commit comments

Comments
 (0)