Skip to content

Commit

Permalink
Merge branch 'work.open3' of git://git.kernel.org/pub/scm/linux/kerne…
Browse files Browse the repository at this point in the history
…l/git/viro/vfs

Pull vfs open-related updates from Al Viro:

 - "do we need fput() or put_filp()" rules are gone - it's always fput()
   now. We keep track of that state where it belongs - in ->f_mode.

 - int *opened mess killed - in finish_open(), in ->atomic_open()
   instances and in fs/namei.c code around do_last()/lookup_open()/atomic_open().

 - alloc_file() wrappers with saner calling conventions are introduced
   (alloc_file_clone() and alloc_file_pseudo()); callers converted, with
   much simplification.

 - while we are at it, saner calling conventions for path_init() and
   link_path_walk(), simplifying things inside fs/namei.c (both on
   open-related paths and elsewhere).

* 'work.open3' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (40 commits)
  few more cleanups of link_path_walk() callers
  allow link_path_walk() to take ERR_PTR()
  make path_init() unconditionally paired with terminate_walk()
  document alloc_file() changes
  make alloc_file() static
  do_shmat(): grab shp->shm_file earlier, switch to alloc_file_clone()
  new helper: alloc_file_clone()
  create_pipe_files(): switch the first allocation to alloc_file_pseudo()
  anon_inode_getfile(): switch to alloc_file_pseudo()
  hugetlb_file_setup(): switch to alloc_file_pseudo()
  ocxlflash_getfile(): switch to alloc_file_pseudo()
  cxl_getfile(): switch to alloc_file_pseudo()
  ... and switch shmem_file_setup() to alloc_file_pseudo()
  __shmem_file_setup(): reorder allocations
  new wrapper: alloc_file_pseudo()
  kill FILE_{CREATED,OPENED}
  switch atomic_open() and lookup_open() to returning 0 in all success cases
  document ->atomic_open() changes
  ->atomic_open(): return 0 in all success cases
  get rid of 'opened' in path_openat() and the helpers downstream
  ...
  • Loading branch information
torvalds committed Aug 14, 2018
2 parents b165284 + 5f336e7 commit a66b4cd
Show file tree
Hide file tree
Showing 45 changed files with 371 additions and 576 deletions.
2 changes: 1 addition & 1 deletion Documentation/filesystems/Locking
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ prototypes:
void (*update_time)(struct inode *, struct timespec *, int);
int (*atomic_open)(struct inode *, struct dentry *,
struct file *, unsigned open_flag,
umode_t create_mode, int *opened);
umode_t create_mode);
int (*tmpfile) (struct inode *, struct dentry *, umode_t);

locking rules:
Expand Down
20 changes: 20 additions & 0 deletions Documentation/filesystems/porting
Original file line number Diff line number Diff line change
Expand Up @@ -602,3 +602,23 @@ in your dentry operations instead.
dentry separately, and it now has request_mask and query_flags arguments
to specify the fields and sync type requested by statx. Filesystems not
supporting any statx-specific features may ignore the new arguments.
--
[mandatory]
->atomic_open() calling conventions have changed. Gone is int *opened,
along with FILE_OPENED/FILE_CREATED. In place of those we have
FMODE_OPENED/FMODE_CREATED, set in file->f_mode. Additionally, return
value for 'called finish_no_open(), open it yourself' case has become
0, not 1. Since finish_no_open() itself is returning 0 now, that part
does not need any changes in ->atomic_open() instances.
--
[mandatory]
alloc_file() has become static now; two wrappers are to be used instead.
alloc_file_pseudo(inode, vfsmount, name, flags, ops) is for the cases
when dentry needs to be created; that's the majority of old alloc_file()
users. Calling conventions: on success a reference to new struct file
is returned and callers reference to inode is subsumed by that. On
failure, ERR_PTR() is returned and no caller's references are affected,
so the caller needs to drop the inode reference it held.
alloc_file_clone(file, flags, ops) does not affect any caller's references.
On success you get a new struct file sharing the mount/dentry with the
original, on failure - ERR_PTR().
18 changes: 10 additions & 8 deletions Documentation/filesystems/vfs.txt
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ struct inode_operations {
ssize_t (*listxattr) (struct dentry *, char *, size_t);
void (*update_time)(struct inode *, struct timespec *, int);
int (*atomic_open)(struct inode *, struct dentry *, struct file *,
unsigned open_flag, umode_t create_mode, int *opened);
unsigned open_flag, umode_t create_mode);
int (*tmpfile) (struct inode *, struct dentry *, umode_t);
};

