Commit f956d08a authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs

Pull misc vfs updates from Al Viro:
 "Misc bits and pieces not fitting into anything more specific"

* 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  vfs: delete unnecessary assignment in vfs_listxattr
  Documentation: filesystems: update filesystem locking documentation
  vfs: namei: use path_equal() in follow_dotdot()
  fs.h: fix outdated comment about file flags
  __inode_security_revalidate() never gets NULL opt_dentry
  make xattr_getsecurity() static
  vfat: simplify checks in vfat_lookup()
  get rid of dead code in d_find_alias()
  it's SB_BORN, not MS_BORN...
  msdos_rmdir(): kill BS comment
  remove rpc_rmdir()
  fs: avoid fdput() after failed fdget() in vfs_dedupe_file_range()
parents cf626b0d eb915375
...@@ -69,31 +69,31 @@ prototypes: ...@@ -69,31 +69,31 @@ prototypes:
locking rules: locking rules:
all may block all may block
i_mutex(inode) i_rwsem(inode)
lookup: yes lookup: shared
create: yes create: exclusive
link: yes (both) link: exclusive (both)
mknod: yes mknod: exclusive
symlink: yes symlink: exclusive
mkdir: yes mkdir: exclusive
unlink: yes (both) unlink: exclusive (both)
rmdir: yes (both) (see below) rmdir: exclusive (both)(see below)
rename: yes (all) (see below) rename: exclusive (all) (see below)
readlink: no readlink: no
get_link: no get_link: no
setattr: yes setattr: exclusive
permission: no (may not block if called in rcu-walk mode) permission: no (may not block if called in rcu-walk mode)
get_acl: no get_acl: no
getattr: no getattr: no
listxattr: no listxattr: no
fiemap: no fiemap: no
update_time: no update_time: no
atomic_open: yes atomic_open: exclusive
tmpfile: no tmpfile: no
Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_mutex on Additionally, ->rmdir(), ->unlink() and ->rename() have ->i_rwsem
victim. exclusive on victim.
cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem. cross-directory ->rename() has (per-superblock) ->s_vfs_rename_sem.
See Documentation/filesystems/directory-locking for more detailed discussion See Documentation/filesystems/directory-locking for more detailed discussion
...@@ -111,10 +111,10 @@ prototypes: ...@@ -111,10 +111,10 @@ prototypes:
locking rules: locking rules:
all may block all may block
i_mutex(inode) i_rwsem(inode)
list: no list: no
get: no get: no
set: yes set: exclusive
--------------------------- super_operations --------------------------- --------------------------- super_operations ---------------------------
prototypes: prototypes:
...@@ -217,14 +217,14 @@ prototypes: ...@@ -217,14 +217,14 @@ prototypes:
locking rules: locking rules:
All except set_page_dirty and freepage may block All except set_page_dirty and freepage may block
PageLocked(page) i_mutex PageLocked(page) i_rwsem
writepage: yes, unlocks (see below) writepage: yes, unlocks (see below)
readpage: yes, unlocks readpage: yes, unlocks
writepages: writepages:
set_page_dirty no set_page_dirty no
readpages: readpages:
write_begin: locks the page yes write_begin: locks the page exclusive
write_end: yes, unlocks yes write_end: yes, unlocks exclusive
bmap: bmap:
invalidatepage: yes invalidatepage: yes
releasepage: yes releasepage: yes
...@@ -439,6 +439,7 @@ prototypes: ...@@ -439,6 +439,7 @@ prototypes:
ssize_t (*read_iter) (struct kiocb *, struct iov_iter *); ssize_t (*read_iter) (struct kiocb *, struct iov_iter *);
ssize_t (*write_iter) (struct kiocb *, struct iov_iter *); ssize_t (*write_iter) (struct kiocb *, struct iov_iter *);
int (*iterate) (struct file *, struct dir_context *); int (*iterate) (struct file *, struct dir_context *);
int (*iterate_shared) (struct file *, struct dir_context *);
unsigned int (*poll) (struct file *, struct poll_table_struct *); unsigned int (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long); long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
long (*compat_ioctl) (struct file *, unsigned int, unsigned long); long (*compat_ioctl) (struct file *, unsigned int, unsigned long);
...@@ -480,6 +481,10 @@ mutex or just to use i_size_read() instead. ...@@ -480,6 +481,10 @@ mutex or just to use i_size_read() instead.
Note: this does not protect the file->f_pos against concurrent modifications Note: this does not protect the file->f_pos against concurrent modifications
since this is something the userspace has to take care about. since this is something the userspace has to take care about.
->iterate() is called with i_rwsem exclusive.
->iterate_shared() is called with i_rwsem at least shared.
->fasync() is responsible for maintaining the FASYNC bit in filp->f_flags. ->fasync() is responsible for maintaining the FASYNC bit in filp->f_flags.
Most instances call fasync_helper(), which does that maintenance, so it's Most instances call fasync_helper(), which does that maintenance, so it's
not normally something one needs to worry about. Return values > 0 will be not normally something one needs to worry about. Return values > 0 will be
......
...@@ -902,6 +902,35 @@ struct dentry *dget_parent(struct dentry *dentry) ...@@ -902,6 +902,35 @@ struct dentry *dget_parent(struct dentry *dentry)
} }
EXPORT_SYMBOL(dget_parent); EXPORT_SYMBOL(dget_parent);
static struct dentry * __d_find_any_alias(struct inode *inode)
{
struct dentry *alias;
if (hlist_empty(&inode->i_dentry))
return NULL;
alias = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
__dget(alias);
return alias;
}
/**
* d_find_any_alias - find any alias for a given inode
* @inode: inode to find an alias for
*
* If any aliases exist for the given inode, take and return a
* reference for one of them. If no aliases exist, return %NULL.
*/
struct dentry *d_find_any_alias(struct inode *inode)
{
struct dentry *de;
spin_lock(&inode->i_lock);
de = __d_find_any_alias(inode);
spin_unlock(&inode->i_lock);
return de;
}
EXPORT_SYMBOL(d_find_any_alias);
/** /**
* d_find_alias - grab a hashed alias of inode * d_find_alias - grab a hashed alias of inode
* @inode: inode in question * @inode: inode in question
...@@ -918,34 +947,19 @@ EXPORT_SYMBOL(dget_parent); ...@@ -918,34 +947,19 @@ EXPORT_SYMBOL(dget_parent);
*/ */
static struct dentry *__d_find_alias(struct inode *inode) static struct dentry *__d_find_alias(struct inode *inode)
{ {
struct dentry *alias, *discon_alias; struct dentry *alias;
if (S_ISDIR(inode->i_mode))
return __d_find_any_alias(inode);
again:
discon_alias = NULL;
hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) { hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
spin_lock(&alias->d_lock); spin_lock(&alias->d_lock);
if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) { if (!d_unhashed(alias)) {
if (IS_ROOT(alias) &&
(alias->d_flags & DCACHE_DISCONNECTED)) {
discon_alias = alias;
} else {
__dget_dlock(alias);
spin_unlock(&alias->d_lock);
return alias;
}
}
spin_unlock(&alias->d_lock);
}
if (discon_alias) {
alias = discon_alias;
spin_lock(&alias->d_lock);
if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
__dget_dlock(alias); __dget_dlock(alias);
spin_unlock(&alias->d_lock); spin_unlock(&alias->d_lock);
return alias; return alias;
} }
spin_unlock(&alias->d_lock); spin_unlock(&alias->d_lock);
goto again;
} }
return NULL; return NULL;
} }
...@@ -1927,35 +1941,6 @@ struct dentry *d_make_root(struct inode *root_inode) ...@@ -1927,35 +1941,6 @@ struct dentry *d_make_root(struct inode *root_inode)
} }
EXPORT_SYMBOL(d_make_root); EXPORT_SYMBOL(d_make_root);
static struct dentry * __d_find_any_alias(struct inode *inode)
{
struct dentry *alias;
if (hlist_empty(&inode->i_dentry))
return NULL;
alias = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
__dget(alias);
return alias;
}
/**
* d_find_any_alias - find any alias for a given inode
* @inode: inode to find an alias for
*
* If any aliases exist for the given inode, take and return a
* reference for one of them. If no aliases exist, return %NULL.
*/
struct dentry *d_find_any_alias(struct inode *inode)
{
struct dentry *de;
spin_lock(&inode->i_lock);
de = __d_find_any_alias(inode);
spin_unlock(&inode->i_lock);
return de;
}
EXPORT_SYMBOL(d_find_any_alias);
static struct dentry *__d_instantiate_anon(struct dentry *dentry, static struct dentry *__d_instantiate_anon(struct dentry *dentry,
struct inode *inode, struct inode *inode,
bool disconnected) bool disconnected)
......
...@@ -314,10 +314,6 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -314,10 +314,6 @@ static int msdos_rmdir(struct inode *dir, struct dentry *dentry)
int err; int err;
mutex_lock(&MSDOS_SB(sb)->s_lock); mutex_lock(&MSDOS_SB(sb)->s_lock);
/*
* Check whether the directory is not in use, then check
* whether it is empty.
*/
err = fat_dir_empty(inode); err = fat_dir_empty(inode);
if (err) if (err)
goto out; goto out;
......
...@@ -697,15 +697,6 @@ static int vfat_find(struct inode *dir, const struct qstr *qname, ...@@ -697,15 +697,6 @@ static int vfat_find(struct inode *dir, const struct qstr *qname,
return fat_search_long(dir, qname->name, len, sinfo); return fat_search_long(dir, qname->name, len, sinfo);
} }
/*
* (nfsd's) anonymous disconnected dentry?
* NOTE: !IS_ROOT() is not anonymous (I.e. d_splice_alias() did the job).
*/
static int vfat_d_anon_disconn(struct dentry *dentry)
{
return IS_ROOT(dentry) && (dentry->d_flags & DCACHE_DISCONNECTED);
}
static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
unsigned int flags) unsigned int flags)
{ {
...@@ -738,8 +729,7 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, ...@@ -738,8 +729,7 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
* Checking "alias->d_parent == dentry->d_parent" to make sure * Checking "alias->d_parent == dentry->d_parent" to make sure
* FS is not corrupted (especially double linked dir). * FS is not corrupted (especially double linked dir).
*/ */
if (alias && alias->d_parent == dentry->d_parent && if (alias && alias->d_parent == dentry->d_parent) {
!vfat_d_anon_disconn(alias)) {
/* /*
* This inode has non anonymous-DCACHE_DISCONNECTED * This inode has non anonymous-DCACHE_DISCONNECTED
* dentry. This means, the user did ->lookup() by an * dentry. This means, the user did ->lookup() by an
...@@ -747,7 +737,6 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, ...@@ -747,7 +737,6 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
* *
* Switch to new one for reason of locality if possible. * Switch to new one for reason of locality if possible.
*/ */
BUG_ON(d_unhashed(alias));
if (!S_ISDIR(inode->i_mode)) if (!S_ISDIR(inode->i_mode))
d_move(alias, dentry); d_move(alias, dentry);
iput(inode); iput(inode);
......
...@@ -1438,10 +1438,8 @@ static int path_parent_directory(struct path *path) ...@@ -1438,10 +1438,8 @@ static int path_parent_directory(struct path *path)
static int follow_dotdot(struct nameidata *nd) static int follow_dotdot(struct nameidata *nd)
{ {
while(1) { while(1) {
if (nd->path.dentry == nd->root.dentry && if (path_equal(&nd->path, &nd->root))
nd->path.mnt == nd->root.mnt) {
break; break;
}
if (nd->path.dentry != nd->path.mnt->mnt_root) { if (nd->path.dentry != nd->path.mnt->mnt_root) {
int ret = path_parent_directory(&nd->path); int ret = path_parent_directory(&nd->path);
if (ret) if (ret)
......
...@@ -2023,7 +2023,7 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same) ...@@ -2023,7 +2023,7 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
ret = mnt_want_write_file(dst_file); ret = mnt_want_write_file(dst_file);
if (ret) { if (ret) {
info->status = ret; info->status = ret;
goto next_loop; goto next_fdput;
} }
dst_off = info->dest_offset; dst_off = info->dest_offset;
...@@ -2058,9 +2058,9 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same) ...@@ -2058,9 +2058,9 @@ int vfs_dedupe_file_range(struct file *file, struct file_dedupe_range *same)
next_file: next_file:
mnt_drop_write_file(dst_file); mnt_drop_write_file(dst_file);
next_loop: next_fdput:
fdput(dst_fd); fdput(dst_fd);
next_loop:
if (fatal_signal_pending(current)) if (fatal_signal_pending(current))
goto out; goto out;
} }
......
...@@ -947,7 +947,7 @@ void emergency_remount(void) ...@@ -947,7 +947,7 @@ void emergency_remount(void)
static void do_thaw_all_callback(struct super_block *sb) static void do_thaw_all_callback(struct super_block *sb)
{ {
down_write(&sb->s_umount); down_write(&sb->s_umount);
if (sb->s_root && sb->s_flags & MS_BORN) { if (sb->s_root && sb->s_flags & SB_BORN) {
emergency_thaw_bdev(sb); emergency_thaw_bdev(sb);
thaw_super_locked(sb); thaw_super_locked(sb);
} else { } else {
......
...@@ -229,7 +229,7 @@ vfs_setxattr(struct dentry *dentry, const char *name, const void *value, ...@@ -229,7 +229,7 @@ vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
} }
EXPORT_SYMBOL_GPL(vfs_setxattr); EXPORT_SYMBOL_GPL(vfs_setxattr);
ssize_t static ssize_t
xattr_getsecurity(struct inode *inode, const char *name, void *value, xattr_getsecurity(struct inode *inode, const char *name, void *value,
size_t size) size_t size)
{ {
...@@ -254,7 +254,6 @@ xattr_getsecurity(struct inode *inode, const char *name, void *value, ...@@ -254,7 +254,6 @@ xattr_getsecurity(struct inode *inode, const char *name, void *value,
out_noalloc: out_noalloc:
return len; return len;
} }
EXPORT_SYMBOL_GPL(xattr_getsecurity);
/* /*
* vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr * vfs_getxattr_alloc - allocate memory, if necessary, before calling getxattr
...@@ -354,7 +353,6 @@ vfs_listxattr(struct dentry *dentry, char *list, size_t size) ...@@ -354,7 +353,6 @@ vfs_listxattr(struct dentry *dentry, char *list, size_t size)
if (error) if (error)
return error; return error;
if (inode->i_op->listxattr && (inode->i_opflags & IOP_XATTR)) { if (inode->i_op->listxattr && (inode->i_opflags & IOP_XATTR)) {
error = -EOPNOTSUPP;
error = inode->i_op->listxattr(dentry, list, size); error = inode->i_op->listxattr(dentry, list, size);
} else { } else {
error = security_inode_listsecurity(inode, list, size); error = security_inode_listsecurity(inode, list, size);
......
...@@ -94,7 +94,7 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset, ...@@ -94,7 +94,7 @@ typedef int (dio_iodone_t)(struct kiocb *iocb, loff_t offset,
/* /*
* flags in file.f_mode. Note that FMODE_READ and FMODE_WRITE must correspond * flags in file.f_mode. Note that FMODE_READ and FMODE_WRITE must correspond
* to O_WRONLY and O_RDWR via the strange trick in __dentry_open() * to O_WRONLY and O_RDWR via the strange trick in do_dentry_open()
*/ */
/* file is open for reading */ /* file is open for reading */
......
...@@ -122,8 +122,6 @@ extern struct dentry *rpc_create_cache_dir(struct dentry *, ...@@ -122,8 +122,6 @@ extern struct dentry *rpc_create_cache_dir(struct dentry *,
struct cache_detail *); struct cache_detail *);
extern void rpc_remove_cache_dir(struct dentry *); extern void rpc_remove_cache_dir(struct dentry *);
extern int rpc_rmdir(struct dentry *dentry);
struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags); struct rpc_pipe *rpc_mkpipe_data(const struct rpc_pipe_ops *ops, int flags);
void rpc_destroy_pipe_data(struct rpc_pipe *pipe); void rpc_destroy_pipe_data(struct rpc_pipe *pipe);
extern struct dentry *rpc_mkpipe_dentry(struct dentry *, const char *, void *, extern struct dentry *rpc_mkpipe_dentry(struct dentry *, const char *, void *,
......
...@@ -46,7 +46,6 @@ struct xattr { ...@@ -46,7 +46,6 @@ struct xattr {
size_t value_len; size_t value_len;
}; };
ssize_t xattr_getsecurity(struct inode *, const char *, void *, size_t);
ssize_t __vfs_getxattr(struct dentry *, struct inode *, const char *, void *, size_t); ssize_t __vfs_getxattr(struct dentry *, struct inode *, const char *, void *, size_t);
ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t); ssize_t vfs_getxattr(struct dentry *, const char *, void *, size_t);
ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size); ssize_t vfs_listxattr(struct dentry *d, char *list, size_t size);
......
...@@ -609,22 +609,6 @@ static int __rpc_rmdir(struct inode *dir, struct dentry *dentry) ...@@ -609,22 +609,6 @@ static int __rpc_rmdir(struct inode *dir, struct dentry *dentry)
return ret; return ret;
} }
int rpc_rmdir(struct dentry *dentry)
{
struct dentry *parent;
struct inode *dir;
int error;
parent = dget_parent(dentry);
dir = d_inode(parent);
inode_lock_nested(dir, I_MUTEX_PARENT);
error = __rpc_rmdir(dir, dentry);
inode_unlock(dir);
dput(parent);
return error;
}
EXPORT_SYMBOL_GPL(rpc_rmdir);
static int __rpc_unlink(struct inode *dir, struct dentry *dentry) static int __rpc_unlink(struct inode *dir, struct dentry *dentry)
{ {
int ret; int ret;
......
...@@ -274,11 +274,10 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent ...@@ -274,11 +274,10 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
* Try reloading inode security labels that have been marked as invalid. The * Try reloading inode security labels that have been marked as invalid. The
* @may_sleep parameter indicates when sleeping and thus reloading labels is * @may_sleep parameter indicates when sleeping and thus reloading labels is
* allowed; when set to false, returns -ECHILD when the label is * allowed; when set to false, returns -ECHILD when the label is
* invalid. The @opt_dentry parameter should be set to a dentry of the inode; * invalid. The @dentry parameter should be set to a dentry of the inode.
* when no dentry is available, set it to NULL instead.
*/ */
static int __inode_security_revalidate(struct inode *inode, static int __inode_security_revalidate(struct inode *inode,
struct dentry *opt_dentry, struct dentry *dentry,
bool may_sleep) bool may_sleep)
{ {
struct inode_security_struct *isec = inode->i_security; struct inode_security_struct *isec = inode->i_security;
...@@ -295,7 +294,7 @@ static int __inode_security_revalidate(struct inode *inode, ...@@ -295,7 +294,7 @@ static int __inode_security_revalidate(struct inode *inode,
* @opt_dentry is NULL and no dentry for this inode can be * @opt_dentry is NULL and no dentry for this inode can be
* found; in that case, continue using the old label. * found; in that case, continue using the old label.
*/ */
inode_doinit_with_dentry(inode, opt_dentry); inode_doinit_with_dentry(inode, dentry);
} }
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment