Skip to content

Commit 8113b39

Browse files
committed
Merge tag 'vfs-7.0-rc1.atomic_open' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs atomic_open updates from Christian Brauner: "Allow knfsd to use atomic_open() While knfsd offers combined exclusive create and open results to clients, on some filesystems those results are not atomic. The separate vfs_create() + vfs_open() sequence in dentry_create() can produce races and unexpected errors. For example, open O_CREAT with mode 0 will succeed in creating the file but return -EACCES from vfs_open(). Additionally, network filesystems benefit from reducing remote round-trip operations by using a single atomic_open() call. Teach dentry_create() -- whose sole caller is knfsd -- to use atomic_open() for filesystems that support it" * tag 'vfs-7.0-rc1.atomic_open' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: fs/namei: fix kernel-doc markup for dentry_create VFS/knfsd: Teach dentry_create() to use atomic_open() VFS: Prepare atomic_open() for dentry_create() VFS: move dentry_create() from fs/open.c to fs/namei.c
2 parents c84bb79 + 6ea258d commit 8113b39

4 files changed

Lines changed: 82 additions & 50 deletions

File tree

fs/namei.c

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4290,19 +4290,16 @@ static int may_o_create(struct mnt_idmap *idmap,
42904290
*
42914291
* Returns an error code otherwise.
42924292
*/
4293-
static struct dentry *atomic_open(struct nameidata *nd, struct dentry *dentry,
4293+
static struct dentry *atomic_open(const struct path *path, struct dentry *dentry,
42944294
struct file *file,
42954295
int open_flag, umode_t mode)
42964296
{
42974297
struct dentry *const DENTRY_NOT_SET = (void *) -1UL;
4298-
struct inode *dir = nd->path.dentry->d_inode;
4298+
struct inode *dir = path->dentry->d_inode;
42994299
int error;
43004300

4301-
if (nd->flags & LOOKUP_DIRECTORY)
4302-
open_flag |= O_DIRECTORY;
4303-
43044301
file->__f_path.dentry = DENTRY_NOT_SET;
4305-
file->__f_path.mnt = nd->path.mnt;
4302+
file->__f_path.mnt = path->mnt;
43064303
error = dir->i_op->atomic_open(dir, dentry, file,
43074304
open_to_namei_flags(open_flag), mode);
43084305
d_lookup_done(dentry);
@@ -4414,7 +4411,9 @@ static struct dentry *lookup_open(struct nameidata *nd, struct file *file,
44144411
if (create_error)
44154412
open_flag &= ~O_CREAT;
44164413
if (dir_inode->i_op->atomic_open) {
4417-
dentry = atomic_open(nd, dentry, file, open_flag, mode);
4414+
if (nd->flags & LOOKUP_DIRECTORY)
4415+
open_flag |= O_DIRECTORY;
4416+
dentry = atomic_open(&nd->path, dentry, file, open_flag, mode);
44184417
if (unlikely(create_error) && dentry == ERR_PTR(-ENOENT))
44194418
dentry = ERR_PTR(create_error);
44204419
return dentry;
@@ -4948,6 +4947,73 @@ inline struct dentry *start_creating_user_path(
49484947
}
49494948
EXPORT_SYMBOL(start_creating_user_path);
49504949

4950+
/**
4951+
* dentry_create - Create and open a file
4952+
* @path: path to create
4953+
* @flags: O\_ flags
4954+
* @mode: mode bits for new file
4955+
* @cred: credentials to use
4956+
*
4957+
* Caller must hold the parent directory's lock, and have prepared
4958+
* a negative dentry, placed in @path->dentry, for the new file.
4959+
*
4960+
* Caller sets @path->mnt to the vfsmount of the filesystem where
4961+
* the new file is to be created. The parent directory and the
4962+
* negative dentry must reside on the same filesystem instance.
4963+
*
4964+
* On success, returns a ``struct file *``. Otherwise an ERR_PTR
4965+
* is returned.
4966+
*/
4967+
struct file *dentry_create(struct path *path, int flags, umode_t mode,
4968+
const struct cred *cred)
4969+
{
4970+
struct file *file __free(fput) = NULL;
4971+
struct dentry *dentry = path->dentry;
4972+
struct dentry *dir = dentry->d_parent;
4973+
struct inode *dir_inode = d_inode(dir);
4974+
struct mnt_idmap *idmap;
4975+
int error, create_error;
4976+
4977+
file = alloc_empty_file(flags, cred);
4978+
if (IS_ERR(file))
4979+
return file;
4980+
4981+
idmap = mnt_idmap(path->mnt);
4982+
4983+
if (dir_inode->i_op->atomic_open) {
4984+
path->dentry = dir;
4985+
mode = vfs_prepare_mode(idmap, dir_inode, mode, S_IALLUGO, S_IFREG);
4986+
4987+
create_error = may_o_create(idmap, path, dentry, mode);
4988+
if (create_error)
4989+
flags &= ~O_CREAT;
4990+
4991+
dentry = atomic_open(path, dentry, file, flags, mode);
4992+
error = PTR_ERR_OR_ZERO(dentry);
4993+
4994+
if (unlikely(create_error) && error == -ENOENT)
4995+
error = create_error;
4996+
4997+
if (!error) {
4998+
if (file->f_mode & FMODE_CREATED)
4999+
fsnotify_create(dir->d_inode, dentry);
5000+
if (file->f_mode & FMODE_OPENED)
5001+
fsnotify_open(file);
5002+
}
5003+
5004+
path->dentry = dentry;
5005+
5006+
} else {
5007+
error = vfs_create(mnt_idmap(path->mnt), path->dentry, mode, NULL);
5008+
if (!error)
5009+
error = vfs_open(path, file);
5010+
}
5011+
if (unlikely(error))
5012+
return ERR_PTR(error);
5013+
5014+
return no_free_ptr(file);
5015+
}
5016+
EXPORT_SYMBOL(dentry_create);
49515017

49525018
/**
49535019
* vfs_mknod - create device node or file

fs/nfsd/nfs4proc.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -194,14 +194,17 @@ static inline bool nfsd4_create_is_exclusive(int createmode)
194194
}
195195

196196
static __be32
197-
nfsd4_vfs_create(struct svc_fh *fhp, struct dentry *child,
197+
nfsd4_vfs_create(struct svc_fh *fhp, struct dentry **child,
198198
struct nfsd4_open *open)
199199
{
200200
struct file *filp;
201201
struct path path;
202202
int oflags;
203203

204204
oflags = O_CREAT | O_LARGEFILE;
205+
if (nfsd4_create_is_exclusive(open->op_createmode))
206+
oflags |= O_EXCL;
207+
205208
switch (open->op_share_access & NFS4_SHARE_ACCESS_BOTH) {
206209
case NFS4_SHARE_ACCESS_WRITE:
207210
oflags |= O_WRONLY;
@@ -214,9 +217,11 @@ nfsd4_vfs_create(struct svc_fh *fhp, struct dentry *child,
214217
}
215218

216219
path.mnt = fhp->fh_export->ex_path.mnt;
217-
path.dentry = child;
220+
path.dentry = *child;
218221
filp = dentry_create(&path, oflags, open->op_iattr.ia_mode,
219222
current_cred());
223+
*child = path.dentry;
224+
220225
if (IS_ERR(filp))
221226
return nfserrno(PTR_ERR(filp));
222227

@@ -350,7 +355,7 @@ nfsd4_create_file(struct svc_rqst *rqstp, struct svc_fh *fhp,
350355
status = fh_fill_pre_attrs(fhp);
351356
if (status != nfs_ok)
352357
goto out;
353-
status = nfsd4_vfs_create(fhp, child, open);
358+
status = nfsd4_vfs_create(fhp, &child, open);
354359
if (status != nfs_ok)
355360
goto out;
356361
open->op_created = true;

fs/open.c

Lines changed: 0 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,45 +1141,6 @@ struct file *dentry_open_nonotify(const struct path *path, int flags,
11411141
return f;
11421142
}
11431143

1144-
/**
1145-
* dentry_create - Create and open a file
1146-
* @path: path to create
1147-
* @flags: O_ flags
1148-
* @mode: mode bits for new file
1149-
* @cred: credentials to use
1150-
*
1151-
* Caller must hold the parent directory's lock, and have prepared
1152-
* a negative dentry, placed in @path->dentry, for the new file.
1153-
*
1154-
* Caller sets @path->mnt to the vfsmount of the filesystem where
1155-
* the new file is to be created. The parent directory and the
1156-
* negative dentry must reside on the same filesystem instance.
1157-
*
1158-
* On success, returns a "struct file *". Otherwise a ERR_PTR
1159-
* is returned.
1160-
*/
1161-
struct file *dentry_create(const struct path *path, int flags, umode_t mode,
1162-
const struct cred *cred)
1163-
{
1164-
struct file *f;
1165-
int error;
1166-
1167-
f = alloc_empty_file(flags, cred);
1168-
if (IS_ERR(f))
1169-
return f;
1170-
1171-
error = vfs_create(mnt_idmap(path->mnt), path->dentry, mode, NULL);
1172-
if (!error)
1173-
error = vfs_open(path, f);
1174-
1175-
if (unlikely(error)) {
1176-
fput(f);
1177-
return ERR_PTR(error);
1178-
}
1179-
return f;
1180-
}
1181-
EXPORT_SYMBOL(dentry_create);
1182-
11831144
/**
11841145
* kernel_file_open - open a file for kernel internal use
11851146
* @path: path of the file to open

include/linux/fs.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2467,7 +2467,7 @@ struct file *dentry_open(const struct path *path, int flags,
24672467
const struct cred *creds);
24682468
struct file *dentry_open_nonotify(const struct path *path, int flags,
24692469
const struct cred *cred);
2470-
struct file *dentry_create(const struct path *path, int flags, umode_t mode,
2470+
struct file *dentry_create(struct path *path, int flags, umode_t mode,
24712471
const struct cred *cred);
24722472
const struct path *backing_file_user_path(const struct file *f);
24732473

0 commit comments

Comments
 (0)