Expand Down Expand Up @@ -496,13 +496,15 @@ otherwise noted.

atomic_open: called on the last component of an open. Using this optional
method the filesystem can look up, possibly create and open the file in
one atomic operation. If it cannot perform this (e.g. the file type
turned out to be wrong) it may signal this by returning 1 instead of
usual 0 or -ve . This method is only called if the last component is
negative or needs lookup. Cached positive dentries are still handled by
f_op->open(). If the file was created, the FILE_CREATED flag should be
set in "opened". In case of O_EXCL the method must only succeed if the
file didn't exist and hence FILE_CREATED shall always be set on success.
one atomic operation. If it wants to leave actual opening to the
caller (e.g. if the file turned out to be a symlink, device, or just
something filesystem won't do atomic open for), it may signal this by
returning finish_no_open(file, dentry). This method is only called if
the last component is negative or needs lookup. Cached positive dentries
are still handled by f_op->open(). If the file was created,
FMODE_CREATED flag should be set in file->f_mode. In case of O_EXCL
the method must only succeed if the file didn't exist and hence FMODE_CREATED
shall always be set on success.

tmpfile: called in the end of O_TMPFILE open(). Optional, equivalent to
atomically creating, opening and unlinking a file in given directory.
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/drm_lease.c
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ int drm_mode_create_lease_ioctl(struct drm_device *dev,

/* Clone the lessor file to create a new file for us */
DRM_DEBUG_LEASE("Allocating lease file\n");
lessee_file = filp_clone_open(lessor_file);
lessee_file = file_clone_open(lessor_file);
if (IS_ERR(lessee_file)) {
ret = PTR_ERR(lessee_file);
goto out_lessee;
Expand Down
22 changes: 4 additions & 18 deletions drivers/misc/cxl/api.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,8 @@ static struct file *cxl_getfile(const char *name,
const struct file_operations *fops,
void *priv, int flags)
{
struct qstr this;
struct path path;
struct file *file;
struct inode *inode = NULL;
struct inode *inode;
int rc;

/* strongly inspired by anon_inode_getfile() */
Expand All @@ -91,23 +89,11 @@ static struct file *cxl_getfile(const char *name,
goto err_fs;
}

file = ERR_PTR(-ENOMEM);
this.name = name;
this.len = strlen(name);
this.hash = 0;
path.dentry = d_alloc_pseudo(cxl_vfs_mount->mnt_sb, &this);
if (!path.dentry)
file = alloc_file_pseudo(inode, cxl_vfs_mount, name,
flags & (O_ACCMODE | O_NONBLOCK), fops);
if (IS_ERR(file))
goto err_inode;

path.mnt = mntget(cxl_vfs_mount);
d_instantiate(path.dentry, inode);

file = alloc_file(&path, OPEN_FMODE(flags), fops);
if (IS_ERR(file)) {
path_put(&path);
goto err_fs;
}
file->f_flags = flags & (O_ACCMODE | O_NONBLOCK);
file->private_data = priv;

return file;
Expand Down
24 changes: 4 additions & 20 deletions drivers/scsi/cxlflash/ocxl_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,8 @@ static struct file *ocxlflash_getfile(struct device *dev, const char *name,
const struct file_operations *fops,
void *priv, int flags)
{
struct qstr this;
struct path path;
struct file *file;
struct inode *inode = NULL;
struct inode *inode;
int rc;

if (fops->owner && !try_module_get(fops->owner)) {
Expand All @@ -116,29 +114,15 @@ static struct file *ocxlflash_getfile(struct device *dev, const char *name,
goto err3;
}

this.name = name;
this.len = strlen(name);
this.hash = 0;
path.dentry = d_alloc_pseudo(ocxlflash_vfs_mount->mnt_sb, &this);
if (!path.dentry) {
dev_err(dev, "%s: d_alloc_pseudo failed\n", __func__);
rc = -ENOMEM;
goto err4;
}

path.mnt = mntget(ocxlflash_vfs_mount);
d_instantiate(path.dentry, inode);

file = alloc_file(&path, OPEN_FMODE(flags), fops);
file = alloc_file_pseudo(inode, ocxlflash_vfs_mount, name,
flags & (O_ACCMODE | O_NONBLOCK), fops);
if (IS_ERR(file)) {
rc = PTR_ERR(file);
dev_err(dev, "%s: alloc_file failed rc=%d\n",
__func__, rc);
path_put(&path);
goto err3;
goto err4;
}

file->f_flags = flags & (O_ACCMODE | O_NONBLOCK);
file->private_data = priv;
out:
return file;
Expand Down
7 changes: 3 additions & 4 deletions fs/9p/vfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -859,8 +859,7 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,

static int
v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
struct file *file, unsigned flags, umode_t mode,
int *opened)
struct file *file, unsigned flags, umode_t mode)
{
int err;
u32 perm;
Expand Down Expand Up @@ -917,15 +916,15 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
v9inode->writeback_fid = (void *) inode_fid;
}
mutex_unlock(&v9inode->v_mutex);
err = finish_open(file, dentry, generic_file_open, opened);
err = finish_open(file, dentry, generic_file_open);
if (err)
goto error;

file->private_data = fid;
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
v9fs_cache_inode_set_cookie(d_inode(dentry), file);

*opened |= FILE_CREATED;
file->f_mode |= FMODE_CREATED;
out:
dput(res);
return err;
Expand Down
7 changes: 3 additions & 4 deletions fs/9p/vfs_inode_dotl.c
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,7 @@ v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,

static int
v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
struct file *file, unsigned flags, umode_t omode,
int *opened)
struct file *file, unsigned flags, umode_t omode)
{
int err = 0;
kgid_t gid;
Expand Down Expand Up @@ -352,13 +351,13 @@ v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
}
mutex_unlock(&v9inode->v_mutex);
/* Since we are opening a file, assign the open fid to the file */
err = finish_open(file, dentry, generic_file_open, opened);
err = finish_open(file, dentry, generic_file_open);
if (err)
goto err_clunk_old_fid;
file->private_data = ofid;
if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
v9fs_cache_inode_set_cookie(inode, file);
*opened |= FILE_CREATED;
file->f_mode |= FMODE_CREATED;
out:
v9fs_put_acl(dacl, pacl);
dput(res);
Expand Down
24 changes: 4 additions & 20 deletions fs/aio.c
Original file line number Diff line number Diff line change
Expand Up @@ -202,9 +202,7 @@ static const struct address_space_operations aio_ctx_aops;

static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages)
{
struct qstr this = QSTR_INIT("[aio]", 5);
struct file *file;
struct path path;
struct inode *inode = alloc_anon_inode(aio_mnt->mnt_sb);
if (IS_ERR(inode))
return ERR_CAST(inode);
Expand All @@ -213,31 +211,17 @@ static struct file *aio_private_file(struct kioctx *ctx, loff_t nr_pages)
inode->i_mapping->private_data = ctx;
inode->i_size = PAGE_SIZE * nr_pages;

path.dentry = d_alloc_pseudo(aio_mnt->mnt_sb, &this);
if (!path.dentry) {
file = alloc_file_pseudo(inode, aio_mnt, "[aio]",
O_RDWR, &aio_ring_fops);
if (IS_ERR(file))
iput(inode);
return ERR_PTR(-ENOMEM);
}
path.mnt = mntget(aio_mnt);

d_instantiate(path.dentry, inode);
file = alloc_file(&path, FMODE_READ | FMODE_WRITE, &aio_ring_fops);
if (IS_ERR(file)) {
path_put(&path);
return file;
}

file->f_flags = O_RDWR;
return file;
}

static struct dentry *aio_mount(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data)
{
static const struct dentry_operations ops = {
.d_dname = simple_dname,
};
struct dentry *root = mount_pseudo(fs_type, "aio:", NULL, &ops,
struct dentry *root = mount_pseudo(fs_type, "aio:", NULL, NULL,
AIO_RING_MAGIC);

if (!IS_ERR(root))
Expand Down
30 changes: 6 additions & 24 deletions fs/anon_inodes.c
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ struct file *anon_inode_getfile(const char *name,
const struct file_operations *fops,
void *priv, int flags)
{
struct qstr this;
struct path path;
struct file *file;

if (IS_ERR(anon_inode_inode))
Expand All @@ -81,40 +79,24 @@ struct file *anon_inode_getfile(const char *name,
if (fops->owner && !try_module_get(fops->owner))
return ERR_PTR(-ENOENT);

/*
* Link the inode to a directory entry by creating a unique name
* using the inode sequence number.
*/
file = ERR_PTR(-ENOMEM);
this.name = name;
this.len = strlen(name);
this.hash = 0;
path.dentry = d_alloc_pseudo(anon_inode_mnt->mnt_sb, &this);
if (!path.dentry)
goto err_module;

path.mnt = mntget(anon_inode_mnt);
/*
* We know the anon_inode inode count is always greater than zero,
* so ihold() is safe.
*/
ihold(anon_inode_inode);

d_instantiate(path.dentry, anon_inode_inode);

file = alloc_file(&path, OPEN_FMODE(flags), fops);
file = alloc_file_pseudo(anon_inode_inode, anon_inode_mnt, name,
flags & (O_ACCMODE | O_NONBLOCK), fops);
if (IS_ERR(file))
goto err_dput;
goto err;

file->f_mapping = anon_inode_inode->i_mapping;

file->f_flags = flags & (O_ACCMODE | O_NONBLOCK);
file->private_data = priv;

return file;

err_dput:
path_put(&path);
err_module:
err:
iput(anon_inode_inode);
module_put(fops->owner);
return file;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/bad_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ static int bad_inode_update_time(struct inode *inode, struct timespec64 *time,

static int bad_inode_atomic_open(struct inode *inode, struct dentry *dentry,
struct file *file, unsigned int open_flag,
umode_t create_mode, int *opened)
umode_t create_mode)
{
return -EIO;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/binfmt_misc.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ static int load_misc_binary(struct linux_binprm *bprm)
goto error;

if (fmt->flags & MISC_FMT_OPEN_FILE) {
interp_file = filp_clone_open(fmt->interp_file);
interp_file = file_clone_open(fmt->interp_file);
if (!IS_ERR(interp_file))
deny_write_access(interp_file);
} else {
Expand Down
7 changes: 3 additions & 4 deletions fs/ceph/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,7 @@ int ceph_open(struct inode *inode, struct file *file)
* file or symlink, return 1 so the VFS can retry.
*/
int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
struct file *file, unsigned flags, umode_t mode,
int *opened)
struct file *file, unsigned flags, umode_t mode)
{
struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
struct ceph_mds_client *mdsc = fsc->mdsc;
Expand Down Expand Up @@ -507,9 +506,9 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
dout("atomic_open finish_open on dn %p\n", dn);
if (req->r_op == CEPH_MDS_OP_CREATE && req->r_reply_info.has_create_ino) {
ceph_init_inode_acls(d_inode(dentry), &acls);
*opened |= FILE_CREATED;
file->f_mode |= FMODE_CREATED;
}
err = finish_open(file, dentry, ceph_open, opened);
err = finish_open(file, dentry, ceph_open);
}
out_req:
if (!req->r_err && req->r_target_inode)
Expand Down
3 changes: 1 addition & 2 deletions fs/ceph/super.h
Original file line number Diff line number Diff line change
Expand Up @@ -1025,8 +1025,7 @@ extern const struct file_operations ceph_file_fops;
extern int ceph_renew_caps(struct inode *inode);
extern int ceph_open(struct inode *inode, struct file *file);
extern int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
struct file *file, unsigned flags, umode_t mode,
int *opened);
struct file *file, unsigned flags, umode_t mode);
extern int ceph_release(struct inode *inode, struct file *filp);
extern void ceph_fill_inline_data(struct inode *inode, struct page *locked_page,
char *data, size_t len);
Expand Down
3 changes: 1 addition & 2 deletions fs/cifs/cifsfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,7 @@ extern struct inode *cifs_root_iget(struct super_block *);
extern int cifs_create(struct inode *, struct dentry *, umode_t,
bool excl);
extern int cifs_atomic_open(struct inode *, struct dentry *,
struct file *, unsigned, umode_t,
int *);
struct file *, unsigned, umode_t);
extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
unsigned int);
extern int cifs_unlink(struct inode *dir, struct dentry *dentry);
Expand Down
7 changes: 3 additions & 4 deletions fs/cifs/dir.c
Original file line number Diff line number Diff line change
Expand Up @@ -465,8 +465,7 @@ cifs_do_create(struct inode *inode, struct dentry *direntry, unsigned int xid,

int
cifs_atomic_open(struct inode *inode, struct dentry *direntry,
struct file *file, unsigned oflags, umode_t mode,
int *opened)
struct file *file, unsigned oflags, umode_t mode)
{
int rc;
unsigned int xid;
Expand Down Expand Up @@ -539,9 +538,9 @@ cifs_atomic_open(struct inode *inode, struct dentry *direntry,
}

if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
*opened |= FILE_CREATED;
file->f_mode |= FMODE_CREATED;

rc = finish_open(file, direntry, generic_file_open, opened);
rc = finish_open(file, direntry, generic_file_open);
if (rc) {
if (server->ops->close)
server->ops->close(xid, tcon, &fid);
Expand Down
Loading

0 comments on commit a66b4cd

Please sign in to comment.