mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-30 03:27:44 -04:00
Merge branch 'work.open3' of git://git.kernel.org/pub/scm/linux/kernel/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
...
This commit is contained in:
commit
a66b4cd1e7
45 changed files with 371 additions and 576 deletions
|
|
@ -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;
|
||||
|
|
@ -917,7 +916,7 @@ 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;
|
||||
|
||||
|
|
@ -925,7 +924,7 @@ v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
|
|||
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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
24
fs/aio.c
24
fs/aio.c
|
|
@ -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);
|
||||
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -429,8 +429,7 @@ out:
|
|||
* 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;
|
||||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -465,8 +465,7 @@ out_err:
|
|||
|
||||
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;
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ static void file_free_rcu(struct rcu_head *head)
|
|||
|
||||
static inline void file_free(struct file *f)
|
||||
{
|
||||
security_file_free(f);
|
||||
percpu_counter_dec(&nr_files);
|
||||
call_rcu(&f->f_u.fu_rcuhead, file_free_rcu);
|
||||
}
|
||||
|
|
@ -100,9 +101,8 @@ int proc_nr_files(struct ctl_table *table, int write,
|
|||
* done, you will imbalance int the mount's writer count
|
||||
* and a warning at __fput() time.
|
||||
*/
|
||||
struct file *get_empty_filp(void)
|
||||
struct file *alloc_empty_file(int flags, const struct cred *cred)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
static long old_max;
|
||||
struct file *f;
|
||||
int error;
|
||||
|
|
@ -123,11 +123,10 @@ struct file *get_empty_filp(void)
|
|||
if (unlikely(!f))
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
percpu_counter_inc(&nr_files);
|
||||
f->f_cred = get_cred(cred);
|
||||
error = security_file_alloc(f);
|
||||
if (unlikely(error)) {
|
||||
file_free(f);
|
||||
file_free_rcu(&f->f_u.fu_rcuhead);
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
|
|
@ -136,7 +135,10 @@ struct file *get_empty_filp(void)
|
|||
spin_lock_init(&f->f_lock);
|
||||
mutex_init(&f->f_pos_lock);
|
||||
eventpoll_init_file(f);
|
||||
f->f_flags = flags;
|
||||
f->f_mode = OPEN_FMODE(flags);
|
||||
/* f->f_version: 0 */
|
||||
percpu_counter_inc(&nr_files);
|
||||
return f;
|
||||
|
||||
over:
|
||||
|
|
@ -152,15 +154,15 @@ over:
|
|||
* alloc_file - allocate and initialize a 'struct file'
|
||||
*
|
||||
* @path: the (dentry, vfsmount) pair for the new file
|
||||
* @mode: the mode with which the new file will be opened
|
||||
* @flags: O_... flags with which the new file will be opened
|
||||
* @fop: the 'struct file_operations' for the new file
|
||||
*/
|
||||
struct file *alloc_file(const struct path *path, fmode_t mode,
|
||||
static struct file *alloc_file(const struct path *path, int flags,
|
||||
const struct file_operations *fop)
|
||||
{
|
||||
struct file *file;
|
||||
|
||||
file = get_empty_filp();
|
||||
file = alloc_empty_file(flags, current_cred());
|
||||
if (IS_ERR(file))
|
||||
return file;
|
||||
|
||||
|
|
@ -168,19 +170,56 @@ struct file *alloc_file(const struct path *path, fmode_t mode,
|
|||
file->f_inode = path->dentry->d_inode;
|
||||
file->f_mapping = path->dentry->d_inode->i_mapping;
|
||||
file->f_wb_err = filemap_sample_wb_err(file->f_mapping);
|
||||
if ((mode & FMODE_READ) &&
|
||||
if ((file->f_mode & FMODE_READ) &&
|
||||
likely(fop->read || fop->read_iter))
|
||||
mode |= FMODE_CAN_READ;
|
||||
if ((mode & FMODE_WRITE) &&
|
||||
file->f_mode |= FMODE_CAN_READ;
|
||||
if ((file->f_mode & FMODE_WRITE) &&
|
||||
likely(fop->write || fop->write_iter))
|
||||
mode |= FMODE_CAN_WRITE;
|
||||
file->f_mode = mode;
|
||||
file->f_mode |= FMODE_CAN_WRITE;
|
||||
file->f_mode |= FMODE_OPENED;
|
||||
file->f_op = fop;
|
||||
if ((mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
|
||||
if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
|
||||
i_readcount_inc(path->dentry->d_inode);
|
||||
return file;
|
||||
}
|
||||
EXPORT_SYMBOL(alloc_file);
|
||||
|
||||
struct file *alloc_file_pseudo(struct inode *inode, struct vfsmount *mnt,
|
||||
const char *name, int flags,
|
||||
const struct file_operations *fops)
|
||||
{
|
||||
static const struct dentry_operations anon_ops = {
|
||||
.d_dname = simple_dname
|
||||
};
|
||||
struct qstr this = QSTR_INIT(name, strlen(name));
|
||||
struct path path;
|
||||
struct file *file;
|
||||
|
||||
path.dentry = d_alloc_pseudo(mnt->mnt_sb, &this);
|
||||
if (!path.dentry)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (!mnt->mnt_sb->s_d_op)
|
||||
d_set_d_op(path.dentry, &anon_ops);
|
||||
path.mnt = mntget(mnt);
|
||||
d_instantiate(path.dentry, inode);
|
||||
file = alloc_file(&path, flags, fops);
|
||||
if (IS_ERR(file)) {
|
||||
ihold(inode);
|
||||
path_put(&path);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
EXPORT_SYMBOL(alloc_file_pseudo);
|
||||
|
||||
struct file *alloc_file_clone(struct file *base, int flags,
|
||||
const struct file_operations *fops)
|
||||
{
|
||||
struct file *f = alloc_file(&base->f_path, flags, fops);
|
||||
if (!IS_ERR(f)) {
|
||||
path_get(&f->f_path);
|
||||
f->f_mapping = base->f_mapping;
|
||||
}
|
||||
return f;
|
||||
}
|
||||
|
||||
/* the real guts of fput() - releasing the last reference to file
|
||||
*/
|
||||
|
|
@ -190,6 +229,9 @@ static void __fput(struct file *file)
|
|||
struct vfsmount *mnt = file->f_path.mnt;
|
||||
struct inode *inode = file->f_inode;
|
||||
|
||||
if (unlikely(!(file->f_mode & FMODE_OPENED)))
|
||||
goto out;
|
||||
|
||||
might_sleep();
|
||||
|
||||
fsnotify_close(file);
|
||||
|
|
@ -207,7 +249,6 @@ static void __fput(struct file *file)
|
|||
}
|
||||
if (file->f_op->release)
|
||||
file->f_op->release(inode, file);
|
||||
security_file_free(file);
|
||||
if (unlikely(S_ISCHR(inode->i_mode) && inode->i_cdev != NULL &&
|
||||
!(file->f_mode & FMODE_PATH))) {
|
||||
cdev_put(inode->i_cdev);
|
||||
|
|
@ -220,12 +261,10 @@ static void __fput(struct file *file)
|
|||
put_write_access(inode);
|
||||
__mnt_drop_write(mnt);
|
||||
}
|
||||
file->f_path.dentry = NULL;
|
||||
file->f_path.mnt = NULL;
|
||||
file->f_inode = NULL;
|
||||
file_free(file);
|
||||
dput(dentry);
|
||||
mntput(mnt);
|
||||
out:
|
||||
file_free(file);
|
||||
}
|
||||
|
||||
static LLIST_HEAD(delayed_fput_list);
|
||||
|
|
@ -300,14 +339,6 @@ void __fput_sync(struct file *file)
|
|||
|
||||
EXPORT_SYMBOL(fput);
|
||||
|
||||
void put_filp(struct file *file)
|
||||
{
|
||||
if (atomic_long_dec_and_test(&file->f_count)) {
|
||||
security_file_free(file);
|
||||
file_free(file);
|
||||
}
|
||||
}
|
||||
|
||||
void __init files_init(void)
|
||||
{
|
||||
filp_cachep = kmem_cache_create("filp", sizeof(struct file), 0,
|
||||
|
|
|
|||
|
|
@ -399,7 +399,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
|
|||
*/
|
||||
static int fuse_create_open(struct inode *dir, struct dentry *entry,
|
||||
struct file *file, unsigned flags,
|
||||
umode_t mode, int *opened)
|
||||
umode_t mode)
|
||||
{
|
||||
int err;
|
||||
struct inode *inode;
|
||||
|
|
@ -469,7 +469,7 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
|
|||
d_instantiate(entry, inode);
|
||||
fuse_change_entry_timeout(entry, &outentry);
|
||||
fuse_invalidate_attr(dir);
|
||||
err = finish_open(file, entry, generic_file_open, opened);
|
||||
err = finish_open(file, entry, generic_file_open);
|
||||
if (err) {
|
||||
fuse_sync_release(ff, flags);
|
||||
} else {
|
||||
|
|
@ -489,7 +489,7 @@ out_err:
|
|||
static int fuse_mknod(struct inode *, struct dentry *, umode_t, dev_t);
|
||||
static int fuse_atomic_open(struct inode *dir, struct dentry *entry,
|
||||
struct file *file, unsigned flags,
|
||||
umode_t mode, int *opened)
|
||||
umode_t mode)
|
||||
{
|
||||
int err;
|
||||
struct fuse_conn *fc = get_fuse_conn(dir);
|
||||
|
|
@ -508,12 +508,12 @@ static int fuse_atomic_open(struct inode *dir, struct dentry *entry,
|
|||
goto no_open;
|
||||
|
||||
/* Only creates */
|
||||
*opened |= FILE_CREATED;
|
||||
file->f_mode |= FMODE_CREATED;
|
||||
|
||||
if (fc->no_create)
|
||||
goto mknod;
|
||||
|
||||
err = fuse_create_open(dir, entry, file, flags, mode, opened);
|
||||
err = fuse_create_open(dir, entry, file, flags, mode);
|
||||
if (err == -ENOSYS) {
|
||||
fc->no_create = 1;
|
||||
goto mknod;
|
||||
|
|
|
|||
|
|
@ -580,7 +580,7 @@ static int gfs2_initxattrs(struct inode *inode, const struct xattr *xattr_array,
|
|||
static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
||||
struct file *file,
|
||||
umode_t mode, dev_t dev, const char *symname,
|
||||
unsigned int size, int excl, int *opened)
|
||||
unsigned int size, int excl)
|
||||
{
|
||||
const struct qstr *name = &dentry->d_name;
|
||||
struct posix_acl *default_acl, *acl;
|
||||
|
|
@ -626,7 +626,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
|||
error = 0;
|
||||
if (file) {
|
||||
if (S_ISREG(inode->i_mode))
|
||||
error = finish_open(file, dentry, gfs2_open_common, opened);
|
||||
error = finish_open(file, dentry, gfs2_open_common);
|
||||
else
|
||||
error = finish_no_open(file, NULL);
|
||||
}
|
||||
|
|
@ -767,8 +767,8 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
|
|||
mark_inode_dirty(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
if (file) {
|
||||
*opened |= FILE_CREATED;
|
||||
error = finish_open(file, dentry, gfs2_open_common, opened);
|
||||
file->f_mode |= FMODE_CREATED;
|
||||
error = finish_open(file, dentry, gfs2_open_common);
|
||||
}
|
||||
gfs2_glock_dq_uninit(ghs);
|
||||
gfs2_glock_dq_uninit(ghs + 1);
|
||||
|
|
@ -822,7 +822,7 @@ fail:
|
|||
static int gfs2_create(struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode, bool excl)
|
||||
{
|
||||
return gfs2_create_inode(dir, dentry, NULL, S_IFREG | mode, 0, NULL, 0, excl, NULL);
|
||||
return gfs2_create_inode(dir, dentry, NULL, S_IFREG | mode, 0, NULL, 0, excl);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -830,14 +830,13 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry,
|
|||
* @dir: The directory inode
|
||||
* @dentry: The dentry of the new inode
|
||||
* @file: File to be opened
|
||||
* @opened: atomic_open flags
|
||||
*
|
||||
*
|
||||
* Returns: errno
|
||||
*/
|
||||
|
||||
static struct dentry *__gfs2_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct file *file, int *opened)
|
||||
struct file *file)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct dentry *d;
|
||||
|
|
@ -866,7 +865,7 @@ static struct dentry *__gfs2_lookup(struct inode *dir, struct dentry *dentry,
|
|||
return d;
|
||||
}
|
||||
if (file && S_ISREG(inode->i_mode))
|
||||
error = finish_open(file, dentry, gfs2_open_common, opened);
|
||||
error = finish_open(file, dentry, gfs2_open_common);
|
||||
|
||||
gfs2_glock_dq_uninit(&gh);
|
||||
if (error) {
|
||||
|
|
@ -879,7 +878,7 @@ static struct dentry *__gfs2_lookup(struct inode *dir, struct dentry *dentry,
|
|||
static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
|
||||
unsigned flags)
|
||||
{
|
||||
return __gfs2_lookup(dir, dentry, NULL, NULL);
|
||||
return __gfs2_lookup(dir, dentry, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1189,7 +1188,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
|
|||
if (size >= gfs2_max_stuffed_size(GFS2_I(dir)))
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
return gfs2_create_inode(dir, dentry, NULL, S_IFLNK | S_IRWXUGO, 0, symname, size, 0, NULL);
|
||||
return gfs2_create_inode(dir, dentry, NULL, S_IFLNK | S_IRWXUGO, 0, symname, size, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1204,7 +1203,7 @@ static int gfs2_symlink(struct inode *dir, struct dentry *dentry,
|
|||
static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
unsigned dsize = gfs2_max_stuffed_size(GFS2_I(dir));
|
||||
return gfs2_create_inode(dir, dentry, NULL, S_IFDIR | mode, 0, NULL, dsize, 0, NULL);
|
||||
return gfs2_create_inode(dir, dentry, NULL, S_IFDIR | mode, 0, NULL, dsize, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1219,7 +1218,7 @@ static int gfs2_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
|||
static int gfs2_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
dev_t dev)
|
||||
{
|
||||
return gfs2_create_inode(dir, dentry, NULL, mode, dev, NULL, 0, 0, NULL);
|
||||
return gfs2_create_inode(dir, dentry, NULL, mode, dev, NULL, 0, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1229,14 +1228,13 @@ static int gfs2_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|||
* @file: The proposed new struct file
|
||||
* @flags: open flags
|
||||
* @mode: File mode
|
||||
* @opened: Flag to say whether the file has been opened or not
|
||||
*
|
||||
* Returns: error code or 0 for success
|
||||
*/
|
||||
|
||||
static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry,
|
||||
struct file *file, unsigned flags,
|
||||
umode_t mode, int *opened)
|
||||
umode_t mode)
|
||||
{
|
||||
struct dentry *d;
|
||||
bool excl = !!(flags & O_EXCL);
|
||||
|
|
@ -1244,13 +1242,13 @@ static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry,
|
|||
if (!d_in_lookup(dentry))
|
||||
goto skip_lookup;
|
||||
|
||||
d = __gfs2_lookup(dir, dentry, file, opened);
|
||||
d = __gfs2_lookup(dir, dentry, file);
|
||||
if (IS_ERR(d))
|
||||
return PTR_ERR(d);
|
||||
if (d != NULL)
|
||||
dentry = d;
|
||||
if (d_really_is_positive(dentry)) {
|
||||
if (!(*opened & FILE_OPENED))
|
||||
if (!(file->f_mode & FMODE_OPENED))
|
||||
return finish_no_open(file, d);
|
||||
dput(d);
|
||||
return 0;
|
||||
|
|
@ -1262,7 +1260,7 @@ skip_lookup:
|
|||
if (!(flags & O_CREAT))
|
||||
return -ENOENT;
|
||||
|
||||
return gfs2_create_inode(dir, dentry, file, S_IFREG | mode, 0, NULL, 0, excl, opened);
|
||||
return gfs2_create_inode(dir, dentry, file, S_IFREG | mode, 0, NULL, 0, excl);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -1310,10 +1310,6 @@ static int get_hstate_idx(int page_size_log)
|
|||
return h - hstates;
|
||||
}
|
||||
|
||||
static const struct dentry_operations anon_ops = {
|
||||
.d_dname = simple_dname
|
||||
};
|
||||
|
||||
/*
|
||||
* Note that size should be aligned to proper hugepage size in caller side,
|
||||
* otherwise hugetlb_reserve_pages reserves one less hugepages than intended.
|
||||
|
|
@ -1322,19 +1318,18 @@ struct file *hugetlb_file_setup(const char *name, size_t size,
|
|||
vm_flags_t acctflag, struct user_struct **user,
|
||||
int creat_flags, int page_size_log)
|
||||
{
|
||||
struct file *file = ERR_PTR(-ENOMEM);
|
||||
struct inode *inode;
|
||||
struct path path;
|
||||
struct super_block *sb;
|
||||
struct qstr quick_string;
|
||||
struct vfsmount *mnt;
|
||||
int hstate_idx;
|
||||
struct file *file;
|
||||
|
||||
hstate_idx = get_hstate_idx(page_size_log);
|
||||
if (hstate_idx < 0)
|
||||
return ERR_PTR(-ENODEV);
|
||||
|
||||
*user = NULL;
|
||||
if (!hugetlbfs_vfsmount[hstate_idx])
|
||||
mnt = hugetlbfs_vfsmount[hstate_idx];
|
||||
if (!mnt)
|
||||
return ERR_PTR(-ENOENT);
|
||||
|
||||
if (creat_flags == HUGETLB_SHMFS_INODE && !can_do_hugetlb_shm()) {
|
||||
|
|
@ -1350,45 +1345,28 @@ struct file *hugetlb_file_setup(const char *name, size_t size,
|
|||
}
|
||||
}
|
||||
|
||||
sb = hugetlbfs_vfsmount[hstate_idx]->mnt_sb;
|
||||
quick_string.name = name;
|
||||
quick_string.len = strlen(quick_string.name);
|
||||
quick_string.hash = 0;
|
||||
path.dentry = d_alloc_pseudo(sb, &quick_string);
|
||||
if (!path.dentry)
|
||||
goto out_shm_unlock;
|
||||
|
||||
d_set_d_op(path.dentry, &anon_ops);
|
||||
path.mnt = mntget(hugetlbfs_vfsmount[hstate_idx]);
|
||||
file = ERR_PTR(-ENOSPC);
|
||||
inode = hugetlbfs_get_inode(sb, NULL, S_IFREG | S_IRWXUGO, 0);
|
||||
inode = hugetlbfs_get_inode(mnt->mnt_sb, NULL, S_IFREG | S_IRWXUGO, 0);
|
||||
if (!inode)
|
||||
goto out_dentry;
|
||||
goto out;
|
||||
if (creat_flags == HUGETLB_SHMFS_INODE)
|
||||
inode->i_flags |= S_PRIVATE;
|
||||
|
||||
file = ERR_PTR(-ENOMEM);
|
||||
if (hugetlb_reserve_pages(inode, 0,
|
||||
size >> huge_page_shift(hstate_inode(inode)), NULL,
|
||||
acctflag))
|
||||
goto out_inode;
|
||||
|
||||
d_instantiate(path.dentry, inode);
|
||||
inode->i_size = size;
|
||||
clear_nlink(inode);
|
||||
|
||||
file = alloc_file(&path, FMODE_WRITE | FMODE_READ,
|
||||
&hugetlbfs_file_operations);
|
||||
if (IS_ERR(file))
|
||||
goto out_dentry; /* inode is already attached */
|
||||
if (hugetlb_reserve_pages(inode, 0,
|
||||
size >> huge_page_shift(hstate_inode(inode)), NULL,
|
||||
acctflag))
|
||||
file = ERR_PTR(-ENOMEM);
|
||||
else
|
||||
file = alloc_file_pseudo(inode, mnt, name, O_RDWR,
|
||||
&hugetlbfs_file_operations);
|
||||
if (!IS_ERR(file))
|
||||
return file;
|
||||
|
||||
return file;
|
||||
|
||||
out_inode:
|
||||
iput(inode);
|
||||
out_dentry:
|
||||
path_put(&path);
|
||||
out_shm_unlock:
|
||||
out:
|
||||
if (*user) {
|
||||
user_shm_unlock(size, *user);
|
||||
*user = NULL;
|
||||
|
|
|
|||
|
|
@ -93,7 +93,7 @@ extern void chroot_fs_refs(const struct path *, const struct path *);
|
|||
/*
|
||||
* file_table.c
|
||||
*/
|
||||
extern struct file *get_empty_filp(void);
|
||||
extern struct file *alloc_empty_file(int, const struct cred *);
|
||||
|
||||
/*
|
||||
* super.c
|
||||
|
|
@ -125,8 +125,7 @@ int do_fchmodat(int dfd, const char __user *filename, umode_t mode);
|
|||
int do_fchownat(int dfd, const char __user *filename, uid_t user, gid_t group,
|
||||
int flag);
|
||||
|
||||
extern int open_check_o_direct(struct file *f);
|
||||
extern int vfs_open(const struct path *, struct file *, const struct cred *);
|
||||
extern int vfs_open(const struct path *, struct file *);
|
||||
|
||||
/*
|
||||
* inode.c
|
||||
|
|
|
|||
225
fs/namei.c
225
fs/namei.c
|
|
@ -2028,6 +2028,8 @@ static int link_path_walk(const char *name, struct nameidata *nd)
|
|||
{
|
||||
int err;
|
||||
|
||||
if (IS_ERR(name))
|
||||
return PTR_ERR(name);
|
||||
while (*name=='/')
|
||||
name++;
|
||||
if (!*name)
|
||||
|
|
@ -2125,12 +2127,15 @@ OK:
|
|||
}
|
||||
}
|
||||
|
||||
/* must be paired with terminate_walk() */
|
||||
static const char *path_init(struct nameidata *nd, unsigned flags)
|
||||
{
|
||||
const char *s = nd->name->name;
|
||||
|
||||
if (!*s)
|
||||
flags &= ~LOOKUP_RCU;
|
||||
if (flags & LOOKUP_RCU)
|
||||
rcu_read_lock();
|
||||
|
||||
nd->last_type = LAST_ROOT; /* if there are only slashes... */
|
||||
nd->flags = flags | LOOKUP_JUMPED | LOOKUP_PARENT;
|
||||
|
|
@ -2143,7 +2148,6 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
|
|||
nd->path = nd->root;
|
||||
nd->inode = inode;
|
||||
if (flags & LOOKUP_RCU) {
|
||||
rcu_read_lock();
|
||||
nd->seq = __read_seqcount_begin(&nd->path.dentry->d_seq);
|
||||
nd->root_seq = nd->seq;
|
||||
nd->m_seq = read_seqbegin(&mount_lock);
|
||||
|
|
@ -2159,21 +2163,15 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
|
|||
|
||||
nd->m_seq = read_seqbegin(&mount_lock);
|
||||
if (*s == '/') {
|
||||
if (flags & LOOKUP_RCU)
|
||||
rcu_read_lock();
|
||||
set_root(nd);
|
||||
if (likely(!nd_jump_root(nd)))
|
||||
return s;
|
||||
nd->root.mnt = NULL;
|
||||
rcu_read_unlock();
|
||||
return ERR_PTR(-ECHILD);
|
||||
} else if (nd->dfd == AT_FDCWD) {
|
||||
if (flags & LOOKUP_RCU) {
|
||||
struct fs_struct *fs = current->fs;
|
||||
unsigned seq;
|
||||
|
||||
rcu_read_lock();
|
||||
|
||||
do {
|
||||
seq = read_seqcount_begin(&fs->seq);
|
||||
nd->path = fs->pwd;
|
||||
|
|
@ -2195,16 +2193,13 @@ static const char *path_init(struct nameidata *nd, unsigned flags)
|
|||
|
||||
dentry = f.file->f_path.dentry;
|
||||
|
||||
if (*s) {
|
||||
if (!d_can_lookup(dentry)) {
|
||||
fdput(f);
|
||||
return ERR_PTR(-ENOTDIR);
|
||||
}
|
||||
if (*s && unlikely(!d_can_lookup(dentry))) {
|
||||
fdput(f);
|
||||
return ERR_PTR(-ENOTDIR);
|
||||
}
|
||||
|
||||
nd->path = f.file->f_path;
|
||||
if (flags & LOOKUP_RCU) {
|
||||
rcu_read_lock();
|
||||
nd->inode = nd->path.dentry->d_inode;
|
||||
nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
|
||||
} else {
|
||||
|
|
@ -2272,24 +2267,15 @@ static int path_lookupat(struct nameidata *nd, unsigned flags, struct path *path
|
|||
const char *s = path_init(nd, flags);
|
||||
int err;
|
||||
|
||||
if (IS_ERR(s))
|
||||
return PTR_ERR(s);
|
||||
|
||||
if (unlikely(flags & LOOKUP_DOWN)) {
|
||||
if (unlikely(flags & LOOKUP_DOWN) && !IS_ERR(s)) {
|
||||
err = handle_lookup_down(nd);
|
||||
if (unlikely(err < 0)) {
|
||||
terminate_walk(nd);
|
||||
return err;
|
||||
}
|
||||
if (unlikely(err < 0))
|
||||
s = ERR_PTR(err);
|
||||
}
|
||||
|
||||
while (!(err = link_path_walk(s, nd))
|
||||
&& ((err = lookup_last(nd)) > 0)) {
|
||||
s = trailing_symlink(nd);
|
||||
if (IS_ERR(s)) {
|
||||
err = PTR_ERR(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!err)
|
||||
err = complete_walk(nd);
|
||||
|
|
@ -2336,10 +2322,7 @@ static int path_parentat(struct nameidata *nd, unsigned flags,
|
|||
struct path *parent)
|
||||
{
|
||||
const char *s = path_init(nd, flags);
|
||||
int err;
|
||||
if (IS_ERR(s))
|
||||
return PTR_ERR(s);
|
||||
err = link_path_walk(s, nd);
|
||||
int err = link_path_walk(s, nd);
|
||||
if (!err)
|
||||
err = complete_walk(nd);
|
||||
if (!err) {
|
||||
|
|
@ -2666,15 +2649,10 @@ path_mountpoint(struct nameidata *nd, unsigned flags, struct path *path)
|
|||
{
|
||||
const char *s = path_init(nd, flags);
|
||||
int err;
|
||||
if (IS_ERR(s))
|
||||
return PTR_ERR(s);
|
||||
|
||||
while (!(err = link_path_walk(s, nd)) &&
|
||||
(err = mountpoint_last(nd)) > 0) {
|
||||
s = trailing_symlink(nd);
|
||||
if (IS_ERR(s)) {
|
||||
err = PTR_ERR(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!err) {
|
||||
*path = nd->path;
|
||||
|
|
@ -3027,17 +3005,16 @@ static int may_o_create(const struct path *dir, struct dentry *dentry, umode_t m
|
|||
* Returns 0 if successful. The file will have been created and attached to
|
||||
* @file by the filesystem calling finish_open().
|
||||
*
|
||||
* Returns 1 if the file was looked up only or didn't need creating. The
|
||||
* caller will need to perform the open themselves. @path will have been
|
||||
* updated to point to the new dentry. This may be negative.
|
||||
* If the file was looked up only or didn't need creating, FMODE_OPENED won't
|
||||
* be set. The caller will need to perform the open themselves. @path will
|
||||
* have been updated to point to the new dentry. This may be negative.
|
||||
*
|
||||
* Returns an error code otherwise.
|
||||
*/
|
||||
static int atomic_open(struct nameidata *nd, struct dentry *dentry,
|
||||
struct path *path, struct file *file,
|
||||
const struct open_flags *op,
|
||||
int open_flag, umode_t mode,
|
||||
int *opened)
|
||||
int open_flag, umode_t mode)
|
||||
{
|
||||
struct dentry *const DENTRY_NOT_SET = (void *) -1UL;
|
||||
struct inode *dir = nd->path.dentry->d_inode;
|
||||
|
|
@ -3052,39 +3029,38 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
|
|||
file->f_path.dentry = DENTRY_NOT_SET;
|
||||
file->f_path.mnt = nd->path.mnt;
|
||||
error = dir->i_op->atomic_open(dir, dentry, file,
|
||||
open_to_namei_flags(open_flag),
|
||||
mode, opened);
|
||||
open_to_namei_flags(open_flag), mode);
|
||||
d_lookup_done(dentry);
|
||||
if (!error) {
|
||||
/*
|
||||
* We didn't have the inode before the open, so check open
|
||||
* permission here.
|
||||
*/
|
||||
int acc_mode = op->acc_mode;
|
||||
if (*opened & FILE_CREATED) {
|
||||
WARN_ON(!(open_flag & O_CREAT));
|
||||
fsnotify_create(dir, dentry);
|
||||
acc_mode = 0;
|
||||
}
|
||||
error = may_open(&file->f_path, acc_mode, open_flag);
|
||||
if (WARN_ON(error > 0))
|
||||
error = -EINVAL;
|
||||
} else if (error > 0) {
|
||||
if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) {
|
||||
if (file->f_mode & FMODE_OPENED) {
|
||||
/*
|
||||
* We didn't have the inode before the open, so check open
|
||||
* permission here.
|
||||
*/
|
||||
int acc_mode = op->acc_mode;
|
||||
if (file->f_mode & FMODE_CREATED) {
|
||||
WARN_ON(!(open_flag & O_CREAT));
|
||||
fsnotify_create(dir, dentry);
|
||||
acc_mode = 0;
|
||||
}
|
||||
error = may_open(&file->f_path, acc_mode, open_flag);
|
||||
if (WARN_ON(error > 0))
|
||||
error = -EINVAL;
|
||||
} else if (WARN_ON(file->f_path.dentry == DENTRY_NOT_SET)) {
|
||||
error = -EIO;
|
||||
} else {
|
||||
if (file->f_path.dentry) {
|
||||
dput(dentry);
|
||||
dentry = file->f_path.dentry;
|
||||
}
|
||||
if (*opened & FILE_CREATED)
|
||||
if (file->f_mode & FMODE_CREATED)
|
||||
fsnotify_create(dir, dentry);
|
||||
if (unlikely(d_is_negative(dentry))) {
|
||||
error = -ENOENT;
|
||||
} else {
|
||||
path->dentry = dentry;
|
||||
path->mnt = nd->path.mnt;
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3095,25 +3071,22 @@ static int atomic_open(struct nameidata *nd, struct dentry *dentry,
|
|||
/*
|
||||
* Look up and maybe create and open the last component.
|
||||
*
|
||||
* Must be called with i_mutex held on parent.
|
||||
* Must be called with parent locked (exclusive in O_CREAT case).
|
||||
*
|
||||
* Returns 0 if the file was successfully atomically created (if necessary) and
|
||||
* opened. In this case the file will be returned attached to @file.
|
||||
* Returns 0 on success, that is, if
|
||||
* the file was successfully atomically created (if necessary) and opened, or
|
||||
* the file was not completely opened at this time, though lookups and
|
||||
* creations were performed.
|
||||
* These case are distinguished by presence of FMODE_OPENED on file->f_mode.
|
||||
* In the latter case dentry returned in @path might be negative if O_CREAT
|
||||
* hadn't been specified.
|
||||
*
|
||||
* Returns 1 if the file was not completely opened at this time, though lookups
|
||||
* and creations will have been performed and the dentry returned in @path will
|
||||
* be positive upon return if O_CREAT was specified. If O_CREAT wasn't
|
||||
* specified then a negative dentry may be returned.
|
||||
*
|
||||
* An error code is returned otherwise.
|
||||
*
|
||||
* FILE_CREATE will be set in @*opened if the dentry was created and will be
|
||||
* cleared otherwise prior to returning.
|
||||
* An error code is returned on failure.
|
||||
*/
|
||||
static int lookup_open(struct nameidata *nd, struct path *path,
|
||||
struct file *file,
|
||||
const struct open_flags *op,
|
||||
bool got_write, int *opened)
|
||||
bool got_write)
|
||||
{
|
||||
struct dentry *dir = nd->path.dentry;
|
||||
struct inode *dir_inode = dir->d_inode;
|
||||
|
|
@ -3126,7 +3099,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
|
|||
if (unlikely(IS_DEADDIR(dir_inode)))
|
||||
return -ENOENT;
|
||||
|
||||
*opened &= ~FILE_CREATED;
|
||||
file->f_mode &= ~FMODE_CREATED;
|
||||
dentry = d_lookup(dir, &nd->last);
|
||||
for (;;) {
|
||||
if (!dentry) {
|
||||
|
|
@ -3188,7 +3161,7 @@ static int lookup_open(struct nameidata *nd, struct path *path,
|
|||
|
||||
if (dir_inode->i_op->atomic_open) {
|
||||
error = atomic_open(nd, dentry, path, file, op, open_flag,
|
||||
mode, opened);
|
||||
mode);
|
||||
if (unlikely(error == -ENOENT) && create_error)
|
||||
error = create_error;
|
||||
return error;
|
||||
|
|
@ -3211,7 +3184,7 @@ no_open:
|
|||
|
||||
/* Negative dentry, just create the file */
|
||||
if (!dentry->d_inode && (open_flag & O_CREAT)) {
|
||||
*opened |= FILE_CREATED;
|
||||
file->f_mode |= FMODE_CREATED;
|
||||
audit_inode_child(dir_inode, dentry, AUDIT_TYPE_CHILD_CREATE);
|
||||
if (!dir_inode->i_op->create) {
|
||||
error = -EACCES;
|
||||
|
|
@ -3230,7 +3203,7 @@ no_open:
|
|||
out_no_open:
|
||||
path->dentry = dentry;
|
||||
path->mnt = nd->path.mnt;
|
||||
return 1;
|
||||
return 0;
|
||||
|
||||
out_dput:
|
||||
dput(dentry);
|
||||
|
|
@ -3241,8 +3214,7 @@ out_dput:
|
|||
* Handle the last step of open()
|
||||
*/
|
||||
static int do_last(struct nameidata *nd,
|
||||
struct file *file, const struct open_flags *op,
|
||||
int *opened)
|
||||
struct file *file, const struct open_flags *op)
|
||||
{
|
||||
struct dentry *dir = nd->path.dentry;
|
||||
int open_flag = op->open_flag;
|
||||
|
|
@ -3308,17 +3280,17 @@ static int do_last(struct nameidata *nd,
|
|||
inode_lock(dir->d_inode);
|
||||
else
|
||||
inode_lock_shared(dir->d_inode);
|
||||
error = lookup_open(nd, &path, file, op, got_write, opened);
|
||||
error = lookup_open(nd, &path, file, op, got_write);
|
||||
if (open_flag & O_CREAT)
|
||||
inode_unlock(dir->d_inode);
|
||||
else
|
||||
inode_unlock_shared(dir->d_inode);
|
||||
|
||||
if (error <= 0) {
|
||||
if (error)
|
||||
goto out;
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
if ((*opened & FILE_CREATED) ||
|
||||
if (file->f_mode & FMODE_OPENED) {
|
||||
if ((file->f_mode & FMODE_CREATED) ||
|
||||
!S_ISREG(file_inode(file)->i_mode))
|
||||
will_truncate = false;
|
||||
|
||||
|
|
@ -3326,7 +3298,7 @@ static int do_last(struct nameidata *nd,
|
|||
goto opened;
|
||||
}
|
||||
|
||||
if (*opened & FILE_CREATED) {
|
||||
if (file->f_mode & FMODE_CREATED) {
|
||||
/* Don't check for write permission, don't truncate */
|
||||
open_flag &= ~O_TRUNC;
|
||||
will_truncate = false;
|
||||
|
|
@ -3395,20 +3367,15 @@ finish_open_created:
|
|||
error = may_open(&nd->path, acc_mode, open_flag);
|
||||
if (error)
|
||||
goto out;
|
||||
BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */
|
||||
error = vfs_open(&nd->path, file, current_cred());
|
||||
BUG_ON(file->f_mode & FMODE_OPENED); /* once it's opened, it's opened */
|
||||
error = vfs_open(&nd->path, file);
|
||||
if (error)
|
||||
goto out;
|
||||
*opened |= FILE_OPENED;
|
||||
opened:
|
||||
error = open_check_o_direct(file);
|
||||
if (!error)
|
||||
error = ima_file_check(file, op->acc_mode, *opened);
|
||||
error = ima_file_check(file, op->acc_mode);
|
||||
if (!error && will_truncate)
|
||||
error = handle_truncate(file);
|
||||
out:
|
||||
if (unlikely(error) && (*opened & FILE_OPENED))
|
||||
fput(file);
|
||||
if (unlikely(error > 0)) {
|
||||
WARN_ON(1);
|
||||
error = -EINVAL;
|
||||
|
|
@ -3458,7 +3425,7 @@ EXPORT_SYMBOL(vfs_tmpfile);
|
|||
|
||||
static int do_tmpfile(struct nameidata *nd, unsigned flags,
|
||||
const struct open_flags *op,
|
||||
struct file *file, int *opened)
|
||||
struct file *file)
|
||||
{
|
||||
struct dentry *child;
|
||||
struct path path;
|
||||
|
|
@ -3480,12 +3447,7 @@ static int do_tmpfile(struct nameidata *nd, unsigned flags,
|
|||
if (error)
|
||||
goto out2;
|
||||
file->f_path.mnt = path.mnt;
|
||||
error = finish_open(file, child, NULL, opened);
|
||||
if (error)
|
||||
goto out2;
|
||||
error = open_check_o_direct(file);
|
||||
if (error)
|
||||
fput(file);
|
||||
error = finish_open(file, child, NULL);
|
||||
out2:
|
||||
mnt_drop_write(path.mnt);
|
||||
out:
|
||||
|
|
@ -3499,7 +3461,7 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file)
|
|||
int error = path_lookupat(nd, flags, &path);
|
||||
if (!error) {
|
||||
audit_inode(nd->name, path.dentry, 0);
|
||||
error = vfs_open(&path, file, current_cred());
|
||||
error = vfs_open(&path, file);
|
||||
path_put(&path);
|
||||
}
|
||||
return error;
|
||||
|
|
@ -3508,59 +3470,40 @@ static int do_o_path(struct nameidata *nd, unsigned flags, struct file *file)
|
|||
static struct file *path_openat(struct nameidata *nd,
|
||||
const struct open_flags *op, unsigned flags)
|
||||
{
|
||||
const char *s;
|
||||
struct file *file;
|
||||
int opened = 0;
|
||||
int error;
|
||||
|
||||
file = get_empty_filp();
|
||||
file = alloc_empty_file(op->open_flag, current_cred());
|
||||
if (IS_ERR(file))
|
||||
return file;
|
||||
|
||||
file->f_flags = op->open_flag;
|
||||
|
||||
if (unlikely(file->f_flags & __O_TMPFILE)) {
|
||||
error = do_tmpfile(nd, flags, op, file, &opened);
|
||||
goto out2;
|
||||
}
|
||||
|
||||
if (unlikely(file->f_flags & O_PATH)) {
|
||||
error = do_tmpfile(nd, flags, op, file);
|
||||
} else if (unlikely(file->f_flags & O_PATH)) {
|
||||
error = do_o_path(nd, flags, file);
|
||||
if (!error)
|
||||
opened |= FILE_OPENED;
|
||||
goto out2;
|
||||
}
|
||||
|
||||
s = path_init(nd, flags);
|
||||
if (IS_ERR(s)) {
|
||||
put_filp(file);
|
||||
return ERR_CAST(s);
|
||||
}
|
||||
while (!(error = link_path_walk(s, nd)) &&
|
||||
(error = do_last(nd, file, op, &opened)) > 0) {
|
||||
nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
|
||||
s = trailing_symlink(nd);
|
||||
if (IS_ERR(s)) {
|
||||
error = PTR_ERR(s);
|
||||
break;
|
||||
} else {
|
||||
const char *s = path_init(nd, flags);
|
||||
while (!(error = link_path_walk(s, nd)) &&
|
||||
(error = do_last(nd, file, op)) > 0) {
|
||||
nd->flags &= ~(LOOKUP_OPEN|LOOKUP_CREATE|LOOKUP_EXCL);
|
||||
s = trailing_symlink(nd);
|
||||
}
|
||||
terminate_walk(nd);
|
||||
}
|
||||
terminate_walk(nd);
|
||||
out2:
|
||||
if (!(opened & FILE_OPENED)) {
|
||||
BUG_ON(!error);
|
||||
put_filp(file);
|
||||
if (likely(!error)) {
|
||||
if (likely(file->f_mode & FMODE_OPENED))
|
||||
return file;
|
||||
WARN_ON(1);
|
||||
error = -EINVAL;
|
||||
}
|
||||
if (unlikely(error)) {
|
||||
if (error == -EOPENSTALE) {
|
||||
if (flags & LOOKUP_RCU)
|
||||
error = -ECHILD;
|
||||
else
|
||||
error = -ESTALE;
|
||||
}
|
||||
file = ERR_PTR(error);
|
||||
fput(file);
|
||||
if (error == -EOPENSTALE) {
|
||||
if (flags & LOOKUP_RCU)
|
||||
error = -ECHILD;
|
||||
else
|
||||
error = -ESTALE;
|
||||
}
|
||||
return file;
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
struct file *do_filp_open(int dfd, struct filename *pathname,
|
||||
|
|
|
|||
14
fs/nfs/dir.c
14
fs/nfs/dir.c
|
|
@ -1434,12 +1434,11 @@ static int do_open(struct inode *inode, struct file *filp)
|
|||
|
||||
static int nfs_finish_open(struct nfs_open_context *ctx,
|
||||
struct dentry *dentry,
|
||||
struct file *file, unsigned open_flags,
|
||||
int *opened)
|
||||
struct file *file, unsigned open_flags)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = finish_open(file, dentry, do_open, opened);
|
||||
err = finish_open(file, dentry, do_open);
|
||||
if (err)
|
||||
goto out;
|
||||
if (S_ISREG(file->f_path.dentry->d_inode->i_mode))
|
||||
|
|
@ -1452,7 +1451,7 @@ out:
|
|||
|
||||
int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
|
||||
struct file *file, unsigned open_flags,
|
||||
umode_t mode, int *opened)
|
||||
umode_t mode)
|
||||
{
|
||||
DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
|
||||
struct nfs_open_context *ctx;
|
||||
|
|
@ -1461,6 +1460,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
|
|||
struct inode *inode;
|
||||
unsigned int lookup_flags = 0;
|
||||
bool switched = false;
|
||||
int created = 0;
|
||||
int err;
|
||||
|
||||
/* Expect a negative dentry */
|
||||
|
|
@ -1521,7 +1521,9 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
|
|||
goto out;
|
||||
|
||||
trace_nfs_atomic_open_enter(dir, ctx, open_flags);
|
||||
inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr, opened);
|
||||
inode = NFS_PROTO(dir)->open_context(dir, ctx, open_flags, &attr, &created);
|
||||
if (created)
|
||||
file->f_mode |= FMODE_CREATED;
|
||||
if (IS_ERR(inode)) {
|
||||
err = PTR_ERR(inode);
|
||||
trace_nfs_atomic_open_exit(dir, ctx, open_flags, err);
|
||||
|
|
@ -1546,7 +1548,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
|
|||
goto out;
|
||||
}
|
||||
|
||||
err = nfs_finish_open(ctx, ctx->dentry, file, open_flags, opened);
|
||||
err = nfs_finish_open(ctx, ctx->dentry, file, open_flags);
|
||||
trace_nfs_atomic_open_exit(dir, ctx, open_flags, err);
|
||||
put_nfs_open_context(ctx);
|
||||
out:
|
||||
|
|
|
|||
|
|
@ -258,7 +258,7 @@ extern const struct dentry_operations nfs4_dentry_operations;
|
|||
|
||||
/* dir.c */
|
||||
int nfs_atomic_open(struct inode *, struct dentry *, struct file *,
|
||||
unsigned, umode_t, int *);
|
||||
unsigned, umode_t);
|
||||
|
||||
/* super.c */
|
||||
extern struct file_system_type nfs4_fs_type;
|
||||
|
|
|
|||
|
|
@ -2951,7 +2951,7 @@ static int _nfs4_do_open(struct inode *dir,
|
|||
}
|
||||
}
|
||||
if (opened && opendata->file_created)
|
||||
*opened |= FILE_CREATED;
|
||||
*opened = 1;
|
||||
|
||||
if (pnfs_use_threshold(ctx_th, opendata->f_attr.mdsthreshold, server)) {
|
||||
*ctx_th = opendata->f_attr.mdsthreshold;
|
||||
|
|
|
|||
|
|
@ -763,7 +763,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, umode_t type,
|
|||
goto out_nfserr;
|
||||
}
|
||||
|
||||
host_err = ima_file_check(file, may_flags, 0);
|
||||
host_err = ima_file_check(file, may_flags);
|
||||
if (host_err) {
|
||||
fput(file);
|
||||
goto out_nfserr;
|
||||
|
|
|
|||
88
fs/open.c
88
fs/open.c
|
|
@ -724,27 +724,13 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
|
|||
return ksys_fchown(fd, user, group);
|
||||
}
|
||||
|
||||
int open_check_o_direct(struct file *f)
|
||||
{
|
||||
/* NB: we're sure to have correct a_ops only after f_op->open */
|
||||
if (f->f_flags & O_DIRECT) {
|
||||
if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO)
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_dentry_open(struct file *f,
|
||||
struct inode *inode,
|
||||
int (*open)(struct inode *, struct file *),
|
||||
const struct cred *cred)
|
||||
int (*open)(struct inode *, struct file *))
|
||||
{
|
||||
static const struct file_operations empty_fops = {};
|
||||
int error;
|
||||
|
||||
f->f_mode = OPEN_FMODE(f->f_flags) | FMODE_LSEEK |
|
||||
FMODE_PREAD | FMODE_PWRITE;
|
||||
|
||||
path_get(&f->f_path);
|
||||
f->f_inode = inode;
|
||||
f->f_mapping = inode->i_mapping;
|
||||
|
|
@ -753,7 +739,7 @@ static int do_dentry_open(struct file *f,
|
|||
f->f_wb_err = filemap_sample_wb_err(f->f_mapping);
|
||||
|
||||
if (unlikely(f->f_flags & O_PATH)) {
|
||||
f->f_mode = FMODE_PATH;
|
||||
f->f_mode = FMODE_PATH | FMODE_OPENED;
|
||||
f->f_op = &empty_fops;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -780,7 +766,7 @@ static int do_dentry_open(struct file *f,
|
|||
goto cleanup_all;
|
||||
}
|
||||
|
||||
error = security_file_open(f, cred);
|
||||
error = security_file_open(f);
|
||||
if (error)
|
||||
goto cleanup_all;
|
||||
|
||||
|
|
@ -788,6 +774,8 @@ static int do_dentry_open(struct file *f,
|
|||
if (error)
|
||||
goto cleanup_all;
|
||||
|
||||
/* normally all 3 are set; ->open() can clear them if needed */
|
||||
f->f_mode |= FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
|
||||
if (!open)
|
||||
open = f->f_op->open;
|
||||
if (open) {
|
||||
|
|
@ -795,6 +783,7 @@ static int do_dentry_open(struct file *f,
|
|||
if (error)
|
||||
goto cleanup_all;
|
||||
}
|
||||
f->f_mode |= FMODE_OPENED;
|
||||
if ((f->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
|
||||
i_readcount_inc(inode);
|
||||
if ((f->f_mode & FMODE_READ) &&
|
||||
|
|
@ -809,9 +798,16 @@ static int do_dentry_open(struct file *f,
|
|||
|
||||
file_ra_state_init(&f->f_ra, f->f_mapping->host->i_mapping);
|
||||
|
||||
/* NB: we're sure to have correct a_ops only after f_op->open */
|
||||
if (f->f_flags & O_DIRECT) {
|
||||
if (!f->f_mapping->a_ops || !f->f_mapping->a_ops->direct_IO)
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
|
||||
cleanup_all:
|
||||
if (WARN_ON_ONCE(error > 0))
|
||||
error = -EINVAL;
|
||||
fops_put(f->f_op);
|
||||
if (f->f_mode & FMODE_WRITER) {
|
||||
put_write_access(inode);
|
||||
|
|
@ -847,19 +843,12 @@ cleanup_file:
|
|||
* Returns zero on success or -errno if the open failed.
|
||||
*/
|
||||
int finish_open(struct file *file, struct dentry *dentry,
|
||||
int (*open)(struct inode *, struct file *),
|
||||
int *opened)
|
||||
int (*open)(struct inode *, struct file *))
|
||||
{
|
||||
int error;
|
||||
BUG_ON(*opened & FILE_OPENED); /* once it's opened, it's opened */
|
||||
BUG_ON(file->f_mode & FMODE_OPENED); /* once it's opened, it's opened */
|
||||
|
||||
file->f_path.dentry = dentry;
|
||||
error = do_dentry_open(file, d_backing_inode(dentry), open,
|
||||
current_cred());
|
||||
if (!error)
|
||||
*opened |= FILE_OPENED;
|
||||
|
||||
return error;
|
||||
return do_dentry_open(file, d_backing_inode(dentry), open);
|
||||
}
|
||||
EXPORT_SYMBOL(finish_open);
|
||||
|
||||
|
|
@ -874,13 +863,13 @@ EXPORT_SYMBOL(finish_open);
|
|||
* NB: unlike finish_open() this function does consume the dentry reference and
|
||||
* the caller need not dput() it.
|
||||
*
|
||||
* Returns "1" which must be the return value of ->atomic_open() after having
|
||||
* Returns "0" which must be the return value of ->atomic_open() after having
|
||||
* called this function.
|
||||
*/
|
||||
int finish_no_open(struct file *file, struct dentry *dentry)
|
||||
{
|
||||
file->f_path.dentry = dentry;
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(finish_no_open);
|
||||
|
||||
|
|
@ -896,8 +885,7 @@ EXPORT_SYMBOL(file_path);
|
|||
* @file: newly allocated file with f_flag initialized
|
||||
* @cred: credentials to use
|
||||
*/
|
||||
int vfs_open(const struct path *path, struct file *file,
|
||||
const struct cred *cred)
|
||||
int vfs_open(const struct path *path, struct file *file)
|
||||
{
|
||||
struct dentry *dentry = d_real(path->dentry, NULL, file->f_flags, 0);
|
||||
|
||||
|
|
@ -905,7 +893,7 @@ int vfs_open(const struct path *path, struct file *file,
|
|||
return PTR_ERR(dentry);
|
||||
|
||||
file->f_path = *path;
|
||||
return do_dentry_open(file, d_backing_inode(dentry), NULL, cred);
|
||||
return do_dentry_open(file, d_backing_inode(dentry), NULL);
|
||||
}
|
||||
|
||||
struct file *dentry_open(const struct path *path, int flags,
|
||||
|
|
@ -919,19 +907,11 @@ struct file *dentry_open(const struct path *path, int flags,
|
|||
/* We must always pass in a valid mount pointer. */
|
||||
BUG_ON(!path->mnt);
|
||||
|
||||
f = get_empty_filp();
|
||||
f = alloc_empty_file(flags, cred);
|
||||
if (!IS_ERR(f)) {
|
||||
f->f_flags = flags;
|
||||
error = vfs_open(path, f, cred);
|
||||
if (!error) {
|
||||
/* from now on we need fput() to dispose of f */
|
||||
error = open_check_o_direct(f);
|
||||
if (error) {
|
||||
fput(f);
|
||||
f = ERR_PTR(error);
|
||||
}
|
||||
} else {
|
||||
put_filp(f);
|
||||
error = vfs_open(path, f);
|
||||
if (error) {
|
||||
fput(f);
|
||||
f = ERR_PTR(error);
|
||||
}
|
||||
}
|
||||
|
|
@ -1063,26 +1043,6 @@ struct file *file_open_root(struct dentry *dentry, struct vfsmount *mnt,
|
|||
}
|
||||
EXPORT_SYMBOL(file_open_root);
|
||||
|
||||
struct file *filp_clone_open(struct file *oldfile)
|
||||
{
|
||||
struct file *file;
|
||||
int retval;
|
||||
|
||||
file = get_empty_filp();
|
||||
if (IS_ERR(file))
|
||||
return file;
|
||||
|
||||
file->f_flags = oldfile->f_flags;
|
||||
retval = vfs_open(&oldfile->f_path, file, oldfile->f_cred);
|
||||
if (retval) {
|
||||
put_filp(file);
|
||||
return ERR_PTR(retval);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
EXPORT_SYMBOL(filp_clone_open);
|
||||
|
||||
long do_sys_open(int dfd, const char __user *filename, int flags, umode_t mode)
|
||||
{
|
||||
struct open_flags op;
|
||||
|
|
|
|||
43
fs/pipe.c
43
fs/pipe.c
|
|
@ -741,54 +741,33 @@ fail_inode:
|
|||
|
||||
int create_pipe_files(struct file **res, int flags)
|
||||
{
|
||||
int err;
|
||||
struct inode *inode = get_pipe_inode();
|
||||
struct file *f;
|
||||
struct path path;
|
||||
|
||||
if (!inode)
|
||||
return -ENFILE;
|
||||
|
||||
err = -ENOMEM;
|
||||
path.dentry = d_alloc_pseudo(pipe_mnt->mnt_sb, &empty_name);
|
||||
if (!path.dentry)
|
||||
goto err_inode;
|
||||
path.mnt = mntget(pipe_mnt);
|
||||
|
||||
d_instantiate(path.dentry, inode);
|
||||
|
||||
f = alloc_file(&path, FMODE_WRITE, &pipefifo_fops);
|
||||
f = alloc_file_pseudo(inode, pipe_mnt, "",
|
||||
O_WRONLY | (flags & (O_NONBLOCK | O_DIRECT)),
|
||||
&pipefifo_fops);
|
||||
if (IS_ERR(f)) {
|
||||
err = PTR_ERR(f);
|
||||
goto err_dentry;
|
||||
free_pipe_info(inode->i_pipe);
|
||||
iput(inode);
|
||||
return PTR_ERR(f);
|
||||
}
|
||||
|
||||
f->f_flags = O_WRONLY | (flags & (O_NONBLOCK | O_DIRECT));
|
||||
f->private_data = inode->i_pipe;
|
||||
|
||||
res[0] = alloc_file(&path, FMODE_READ, &pipefifo_fops);
|
||||
res[0] = alloc_file_clone(f, O_RDONLY | (flags & O_NONBLOCK),
|
||||
&pipefifo_fops);
|
||||
if (IS_ERR(res[0])) {
|
||||
err = PTR_ERR(res[0]);
|
||||
goto err_file;
|
||||
put_pipe_info(inode, inode->i_pipe);
|
||||
fput(f);
|
||||
return PTR_ERR(res[0]);
|
||||
}
|
||||
|
||||
path_get(&path);
|
||||
res[0]->private_data = inode->i_pipe;
|
||||
res[0]->f_flags = O_RDONLY | (flags & O_NONBLOCK);
|
||||
res[1] = f;
|
||||
return 0;
|
||||
|
||||
err_file:
|
||||
put_filp(f);
|
||||
err_dentry:
|
||||
free_pipe_info(inode->i_pipe);
|
||||
path_put(&path);
|
||||
return err;
|
||||
|
||||
err_inode:
|
||||
free_pipe_info(inode->i_pipe);
|
||||
iput(inode);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __do_pipe_flags(int *fd, struct file **files, int flags)
|
||||
|
|
|
|||
Loading…
Reference in a new issue