mirror of
https://github.com/torvalds/linux.git
synced 2025-11-30 23:16:01 +07:00
Merge tag 'vfs-6.18-rc1.async' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
Pull vfs async directory updates from Christian Brauner:
"This contains further preparatory changes for the asynchronous directory
locking scheme:
- Add lookup_one_positive_killable() which allows overlayfs to
perform lookup that won't block on a fatal signal
- Unify the mount idmap handling in struct renamedata as a rename can
only happen within a single mount
- Introduce kern_path_parent() for audit which sets the path to the
parent and returns a dentry for the target without holding any
locks on return
- Rename kern_path_locked() as it is only used to prepare for the
removal of an object from the filesystem:
kern_path_locked() => start_removing_path()
kern_path_create() => start_creating_path()
user_path_create() => start_creating_user_path()
user_path_locked_at() => start_removing_user_path_at()
done_path_create() => end_creating_path()
NA => end_removing_path()"
* tag 'vfs-6.18-rc1.async' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs:
debugfs: rename start_creating() to debugfs_start_creating()
VFS: rename kern_path_locked() and related functions.
VFS/audit: introduce kern_path_parent() for audit
VFS: unify old_mnt_idmap and new_mnt_idmap in renamedata
VFS: discard err2 in filename_create()
VFS/ovl: add lookup_one_positive_killable()
This commit is contained in:
@@ -1285,3 +1285,15 @@ rather than a VMA, as the VMA at this stage is not yet valid.
|
||||
The vm_area_desc provides the minimum required information for a filesystem
|
||||
to initialise state upon memory mapping of a file-backed region, and output
|
||||
parameters for the file system to set this state.
|
||||
|
||||
---
|
||||
|
||||
**mandatory**
|
||||
|
||||
Several functions are renamed:
|
||||
|
||||
- kern_path_locked -> start_removing_path
|
||||
- kern_path_create -> start_creating_path
|
||||
- user_path_create -> start_creating_user_path
|
||||
- user_path_locked_at -> start_removing_user_path_at
|
||||
- done_path_create -> end_creating_path
|
||||
|
||||
@@ -67,11 +67,11 @@ static long do_spu_create(const char __user *pathname, unsigned int flags,
|
||||
struct dentry *dentry;
|
||||
int ret;
|
||||
|
||||
dentry = user_path_create(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY);
|
||||
dentry = start_creating_user_path(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY);
|
||||
ret = PTR_ERR(dentry);
|
||||
if (!IS_ERR(dentry)) {
|
||||
ret = spufs_create(&path, dentry, flags, mode, neighbor);
|
||||
done_path_create(&path, dentry);
|
||||
end_creating_path(&path, dentry);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -176,7 +176,7 @@ static int dev_mkdir(const char *name, umode_t mode)
|
||||
struct dentry *dentry;
|
||||
struct path path;
|
||||
|
||||
dentry = kern_path_create(AT_FDCWD, name, &path, LOOKUP_DIRECTORY);
|
||||
dentry = start_creating_path(AT_FDCWD, name, &path, LOOKUP_DIRECTORY);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
@@ -184,7 +184,7 @@ static int dev_mkdir(const char *name, umode_t mode)
|
||||
if (!IS_ERR(dentry))
|
||||
/* mark as kernel-created inode */
|
||||
d_inode(dentry)->i_private = &thread;
|
||||
done_path_create(&path, dentry);
|
||||
end_creating_path(&path, dentry);
|
||||
return PTR_ERR_OR_ZERO(dentry);
|
||||
}
|
||||
|
||||
@@ -222,10 +222,10 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid,
|
||||
struct path path;
|
||||
int err;
|
||||
|
||||
dentry = kern_path_create(AT_FDCWD, nodename, &path, 0);
|
||||
dentry = start_creating_path(AT_FDCWD, nodename, &path, 0);
|
||||
if (dentry == ERR_PTR(-ENOENT)) {
|
||||
create_path(nodename);
|
||||
dentry = kern_path_create(AT_FDCWD, nodename, &path, 0);
|
||||
dentry = start_creating_path(AT_FDCWD, nodename, &path, 0);
|
||||
}
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
@@ -246,7 +246,7 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid,
|
||||
/* mark as kernel-created inode */
|
||||
d_inode(dentry)->i_private = &thread;
|
||||
}
|
||||
done_path_create(&path, dentry);
|
||||
end_creating_path(&path, dentry);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -256,7 +256,7 @@ static int dev_rmdir(const char *name)
|
||||
struct dentry *dentry;
|
||||
int err;
|
||||
|
||||
dentry = kern_path_locked(name, &parent);
|
||||
dentry = start_removing_path(name, &parent);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
if (d_inode(dentry)->i_private == &thread)
|
||||
@@ -265,9 +265,7 @@ static int dev_rmdir(const char *name)
|
||||
else
|
||||
err = -EPERM;
|
||||
|
||||
dput(dentry);
|
||||
inode_unlock(d_inode(parent.dentry));
|
||||
path_put(&parent);
|
||||
end_removing_path(&parent, dentry);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -325,7 +323,7 @@ static int handle_remove(const char *nodename, struct device *dev)
|
||||
int deleted = 0;
|
||||
int err = 0;
|
||||
|
||||
dentry = kern_path_locked(nodename, &parent);
|
||||
dentry = start_removing_path(nodename, &parent);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
@@ -349,10 +347,8 @@ static int handle_remove(const char *nodename, struct device *dev)
|
||||
if (!err || err == -ENOENT)
|
||||
deleted = 1;
|
||||
}
|
||||
dput(dentry);
|
||||
inode_unlock(d_inode(parent.dentry));
|
||||
end_removing_path(&parent, dentry);
|
||||
|
||||
path_put(&parent);
|
||||
if (deleted && strchr(nodename, '/'))
|
||||
delete_path(nodename);
|
||||
return err;
|
||||
|
||||
@@ -255,7 +255,7 @@ static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
|
||||
snapshot_src = inode_inum(to_bch_ei(src_path.dentry->d_inode));
|
||||
}
|
||||
|
||||
dst_dentry = user_path_create(arg.dirfd,
|
||||
dst_dentry = start_creating_user_path(arg.dirfd,
|
||||
(const char __user *)(unsigned long)arg.dst_ptr,
|
||||
&dst_path, lookup_flags);
|
||||
error = PTR_ERR_OR_ZERO(dst_dentry);
|
||||
@@ -314,7 +314,7 @@ static long bch2_ioctl_subvolume_create(struct bch_fs *c, struct file *filp,
|
||||
d_instantiate(dst_dentry, &inode->v);
|
||||
fsnotify_mkdir(dir, dst_dentry);
|
||||
err3:
|
||||
done_path_create(&dst_path, dst_dentry);
|
||||
end_creating_path(&dst_path, dst_dentry);
|
||||
err2:
|
||||
if (arg.src_ptr)
|
||||
path_put(&src_path);
|
||||
@@ -334,7 +334,7 @@ static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp,
|
||||
if (arg.flags)
|
||||
return -EINVAL;
|
||||
|
||||
victim = user_path_locked_at(arg.dirfd, name, &path);
|
||||
victim = start_removing_user_path_at(arg.dirfd, name, &path);
|
||||
if (IS_ERR(victim))
|
||||
return PTR_ERR(victim);
|
||||
|
||||
@@ -351,9 +351,7 @@ static long bch2_ioctl_subvolume_destroy(struct bch_fs *c, struct file *filp,
|
||||
d_invalidate(victim);
|
||||
}
|
||||
err:
|
||||
inode_unlock(dir);
|
||||
dput(victim);
|
||||
path_put(&path);
|
||||
end_removing_path(&path, victim);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -387,10 +387,9 @@ try_again:
|
||||
cachefiles_io_error(cache, "Rename security error %d", ret);
|
||||
} else {
|
||||
struct renamedata rd = {
|
||||
.old_mnt_idmap = &nop_mnt_idmap,
|
||||
.mnt_idmap = &nop_mnt_idmap,
|
||||
.old_parent = dir,
|
||||
.old_dentry = rep,
|
||||
.new_mnt_idmap = &nop_mnt_idmap,
|
||||
.new_parent = cache->graveyard,
|
||||
.new_dentry = grave,
|
||||
};
|
||||
|
||||
@@ -362,7 +362,8 @@ struct dentry *debugfs_lookup(const char *name, struct dentry *parent)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_lookup);
|
||||
|
||||
static struct dentry *start_creating(const char *name, struct dentry *parent)
|
||||
static struct dentry *debugfs_start_creating(const char *name,
|
||||
struct dentry *parent)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
int error;
|
||||
@@ -428,7 +429,7 @@ static struct dentry *__debugfs_create_file(const char *name, umode_t mode,
|
||||
if (!(mode & S_IFMT))
|
||||
mode |= S_IFREG;
|
||||
BUG_ON(!S_ISREG(mode));
|
||||
dentry = start_creating(name, parent);
|
||||
dentry = debugfs_start_creating(name, parent);
|
||||
|
||||
if (IS_ERR(dentry))
|
||||
return dentry;
|
||||
@@ -577,7 +578,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_file_size);
|
||||
*/
|
||||
struct dentry *debugfs_create_dir(const char *name, struct dentry *parent)
|
||||
{
|
||||
struct dentry *dentry = start_creating(name, parent);
|
||||
struct dentry *dentry = debugfs_start_creating(name, parent);
|
||||
struct inode *inode;
|
||||
|
||||
if (IS_ERR(dentry))
|
||||
@@ -624,7 +625,7 @@ struct dentry *debugfs_create_automount(const char *name,
|
||||
debugfs_automount_t f,
|
||||
void *data)
|
||||
{
|
||||
struct dentry *dentry = start_creating(name, parent);
|
||||
struct dentry *dentry = debugfs_start_creating(name, parent);
|
||||
struct inode *inode;
|
||||
|
||||
if (IS_ERR(dentry))
|
||||
@@ -687,7 +688,7 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
|
||||
if (!link)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
dentry = start_creating(name, parent);
|
||||
dentry = debugfs_start_creating(name, parent);
|
||||
if (IS_ERR(dentry)) {
|
||||
kfree(link);
|
||||
return dentry;
|
||||
|
||||
@@ -634,10 +634,9 @@ ecryptfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
|
||||
goto out_lock;
|
||||
}
|
||||
|
||||
rd.old_mnt_idmap = &nop_mnt_idmap;
|
||||
rd.mnt_idmap = &nop_mnt_idmap;
|
||||
rd.old_parent = lower_old_dir_dentry;
|
||||
rd.old_dentry = lower_old_dentry;
|
||||
rd.new_mnt_idmap = &nop_mnt_idmap;
|
||||
rd.new_parent = lower_new_dir_dentry;
|
||||
rd.new_dentry = lower_new_dentry;
|
||||
rc = vfs_rename(&rd);
|
||||
|
||||
17
fs/init.c
17
fs/init.c
@@ -149,7 +149,7 @@ int __init init_mknod(const char *filename, umode_t mode, unsigned int dev)
|
||||
else if (!(S_ISBLK(mode) || S_ISCHR(mode)))
|
||||
return -EINVAL;
|
||||
|
||||
dentry = kern_path_create(AT_FDCWD, filename, &path, 0);
|
||||
dentry = start_creating_path(AT_FDCWD, filename, &path, 0);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
@@ -158,7 +158,7 @@ int __init init_mknod(const char *filename, umode_t mode, unsigned int dev)
|
||||
if (!error)
|
||||
error = vfs_mknod(mnt_idmap(path.mnt), path.dentry->d_inode,
|
||||
dentry, mode, new_decode_dev(dev));
|
||||
done_path_create(&path, dentry);
|
||||
end_creating_path(&path, dentry);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -173,7 +173,7 @@ int __init init_link(const char *oldname, const char *newname)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
new_dentry = kern_path_create(AT_FDCWD, newname, &new_path, 0);
|
||||
new_dentry = start_creating_path(AT_FDCWD, newname, &new_path, 0);
|
||||
error = PTR_ERR(new_dentry);
|
||||
if (IS_ERR(new_dentry))
|
||||
goto out;
|
||||
@@ -191,7 +191,7 @@ int __init init_link(const char *oldname, const char *newname)
|
||||
error = vfs_link(old_path.dentry, idmap, new_path.dentry->d_inode,
|
||||
new_dentry, NULL);
|
||||
out_dput:
|
||||
done_path_create(&new_path, new_dentry);
|
||||
end_creating_path(&new_path, new_dentry);
|
||||
out:
|
||||
path_put(&old_path);
|
||||
return error;
|
||||
@@ -203,14 +203,14 @@ int __init init_symlink(const char *oldname, const char *newname)
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
dentry = kern_path_create(AT_FDCWD, newname, &path, 0);
|
||||
dentry = start_creating_path(AT_FDCWD, newname, &path, 0);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
error = security_path_symlink(&path, dentry, oldname);
|
||||
if (!error)
|
||||
error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode,
|
||||
dentry, oldname);
|
||||
done_path_create(&path, dentry);
|
||||
end_creating_path(&path, dentry);
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -225,7 +225,8 @@ int __init init_mkdir(const char *pathname, umode_t mode)
|
||||
struct path path;
|
||||
int error;
|
||||
|
||||
dentry = kern_path_create(AT_FDCWD, pathname, &path, LOOKUP_DIRECTORY);
|
||||
dentry = start_creating_path(AT_FDCWD, pathname, &path,
|
||||
LOOKUP_DIRECTORY);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
mode = mode_strip_umask(d_inode(path.dentry), mode);
|
||||
@@ -236,7 +237,7 @@ int __init init_mkdir(const char *pathname, umode_t mode)
|
||||
if (IS_ERR(dentry))
|
||||
error = PTR_ERR(dentry);
|
||||
}
|
||||
done_path_create(&path, dentry);
|
||||
end_creating_path(&path, dentry);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
164
fs/namei.c
164
fs/namei.c
@@ -1835,6 +1835,20 @@ static struct dentry *lookup_slow(const struct qstr *name,
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct dentry *lookup_slow_killable(const struct qstr *name,
|
||||
struct dentry *dir,
|
||||
unsigned int flags)
|
||||
{
|
||||
struct inode *inode = dir->d_inode;
|
||||
struct dentry *res;
|
||||
|
||||
if (inode_lock_shared_killable(inode))
|
||||
return ERR_PTR(-EINTR);
|
||||
res = __lookup_slow(name, dir, flags);
|
||||
inode_unlock_shared(inode);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int may_lookup(struct mnt_idmap *idmap,
|
||||
struct nameidata *restrict nd)
|
||||
{
|
||||
@@ -2752,7 +2766,8 @@ static int filename_parentat(int dfd, struct filename *name,
|
||||
}
|
||||
|
||||
/* does lookup, returns the object with parent locked */
|
||||
static struct dentry *__kern_path_locked(int dfd, struct filename *name, struct path *path)
|
||||
static struct dentry *__start_removing_path(int dfd, struct filename *name,
|
||||
struct path *path)
|
||||
{
|
||||
struct path parent_path __free(path_put) = {};
|
||||
struct dentry *d;
|
||||
@@ -2764,18 +2779,42 @@ static struct dentry *__kern_path_locked(int dfd, struct filename *name, struct
|
||||
return ERR_PTR(error);
|
||||
if (unlikely(type != LAST_NORM))
|
||||
return ERR_PTR(-EINVAL);
|
||||
/* don't fail immediately if it's r/o, at least try to report other errors */
|
||||
error = mnt_want_write(parent_path.mnt);
|
||||
inode_lock_nested(parent_path.dentry->d_inode, I_MUTEX_PARENT);
|
||||
d = lookup_one_qstr_excl(&last, parent_path.dentry, 0);
|
||||
if (IS_ERR(d)) {
|
||||
inode_unlock(parent_path.dentry->d_inode);
|
||||
return d;
|
||||
}
|
||||
if (IS_ERR(d))
|
||||
goto unlock;
|
||||
if (error)
|
||||
goto fail;
|
||||
path->dentry = no_free_ptr(parent_path.dentry);
|
||||
path->mnt = no_free_ptr(parent_path.mnt);
|
||||
return d;
|
||||
|
||||
fail:
|
||||
dput(d);
|
||||
d = ERR_PTR(error);
|
||||
unlock:
|
||||
inode_unlock(parent_path.dentry->d_inode);
|
||||
if (!error)
|
||||
mnt_drop_write(parent_path.mnt);
|
||||
return d;
|
||||
}
|
||||
|
||||
struct dentry *kern_path_locked_negative(const char *name, struct path *path)
|
||||
/**
|
||||
* kern_path_parent: lookup path returning parent and target
|
||||
* @name: path name
|
||||
* @path: path to store parent in
|
||||
*
|
||||
* The path @name should end with a normal component, not "." or ".." or "/".
|
||||
* A lookup is performed and if successful the parent information
|
||||
* is store in @parent and the dentry is returned.
|
||||
*
|
||||
* The dentry maybe negative, the parent will be positive.
|
||||
*
|
||||
* Returns: dentry or error.
|
||||
*/
|
||||
struct dentry *kern_path_parent(const char *name, struct path *path)
|
||||
{
|
||||
struct path parent_path __free(path_put) = {};
|
||||
struct filename *filename __free(putname) = getname_kernel(name);
|
||||
@@ -2788,35 +2827,35 @@ struct dentry *kern_path_locked_negative(const char *name, struct path *path)
|
||||
return ERR_PTR(error);
|
||||
if (unlikely(type != LAST_NORM))
|
||||
return ERR_PTR(-EINVAL);
|
||||
inode_lock_nested(parent_path.dentry->d_inode, I_MUTEX_PARENT);
|
||||
d = lookup_one_qstr_excl(&last, parent_path.dentry, LOOKUP_CREATE);
|
||||
if (IS_ERR(d)) {
|
||||
inode_unlock(parent_path.dentry->d_inode);
|
||||
|
||||
d = lookup_noperm_unlocked(&last, parent_path.dentry);
|
||||
if (IS_ERR(d))
|
||||
return d;
|
||||
}
|
||||
path->dentry = no_free_ptr(parent_path.dentry);
|
||||
path->mnt = no_free_ptr(parent_path.mnt);
|
||||
return d;
|
||||
}
|
||||
|
||||
struct dentry *kern_path_locked(const char *name, struct path *path)
|
||||
struct dentry *start_removing_path(const char *name, struct path *path)
|
||||
{
|
||||
struct filename *filename = getname_kernel(name);
|
||||
struct dentry *res = __kern_path_locked(AT_FDCWD, filename, path);
|
||||
struct dentry *res = __start_removing_path(AT_FDCWD, filename, path);
|
||||
|
||||
putname(filename);
|
||||
return res;
|
||||
}
|
||||
|
||||
struct dentry *user_path_locked_at(int dfd, const char __user *name, struct path *path)
|
||||
struct dentry *start_removing_user_path_at(int dfd,
|
||||
const char __user *name,
|
||||
struct path *path)
|
||||
{
|
||||
struct filename *filename = getname(name);
|
||||
struct dentry *res = __kern_path_locked(dfd, filename, path);
|
||||
struct dentry *res = __start_removing_path(dfd, filename, path);
|
||||
|
||||
putname(filename);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(user_path_locked_at);
|
||||
EXPORT_SYMBOL(start_removing_user_path_at);
|
||||
|
||||
int kern_path(const char *name, unsigned int flags, struct path *path)
|
||||
{
|
||||
@@ -3018,6 +3057,47 @@ struct dentry *lookup_one_unlocked(struct mnt_idmap *idmap, struct qstr *name,
|
||||
}
|
||||
EXPORT_SYMBOL(lookup_one_unlocked);
|
||||
|
||||
/**
|
||||
* lookup_one_positive_killable - lookup single pathname component
|
||||
* @idmap: idmap of the mount the lookup is performed from
|
||||
* @name: qstr olding pathname component to lookup
|
||||
* @base: base directory to lookup from
|
||||
*
|
||||
* This helper will yield ERR_PTR(-ENOENT) on negatives. The helper returns
|
||||
* known positive or ERR_PTR(). This is what most of the users want.
|
||||
*
|
||||
* Note that pinned negative with unlocked parent _can_ become positive at any
|
||||
* time, so callers of lookup_one_unlocked() need to be very careful; pinned
|
||||
* positives have >d_inode stable, so this one avoids such problems.
|
||||
*
|
||||
* This can be used for in-kernel filesystem clients such as file servers.
|
||||
*
|
||||
* It should be called without the parent i_rwsem held, and will take
|
||||
* the i_rwsem itself if necessary. If a fatal signal is pending or
|
||||
* delivered, it will return %-EINTR if the lock is needed.
|
||||
*/
|
||||
struct dentry *lookup_one_positive_killable(struct mnt_idmap *idmap,
|
||||
struct qstr *name,
|
||||
struct dentry *base)
|
||||
{
|
||||
int err;
|
||||
struct dentry *ret;
|
||||
|
||||
err = lookup_one_common(idmap, name, base);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
ret = lookup_dcache(name, base, 0);
|
||||
if (!ret)
|
||||
ret = lookup_slow_killable(name, base, 0);
|
||||
if (!IS_ERR(ret) && d_flags_negative(smp_load_acquire(&ret->d_flags))) {
|
||||
dput(ret);
|
||||
ret = ERR_PTR(-ENOENT);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(lookup_one_positive_killable);
|
||||
|
||||
/**
|
||||
* lookup_one_positive_unlocked - lookup single pathname component
|
||||
* @idmap: idmap of the mount the lookup is performed from
|
||||
@@ -4122,7 +4202,6 @@ static struct dentry *filename_create(int dfd, struct filename *name,
|
||||
unsigned int reval_flag = lookup_flags & LOOKUP_REVAL;
|
||||
unsigned int create_flags = LOOKUP_CREATE | LOOKUP_EXCL;
|
||||
int type;
|
||||
int err2;
|
||||
int error;
|
||||
|
||||
error = filename_parentat(dfd, name, reval_flag, path, &last, &type);
|
||||
@@ -4137,7 +4216,7 @@ static struct dentry *filename_create(int dfd, struct filename *name,
|
||||
goto out;
|
||||
|
||||
/* don't fail immediately if it's r/o, at least try to report other errors */
|
||||
err2 = mnt_want_write(path->mnt);
|
||||
error = mnt_want_write(path->mnt);
|
||||
/*
|
||||
* Do the final lookup. Suppress 'create' if there is a trailing
|
||||
* '/', and a directory wasn't requested.
|
||||
@@ -4150,25 +4229,24 @@ static struct dentry *filename_create(int dfd, struct filename *name,
|
||||
if (IS_ERR(dentry))
|
||||
goto unlock;
|
||||
|
||||
if (unlikely(err2)) {
|
||||
error = err2;
|
||||
if (unlikely(error))
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return dentry;
|
||||
fail:
|
||||
dput(dentry);
|
||||
dentry = ERR_PTR(error);
|
||||
unlock:
|
||||
inode_unlock(path->dentry->d_inode);
|
||||
if (!err2)
|
||||
if (!error)
|
||||
mnt_drop_write(path->mnt);
|
||||
out:
|
||||
path_put(path);
|
||||
return dentry;
|
||||
}
|
||||
|
||||
struct dentry *kern_path_create(int dfd, const char *pathname,
|
||||
struct path *path, unsigned int lookup_flags)
|
||||
struct dentry *start_creating_path(int dfd, const char *pathname,
|
||||
struct path *path, unsigned int lookup_flags)
|
||||
{
|
||||
struct filename *filename = getname_kernel(pathname);
|
||||
struct dentry *res = filename_create(dfd, filename, path, lookup_flags);
|
||||
@@ -4176,9 +4254,9 @@ struct dentry *kern_path_create(int dfd, const char *pathname,
|
||||
putname(filename);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(kern_path_create);
|
||||
EXPORT_SYMBOL(start_creating_path);
|
||||
|
||||
void done_path_create(struct path *path, struct dentry *dentry)
|
||||
void end_creating_path(struct path *path, struct dentry *dentry)
|
||||
{
|
||||
if (!IS_ERR(dentry))
|
||||
dput(dentry);
|
||||
@@ -4186,10 +4264,11 @@ void done_path_create(struct path *path, struct dentry *dentry)
|
||||
mnt_drop_write(path->mnt);
|
||||
path_put(path);
|
||||
}
|
||||
EXPORT_SYMBOL(done_path_create);
|
||||
EXPORT_SYMBOL(end_creating_path);
|
||||
|
||||
inline struct dentry *user_path_create(int dfd, const char __user *pathname,
|
||||
struct path *path, unsigned int lookup_flags)
|
||||
inline struct dentry *start_creating_user_path(
|
||||
int dfd, const char __user *pathname,
|
||||
struct path *path, unsigned int lookup_flags)
|
||||
{
|
||||
struct filename *filename = getname(pathname);
|
||||
struct dentry *res = filename_create(dfd, filename, path, lookup_flags);
|
||||
@@ -4197,7 +4276,7 @@ inline struct dentry *user_path_create(int dfd, const char __user *pathname,
|
||||
putname(filename);
|
||||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(user_path_create);
|
||||
EXPORT_SYMBOL(start_creating_user_path);
|
||||
|
||||
/**
|
||||
* vfs_mknod - create device node or file
|
||||
@@ -4305,7 +4384,7 @@ retry:
|
||||
break;
|
||||
}
|
||||
out2:
|
||||
done_path_create(&path, dentry);
|
||||
end_creating_path(&path, dentry);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
@@ -4409,7 +4488,7 @@ retry:
|
||||
if (IS_ERR(dentry))
|
||||
error = PTR_ERR(dentry);
|
||||
}
|
||||
done_path_create(&path, dentry);
|
||||
end_creating_path(&path, dentry);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
@@ -4763,7 +4842,7 @@ retry:
|
||||
if (!error)
|
||||
error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode,
|
||||
dentry, from->name);
|
||||
done_path_create(&path, dentry);
|
||||
end_creating_path(&path, dentry);
|
||||
if (retry_estale(error, lookup_flags)) {
|
||||
lookup_flags |= LOOKUP_REVAL;
|
||||
goto retry;
|
||||
@@ -4932,7 +5011,7 @@ retry:
|
||||
error = vfs_link(old_path.dentry, idmap, new_path.dentry->d_inode,
|
||||
new_dentry, &delegated_inode);
|
||||
out_dput:
|
||||
done_path_create(&new_path, new_dentry);
|
||||
end_creating_path(&new_path, new_dentry);
|
||||
if (delegated_inode) {
|
||||
error = break_deleg_wait(&delegated_inode);
|
||||
if (!error) {
|
||||
@@ -5032,20 +5111,20 @@ int vfs_rename(struct renamedata *rd)
|
||||
if (source == target)
|
||||
return 0;
|
||||
|
||||
error = may_delete(rd->old_mnt_idmap, old_dir, old_dentry, is_dir);
|
||||
error = may_delete(rd->mnt_idmap, old_dir, old_dentry, is_dir);
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (!target) {
|
||||
error = may_create(rd->new_mnt_idmap, new_dir, new_dentry);
|
||||
error = may_create(rd->mnt_idmap, new_dir, new_dentry);
|
||||
} else {
|
||||
new_is_dir = d_is_dir(new_dentry);
|
||||
|
||||
if (!(flags & RENAME_EXCHANGE))
|
||||
error = may_delete(rd->new_mnt_idmap, new_dir,
|
||||
error = may_delete(rd->mnt_idmap, new_dir,
|
||||
new_dentry, is_dir);
|
||||
else
|
||||
error = may_delete(rd->new_mnt_idmap, new_dir,
|
||||
error = may_delete(rd->mnt_idmap, new_dir,
|
||||
new_dentry, new_is_dir);
|
||||
}
|
||||
if (error)
|
||||
@@ -5060,13 +5139,13 @@ int vfs_rename(struct renamedata *rd)
|
||||
*/
|
||||
if (new_dir != old_dir) {
|
||||
if (is_dir) {
|
||||
error = inode_permission(rd->old_mnt_idmap, source,
|
||||
error = inode_permission(rd->mnt_idmap, source,
|
||||
MAY_WRITE);
|
||||
if (error)
|
||||
return error;
|
||||
}
|
||||
if ((flags & RENAME_EXCHANGE) && new_is_dir) {
|
||||
error = inode_permission(rd->new_mnt_idmap, target,
|
||||
error = inode_permission(rd->mnt_idmap, target,
|
||||
MAY_WRITE);
|
||||
if (error)
|
||||
return error;
|
||||
@@ -5134,7 +5213,7 @@ int vfs_rename(struct renamedata *rd)
|
||||
if (error)
|
||||
goto out;
|
||||
}
|
||||
error = old_dir->i_op->rename(rd->new_mnt_idmap, old_dir, old_dentry,
|
||||
error = old_dir->i_op->rename(rd->mnt_idmap, old_dir, old_dentry,
|
||||
new_dir, new_dentry, flags);
|
||||
if (error)
|
||||
goto out;
|
||||
@@ -5277,10 +5356,9 @@ retry_deleg:
|
||||
|
||||
rd.old_parent = old_path.dentry;
|
||||
rd.old_dentry = old_dentry;
|
||||
rd.old_mnt_idmap = mnt_idmap(old_path.mnt);
|
||||
rd.mnt_idmap = mnt_idmap(old_path.mnt);
|
||||
rd.new_parent = new_path.dentry;
|
||||
rd.new_dentry = new_dentry;
|
||||
rd.new_mnt_idmap = mnt_idmap(new_path.mnt);
|
||||
rd.delegated_inode = &delegated_inode;
|
||||
rd.flags = flags;
|
||||
error = vfs_rename(&rd);
|
||||
|
||||
@@ -1951,10 +1951,9 @@ retry:
|
||||
goto out_dput_old;
|
||||
} else {
|
||||
struct renamedata rd = {
|
||||
.old_mnt_idmap = &nop_mnt_idmap,
|
||||
.mnt_idmap = &nop_mnt_idmap,
|
||||
.old_parent = fdentry,
|
||||
.old_dentry = odentry,
|
||||
.new_mnt_idmap = &nop_mnt_idmap,
|
||||
.new_parent = tdentry,
|
||||
.new_dentry = ndentry,
|
||||
};
|
||||
|
||||
@@ -4418,7 +4418,7 @@ int ocfs2_reflink_ioctl(struct inode *inode,
|
||||
return error;
|
||||
}
|
||||
|
||||
new_dentry = user_path_create(AT_FDCWD, newname, &new_path, 0);
|
||||
new_dentry = start_creating_user_path(AT_FDCWD, newname, &new_path, 0);
|
||||
error = PTR_ERR(new_dentry);
|
||||
if (IS_ERR(new_dentry)) {
|
||||
mlog_errno(error);
|
||||
@@ -4435,7 +4435,7 @@ int ocfs2_reflink_ioctl(struct inode *inode,
|
||||
d_inode(new_path.dentry),
|
||||
new_dentry, preserve);
|
||||
out_dput:
|
||||
done_path_create(&new_path, new_dentry);
|
||||
end_creating_path(&new_path, new_dentry);
|
||||
out:
|
||||
path_put(&old_path);
|
||||
|
||||
|
||||
@@ -361,10 +361,9 @@ static inline int ovl_do_rename(struct ovl_fs *ofs, struct dentry *olddir,
|
||||
{
|
||||
int err;
|
||||
struct renamedata rd = {
|
||||
.old_mnt_idmap = ovl_upper_mnt_idmap(ofs),
|
||||
.mnt_idmap = ovl_upper_mnt_idmap(ofs),
|
||||
.old_parent = olddir,
|
||||
.old_dentry = olddentry,
|
||||
.new_mnt_idmap = ovl_upper_mnt_idmap(ofs),
|
||||
.new_parent = newdir,
|
||||
.new_dentry = newdentry,
|
||||
.flags = flags,
|
||||
|
||||
@@ -270,26 +270,26 @@ static bool ovl_fill_merge(struct dir_context *ctx, const char *name,
|
||||
|
||||
static int ovl_check_whiteouts(const struct path *path, struct ovl_readdir_data *rdd)
|
||||
{
|
||||
int err;
|
||||
int err = 0;
|
||||
struct dentry *dentry, *dir = path->dentry;
|
||||
const struct cred *old_cred;
|
||||
|
||||
old_cred = ovl_override_creds(rdd->dentry->d_sb);
|
||||
|
||||
err = down_write_killable(&dir->d_inode->i_rwsem);
|
||||
if (!err) {
|
||||
while (rdd->first_maybe_whiteout) {
|
||||
struct ovl_cache_entry *p =
|
||||
rdd->first_maybe_whiteout;
|
||||
rdd->first_maybe_whiteout = p->next_maybe_whiteout;
|
||||
dentry = lookup_one(mnt_idmap(path->mnt),
|
||||
&QSTR_LEN(p->name, p->len), dir);
|
||||
if (!IS_ERR(dentry)) {
|
||||
p->is_whiteout = ovl_is_whiteout(dentry);
|
||||
dput(dentry);
|
||||
}
|
||||
while (rdd->first_maybe_whiteout) {
|
||||
struct ovl_cache_entry *p =
|
||||
rdd->first_maybe_whiteout;
|
||||
rdd->first_maybe_whiteout = p->next_maybe_whiteout;
|
||||
dentry = lookup_one_positive_killable(mnt_idmap(path->mnt),
|
||||
&QSTR_LEN(p->name, p->len),
|
||||
dir);
|
||||
if (!IS_ERR(dentry)) {
|
||||
p->is_whiteout = ovl_is_whiteout(dentry);
|
||||
dput(dentry);
|
||||
} else if (PTR_ERR(dentry) == -EINTR) {
|
||||
err = -EINTR;
|
||||
break;
|
||||
}
|
||||
inode_unlock(dir->d_inode);
|
||||
}
|
||||
ovl_revert_creds(old_cred);
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ int ksmbd_vfs_create(struct ksmbd_work *work, const char *name, umode_t mode)
|
||||
pr_err("File(%s): creation failed (err:%d)\n", name, err);
|
||||
}
|
||||
|
||||
done_path_create(&path, dentry);
|
||||
end_creating_path(&path, dentry);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ int ksmbd_vfs_mkdir(struct ksmbd_work *work, const char *name, umode_t mode)
|
||||
if (!err && dentry != d)
|
||||
ksmbd_vfs_inherit_owner(work, d_inode(path.dentry), d_inode(dentry));
|
||||
|
||||
done_path_create(&path, dentry);
|
||||
end_creating_path(&path, dentry);
|
||||
if (err)
|
||||
pr_err("mkdir(%s): creation failed (err:%d)\n", name, err);
|
||||
return err;
|
||||
@@ -669,7 +669,7 @@ int ksmbd_vfs_link(struct ksmbd_work *work, const char *oldname,
|
||||
ksmbd_debug(VFS, "vfs_link failed err %d\n", err);
|
||||
|
||||
out3:
|
||||
done_path_create(&newpath, dentry);
|
||||
end_creating_path(&newpath, dentry);
|
||||
out2:
|
||||
path_put(&oldpath);
|
||||
out1:
|
||||
@@ -770,10 +770,9 @@ retry:
|
||||
goto out4;
|
||||
}
|
||||
|
||||
rd.old_mnt_idmap = mnt_idmap(old_path->mnt),
|
||||
rd.mnt_idmap = mnt_idmap(old_path->mnt),
|
||||
rd.old_parent = old_parent,
|
||||
rd.old_dentry = old_child,
|
||||
rd.new_mnt_idmap = mnt_idmap(new_path.mnt),
|
||||
rd.new_parent = new_path.dentry,
|
||||
rd.new_dentry = new_dentry,
|
||||
rd.flags = flags,
|
||||
@@ -1326,7 +1325,7 @@ struct dentry *ksmbd_vfs_kern_path_create(struct ksmbd_work *work,
|
||||
if (!abs_name)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
dent = kern_path_create(AT_FDCWD, abs_name, path, flags);
|
||||
dent = start_creating_path(AT_FDCWD, abs_name, path, flags);
|
||||
kfree(abs_name);
|
||||
return dent;
|
||||
}
|
||||
|
||||
@@ -2118,20 +2118,18 @@ int vfs_unlink(struct mnt_idmap *, struct inode *, struct dentry *,
|
||||
|
||||
/**
|
||||
* struct renamedata - contains all information required for renaming
|
||||
* @old_mnt_idmap: idmap of the old mount the inode was found from
|
||||
* @mnt_idmap: idmap of the mount in which the rename is happening.
|
||||
* @old_parent: parent of source
|
||||
* @old_dentry: source
|
||||
* @new_mnt_idmap: idmap of the new mount the inode was found from
|
||||
* @new_parent: parent of destination
|
||||
* @new_dentry: destination
|
||||
* @delegated_inode: returns an inode needing a delegation break
|
||||
* @flags: rename flags
|
||||
*/
|
||||
struct renamedata {
|
||||
struct mnt_idmap *old_mnt_idmap;
|
||||
struct mnt_idmap *mnt_idmap;
|
||||
struct dentry *old_parent;
|
||||
struct dentry *old_dentry;
|
||||
struct mnt_idmap *new_mnt_idmap;
|
||||
struct dentry *new_parent;
|
||||
struct dentry *new_dentry;
|
||||
struct inode **delegated_inode;
|
||||
|
||||
@@ -57,13 +57,17 @@ struct dentry *lookup_one_qstr_excl(const struct qstr *name,
|
||||
struct dentry *base,
|
||||
unsigned int flags);
|
||||
extern int kern_path(const char *, unsigned, struct path *);
|
||||
struct dentry *kern_path_parent(const char *name, struct path *parent);
|
||||
|
||||
extern struct dentry *kern_path_create(int, const char *, struct path *, unsigned int);
|
||||
extern struct dentry *user_path_create(int, const char __user *, struct path *, unsigned int);
|
||||
extern void done_path_create(struct path *, struct dentry *);
|
||||
extern struct dentry *kern_path_locked(const char *, struct path *);
|
||||
extern struct dentry *kern_path_locked_negative(const char *, struct path *);
|
||||
extern struct dentry *user_path_locked_at(int , const char __user *, struct path *);
|
||||
extern struct dentry *start_creating_path(int, const char *, struct path *, unsigned int);
|
||||
extern struct dentry *start_creating_user_path(int, const char __user *, struct path *, unsigned int);
|
||||
extern void end_creating_path(struct path *, struct dentry *);
|
||||
extern struct dentry *start_removing_path(const char *, struct path *);
|
||||
extern struct dentry *start_removing_user_path_at(int , const char __user *, struct path *);
|
||||
static inline void end_removing_path(struct path *path , struct dentry *dentry)
|
||||
{
|
||||
end_creating_path(path, dentry);
|
||||
}
|
||||
int vfs_path_parent_lookup(struct filename *filename, unsigned int flags,
|
||||
struct path *parent, struct qstr *last, int *type,
|
||||
const struct path *root);
|
||||
@@ -80,6 +84,9 @@ struct dentry *lookup_one_unlocked(struct mnt_idmap *idmap,
|
||||
struct dentry *lookup_one_positive_unlocked(struct mnt_idmap *idmap,
|
||||
struct qstr *name,
|
||||
struct dentry *base);
|
||||
struct dentry *lookup_one_positive_killable(struct mnt_idmap *idmap,
|
||||
struct qstr *name,
|
||||
struct dentry *base);
|
||||
|
||||
extern int follow_down_one(struct path *);
|
||||
extern int follow_down(struct path *path, unsigned int flags);
|
||||
|
||||
@@ -76,17 +76,18 @@ struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pa
|
||||
struct audit_fsnotify_mark *audit_mark;
|
||||
struct path path;
|
||||
struct dentry *dentry;
|
||||
struct inode *inode;
|
||||
int ret;
|
||||
|
||||
if (pathname[0] != '/' || pathname[len-1] == '/')
|
||||
return ERR_PTR(-EINVAL);
|
||||
|
||||
dentry = kern_path_locked(pathname, &path);
|
||||
dentry = kern_path_parent(pathname, &path);
|
||||
if (IS_ERR(dentry))
|
||||
return ERR_CAST(dentry); /* returning an error */
|
||||
inode = path.dentry->d_inode;
|
||||
inode_unlock(inode);
|
||||
if (d_really_is_negative(dentry)) {
|
||||
audit_mark = ERR_PTR(-ENOENT);
|
||||
goto out;
|
||||
}
|
||||
|
||||
audit_mark = kzalloc(sizeof(*audit_mark), GFP_KERNEL);
|
||||
if (unlikely(!audit_mark)) {
|
||||
@@ -100,7 +101,7 @@ struct audit_fsnotify_mark *audit_alloc_mark(struct audit_krule *krule, char *pa
|
||||
audit_update_mark(audit_mark, dentry->d_inode);
|
||||
audit_mark->rule = krule;
|
||||
|
||||
ret = fsnotify_add_inode_mark(&audit_mark->mark, inode, 0);
|
||||
ret = fsnotify_add_inode_mark(&audit_mark->mark, path.dentry->d_inode, 0);
|
||||
if (ret < 0) {
|
||||
audit_mark->path = NULL;
|
||||
fsnotify_put_mark(&audit_mark->mark);
|
||||
|
||||
@@ -349,7 +349,7 @@ static int audit_get_nd(struct audit_watch *watch, struct path *parent)
|
||||
{
|
||||
struct dentry *d;
|
||||
|
||||
d = kern_path_locked_negative(watch->path, parent);
|
||||
d = kern_path_parent(watch->path, parent);
|
||||
if (IS_ERR(d))
|
||||
return PTR_ERR(d);
|
||||
|
||||
@@ -359,7 +359,6 @@ static int audit_get_nd(struct audit_watch *watch, struct path *parent)
|
||||
watch->ino = d_backing_inode(d)->i_ino;
|
||||
}
|
||||
|
||||
inode_unlock(d_backing_inode(parent->dentry));
|
||||
dput(d);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -442,7 +442,7 @@ static int bpf_obj_do_pin(int path_fd, const char __user *pathname, void *raw,
|
||||
umode_t mode;
|
||||
int ret;
|
||||
|
||||
dentry = user_path_create(path_fd, pathname, &path, 0);
|
||||
dentry = start_creating_user_path(path_fd, pathname, &path, 0);
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
|
||||
@@ -471,7 +471,7 @@ static int bpf_obj_do_pin(int path_fd, const char __user *pathname, void *raw,
|
||||
ret = -EPERM;
|
||||
}
|
||||
out:
|
||||
done_path_create(&path, dentry);
|
||||
end_creating_path(&path, dentry);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -1387,7 +1387,7 @@ static int unix_bind_bsd(struct sock *sk, struct sockaddr_un *sunaddr,
|
||||
* Get the parent directory, calculate the hash for last
|
||||
* component.
|
||||
*/
|
||||
dentry = kern_path_create(AT_FDCWD, addr->name->sun_path, &parent, 0);
|
||||
dentry = start_creating_path(AT_FDCWD, addr->name->sun_path, &parent, 0);
|
||||
if (IS_ERR(dentry)) {
|
||||
err = PTR_ERR(dentry);
|
||||
goto out;
|
||||
@@ -1417,7 +1417,7 @@ static int unix_bind_bsd(struct sock *sk, struct sockaddr_un *sunaddr,
|
||||
unix_table_double_unlock(net, old_hash, new_hash);
|
||||
unix_insert_bsd_socket(sk);
|
||||
mutex_unlock(&u->bindlock);
|
||||
done_path_create(&parent, dentry);
|
||||
end_creating_path(&parent, dentry);
|
||||
return 0;
|
||||
|
||||
out_unlock:
|
||||
@@ -1427,7 +1427,7 @@ out_unlink:
|
||||
/* failed after successful mknod? unlink what we'd created... */
|
||||
vfs_unlink(idmap, d_inode(parent.dentry), dentry, NULL);
|
||||
out_path:
|
||||
done_path_create(&parent, dentry);
|
||||
end_creating_path(&parent, dentry);
|
||||
out:
|
||||
unix_release_addr(addr);
|
||||
return err == -EEXIST ? -EADDRINUSE : err;
|
||||
|
||||
Reference in New Issue
Block a user