mirror of https://github.com/torvalds/linux.git
filelock: add struct delegated_inode
The current API requires a pointer to an inode pointer. It's easy for callers to get this wrong. Add a new delegated_inode structure and use that to pass back any inode that needs to be waited on. Reviewed-by: Jan Kara <jack@suse.cz> Reviewed-by: NeilBrown <neil@brown.name> Signed-off-by: Jeff Layton <jlayton@kernel.org> Link: https://patch.msgid.link/20251111-dir-deleg-ro-v6-3-52f3feebb2f2@kernel.org Signed-off-by: Christian Brauner <brauner@kernel.org>
This commit is contained in:
parent
4be9f3cc58
commit
6976ed2dd0
|
|
@ -415,7 +415,7 @@ EXPORT_SYMBOL(may_setattr);
|
|||
* performed on the raw inode simply pass @nop_mnt_idmap.
|
||||
*/
|
||||
int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *attr, struct inode **delegated_inode)
|
||||
struct iattr *attr, struct delegated_inode *delegated_inode)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
umode_t mode = inode->i_mode;
|
||||
|
|
|
|||
18
fs/namei.c
18
fs/namei.c
|
|
@ -4648,7 +4648,7 @@ SYSCALL_DEFINE1(rmdir, const char __user *, pathname)
|
|||
* raw inode simply pass @nop_mnt_idmap.
|
||||
*/
|
||||
int vfs_unlink(struct mnt_idmap *idmap, struct inode *dir,
|
||||
struct dentry *dentry, struct inode **delegated_inode)
|
||||
struct dentry *dentry, struct delegated_inode *delegated_inode)
|
||||
{
|
||||
struct inode *target = dentry->d_inode;
|
||||
int error = may_delete(idmap, dir, dentry, 0);
|
||||
|
|
@ -4706,7 +4706,7 @@ int do_unlinkat(int dfd, struct filename *name)
|
|||
struct qstr last;
|
||||
int type;
|
||||
struct inode *inode = NULL;
|
||||
struct inode *delegated_inode = NULL;
|
||||
struct delegated_inode delegated_inode = { };
|
||||
unsigned int lookup_flags = 0;
|
||||
retry:
|
||||
error = filename_parentat(dfd, name, lookup_flags, &path, &last, &type);
|
||||
|
|
@ -4743,7 +4743,7 @@ int do_unlinkat(int dfd, struct filename *name)
|
|||
if (inode)
|
||||
iput(inode); /* truncate the inode here */
|
||||
inode = NULL;
|
||||
if (delegated_inode) {
|
||||
if (is_delegated(&delegated_inode)) {
|
||||
error = break_deleg_wait(&delegated_inode);
|
||||
if (!error)
|
||||
goto retry_deleg;
|
||||
|
|
@ -4892,7 +4892,7 @@ SYSCALL_DEFINE2(symlink, const char __user *, oldname, const char __user *, newn
|
|||
*/
|
||||
int vfs_link(struct dentry *old_dentry, struct mnt_idmap *idmap,
|
||||
struct inode *dir, struct dentry *new_dentry,
|
||||
struct inode **delegated_inode)
|
||||
struct delegated_inode *delegated_inode)
|
||||
{
|
||||
struct inode *inode = old_dentry->d_inode;
|
||||
unsigned max_links = dir->i_sb->s_max_links;
|
||||
|
|
@ -4968,7 +4968,7 @@ int do_linkat(int olddfd, struct filename *old, int newdfd,
|
|||
struct mnt_idmap *idmap;
|
||||
struct dentry *new_dentry;
|
||||
struct path old_path, new_path;
|
||||
struct inode *delegated_inode = NULL;
|
||||
struct delegated_inode delegated_inode = { };
|
||||
int how = 0;
|
||||
int error;
|
||||
|
||||
|
|
@ -5012,7 +5012,7 @@ int do_linkat(int olddfd, struct filename *old, int newdfd,
|
|||
new_dentry, &delegated_inode);
|
||||
out_dput:
|
||||
end_creating_path(&new_path, new_dentry);
|
||||
if (delegated_inode) {
|
||||
if (is_delegated(&delegated_inode)) {
|
||||
error = break_deleg_wait(&delegated_inode);
|
||||
if (!error) {
|
||||
path_put(&old_path);
|
||||
|
|
@ -5098,7 +5098,7 @@ int vfs_rename(struct renamedata *rd)
|
|||
struct inode *new_dir = d_inode(rd->new_parent);
|
||||
struct dentry *old_dentry = rd->old_dentry;
|
||||
struct dentry *new_dentry = rd->new_dentry;
|
||||
struct inode **delegated_inode = rd->delegated_inode;
|
||||
struct delegated_inode *delegated_inode = rd->delegated_inode;
|
||||
unsigned int flags = rd->flags;
|
||||
bool is_dir = d_is_dir(old_dentry);
|
||||
struct inode *source = old_dentry->d_inode;
|
||||
|
|
@ -5261,7 +5261,7 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd,
|
|||
struct path old_path, new_path;
|
||||
struct qstr old_last, new_last;
|
||||
int old_type, new_type;
|
||||
struct inode *delegated_inode = NULL;
|
||||
struct delegated_inode delegated_inode = { };
|
||||
unsigned int lookup_flags = 0, target_flags =
|
||||
LOOKUP_RENAME_TARGET | LOOKUP_CREATE;
|
||||
bool should_retry = false;
|
||||
|
|
@ -5369,7 +5369,7 @@ int do_renameat2(int olddfd, struct filename *from, int newdfd,
|
|||
exit3:
|
||||
unlock_rename(new_path.dentry, old_path.dentry);
|
||||
exit_lock_rename:
|
||||
if (delegated_inode) {
|
||||
if (is_delegated(&delegated_inode)) {
|
||||
error = break_deleg_wait(&delegated_inode);
|
||||
if (!error)
|
||||
goto retry_deleg;
|
||||
|
|
|
|||
|
|
@ -631,7 +631,7 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename)
|
|||
int chmod_common(const struct path *path, umode_t mode)
|
||||
{
|
||||
struct inode *inode = path->dentry->d_inode;
|
||||
struct inode *delegated_inode = NULL;
|
||||
struct delegated_inode delegated_inode = { };
|
||||
struct iattr newattrs;
|
||||
int error;
|
||||
|
||||
|
|
@ -651,7 +651,7 @@ int chmod_common(const struct path *path, umode_t mode)
|
|||
&newattrs, &delegated_inode);
|
||||
out_unlock:
|
||||
inode_unlock(inode);
|
||||
if (delegated_inode) {
|
||||
if (is_delegated(&delegated_inode)) {
|
||||
error = break_deleg_wait(&delegated_inode);
|
||||
if (!error)
|
||||
goto retry_deleg;
|
||||
|
|
@ -756,7 +756,7 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
|
|||
struct mnt_idmap *idmap;
|
||||
struct user_namespace *fs_userns;
|
||||
struct inode *inode = path->dentry->d_inode;
|
||||
struct inode *delegated_inode = NULL;
|
||||
struct delegated_inode delegated_inode = { };
|
||||
int error;
|
||||
struct iattr newattrs;
|
||||
kuid_t uid;
|
||||
|
|
@ -791,7 +791,7 @@ int chown_common(const struct path *path, uid_t user, gid_t group)
|
|||
error = notify_change(idmap, path->dentry, &newattrs,
|
||||
&delegated_inode);
|
||||
inode_unlock(inode);
|
||||
if (delegated_inode) {
|
||||
if (is_delegated(&delegated_inode)) {
|
||||
error = break_deleg_wait(&delegated_inode);
|
||||
if (!error)
|
||||
goto retry_deleg;
|
||||
|
|
|
|||
|
|
@ -1091,7 +1091,7 @@ int vfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
int acl_type;
|
||||
int error;
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct inode *delegated_inode = NULL;
|
||||
struct delegated_inode delegated_inode = { };
|
||||
|
||||
acl_type = posix_acl_type(acl_name);
|
||||
if (acl_type < 0)
|
||||
|
|
@ -1141,7 +1141,7 @@ int vfs_set_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
out_inode_unlock:
|
||||
inode_unlock(inode);
|
||||
|
||||
if (delegated_inode) {
|
||||
if (is_delegated(&delegated_inode)) {
|
||||
error = break_deleg_wait(&delegated_inode);
|
||||
if (!error)
|
||||
goto retry_deleg;
|
||||
|
|
@ -1212,7 +1212,7 @@ int vfs_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
int acl_type;
|
||||
int error;
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct inode *delegated_inode = NULL;
|
||||
struct delegated_inode delegated_inode = { };
|
||||
|
||||
acl_type = posix_acl_type(acl_name);
|
||||
if (acl_type < 0)
|
||||
|
|
@ -1249,7 +1249,7 @@ int vfs_remove_acl(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
out_inode_unlock:
|
||||
inode_unlock(inode);
|
||||
|
||||
if (delegated_inode) {
|
||||
if (is_delegated(&delegated_inode)) {
|
||||
error = break_deleg_wait(&delegated_inode);
|
||||
if (!error)
|
||||
goto retry_deleg;
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ int vfs_utimes(const struct path *path, struct timespec64 *times)
|
|||
int error;
|
||||
struct iattr newattrs;
|
||||
struct inode *inode = path->dentry->d_inode;
|
||||
struct inode *delegated_inode = NULL;
|
||||
struct delegated_inode delegated_inode = { };
|
||||
|
||||
if (times) {
|
||||
if (!nsec_valid(times[0].tv_nsec) ||
|
||||
|
|
@ -66,7 +66,7 @@ int vfs_utimes(const struct path *path, struct timespec64 *times)
|
|||
error = notify_change(mnt_idmap(path->mnt), path->dentry, &newattrs,
|
||||
&delegated_inode);
|
||||
inode_unlock(inode);
|
||||
if (delegated_inode) {
|
||||
if (is_delegated(&delegated_inode)) {
|
||||
error = break_deleg_wait(&delegated_inode);
|
||||
if (!error)
|
||||
goto retry_deleg;
|
||||
|
|
|
|||
12
fs/xattr.c
12
fs/xattr.c
|
|
@ -274,7 +274,7 @@ int __vfs_setxattr_noperm(struct mnt_idmap *idmap,
|
|||
int
|
||||
__vfs_setxattr_locked(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
const char *name, const void *value, size_t size,
|
||||
int flags, struct inode **delegated_inode)
|
||||
int flags, struct delegated_inode *delegated_inode)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
|
|
@ -305,7 +305,7 @@ vfs_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
const char *name, const void *value, size_t size, int flags)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *delegated_inode = NULL;
|
||||
struct delegated_inode delegated_inode = { };
|
||||
const void *orig_value = value;
|
||||
int error;
|
||||
|
||||
|
|
@ -322,7 +322,7 @@ vfs_setxattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
flags, &delegated_inode);
|
||||
inode_unlock(inode);
|
||||
|
||||
if (delegated_inode) {
|
||||
if (is_delegated(&delegated_inode)) {
|
||||
error = break_deleg_wait(&delegated_inode);
|
||||
if (!error)
|
||||
goto retry_deleg;
|
||||
|
|
@ -533,7 +533,7 @@ EXPORT_SYMBOL(__vfs_removexattr);
|
|||
int
|
||||
__vfs_removexattr_locked(struct mnt_idmap *idmap,
|
||||
struct dentry *dentry, const char *name,
|
||||
struct inode **delegated_inode)
|
||||
struct delegated_inode *delegated_inode)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
int error;
|
||||
|
|
@ -567,7 +567,7 @@ vfs_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
const char *name)
|
||||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *delegated_inode = NULL;
|
||||
struct delegated_inode delegated_inode = { };
|
||||
int error;
|
||||
|
||||
retry_deleg:
|
||||
|
|
@ -576,7 +576,7 @@ vfs_removexattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
name, &delegated_inode);
|
||||
inode_unlock(inode);
|
||||
|
||||
if (delegated_inode) {
|
||||
if (is_delegated(&delegated_inode)) {
|
||||
error = break_deleg_wait(&delegated_inode);
|
||||
if (!error)
|
||||
goto retry_deleg;
|
||||
|
|
|
|||
|
|
@ -486,25 +486,35 @@ static inline int break_deleg(struct inode *inode, unsigned int flags)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int try_break_deleg(struct inode *inode, struct inode **delegated_inode)
|
||||
struct delegated_inode {
|
||||
struct inode *di_inode;
|
||||
};
|
||||
|
||||
static inline bool is_delegated(struct delegated_inode *di)
|
||||
{
|
||||
return di->di_inode;
|
||||
}
|
||||
|
||||
static inline int try_break_deleg(struct inode *inode,
|
||||
struct delegated_inode *di)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = break_deleg(inode, LEASE_BREAK_NONBLOCK);
|
||||
if (ret == -EWOULDBLOCK && delegated_inode) {
|
||||
*delegated_inode = inode;
|
||||
if (ret == -EWOULDBLOCK && di) {
|
||||
di->di_inode = inode;
|
||||
ihold(inode);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline int break_deleg_wait(struct inode **delegated_inode)
|
||||
static inline int break_deleg_wait(struct delegated_inode *di)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = break_deleg(*delegated_inode, 0);
|
||||
iput(*delegated_inode);
|
||||
*delegated_inode = NULL;
|
||||
ret = break_deleg(di->di_inode, 0);
|
||||
iput(di->di_inode);
|
||||
di->di_inode = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -523,6 +533,13 @@ static inline int break_layout(struct inode *inode, bool wait)
|
|||
}
|
||||
|
||||
#else /* !CONFIG_FILE_LOCKING */
|
||||
struct delegated_inode { };
|
||||
|
||||
static inline bool is_delegated(struct delegated_inode *di)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline int break_lease(struct inode *inode, bool wait)
|
||||
{
|
||||
return 0;
|
||||
|
|
@ -533,12 +550,13 @@ static inline int break_deleg(struct inode *inode, unsigned int flags)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static inline int try_break_deleg(struct inode *inode, struct inode **delegated_inode)
|
||||
static inline int try_break_deleg(struct inode *inode,
|
||||
struct delegated_inode *delegated_inode)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int break_deleg_wait(struct inode **delegated_inode)
|
||||
static inline int break_deleg_wait(struct delegated_inode *delegated_inode)
|
||||
{
|
||||
BUG();
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -80,6 +80,7 @@ struct fs_context;
|
|||
struct fs_parameter_spec;
|
||||
struct file_kattr;
|
||||
struct iomap_ops;
|
||||
struct delegated_inode;
|
||||
|
||||
extern void __init inode_init(void);
|
||||
extern void __init inode_init_early(void);
|
||||
|
|
@ -2119,10 +2120,10 @@ int vfs_mknod(struct mnt_idmap *, struct inode *, struct dentry *,
|
|||
int vfs_symlink(struct mnt_idmap *, struct inode *,
|
||||
struct dentry *, const char *);
|
||||
int vfs_link(struct dentry *, struct mnt_idmap *, struct inode *,
|
||||
struct dentry *, struct inode **);
|
||||
struct dentry *, struct delegated_inode *);
|
||||
int vfs_rmdir(struct mnt_idmap *, struct inode *, struct dentry *);
|
||||
int vfs_unlink(struct mnt_idmap *, struct inode *, struct dentry *,
|
||||
struct inode **);
|
||||
struct delegated_inode *);
|
||||
|
||||
/**
|
||||
* struct renamedata - contains all information required for renaming
|
||||
|
|
@ -2140,7 +2141,7 @@ struct renamedata {
|
|||
struct dentry *old_dentry;
|
||||
struct dentry *new_parent;
|
||||
struct dentry *new_dentry;
|
||||
struct inode **delegated_inode;
|
||||
struct delegated_inode *delegated_inode;
|
||||
unsigned int flags;
|
||||
} __randomize_layout;
|
||||
|
||||
|
|
@ -3071,7 +3072,7 @@ static inline int bmap(struct inode *inode, sector_t *block)
|
|||
#endif
|
||||
|
||||
int notify_change(struct mnt_idmap *, struct dentry *,
|
||||
struct iattr *, struct inode **);
|
||||
struct iattr *, struct delegated_inode *);
|
||||
int inode_permission(struct mnt_idmap *, struct inode *, int);
|
||||
int generic_permission(struct mnt_idmap *, struct inode *, int);
|
||||
static inline int file_permission(struct file *file, int mask)
|
||||
|
|
|
|||
|
|
@ -85,12 +85,12 @@ int __vfs_setxattr_noperm(struct mnt_idmap *, struct dentry *,
|
|||
const char *, const void *, size_t, int);
|
||||
int __vfs_setxattr_locked(struct mnt_idmap *, struct dentry *,
|
||||
const char *, const void *, size_t, int,
|
||||
struct inode **);
|
||||
struct delegated_inode *);
|
||||
int vfs_setxattr(struct mnt_idmap *, struct dentry *, const char *,
|
||||
const void *, size_t, int);
|
||||
int __vfs_removexattr(struct mnt_idmap *, struct dentry *, const char *);
|
||||
int __vfs_removexattr_locked(struct mnt_idmap *, struct dentry *,
|
||||
const char *, struct inode **);
|
||||
const char *, struct delegated_inode *);
|
||||
int vfs_removexattr(struct mnt_idmap *, struct dentry *, const char *);
|
||||
|
||||
ssize_t generic_listxattr(struct dentry *dentry, char *buffer, size_t buffer_size);
|
||||
|
|
|
|||
Loading…
Reference in New Issue