Merge branch 'vfs-scale-working' of git://git.kernel.org/pub/scm/linux/kernel/git/npiggin/linux-npiggin
* 'vfs-scale-working' of git://git.kernel.org/pub/scm/linux/kernel/git/npiggin/linux-npiggin: fs: fix do_last error case when need_reval_dot nfs: add missing rcu-walk check fs: hlist UP debug fixup fs: fix dropping of rcu-walk from force_reval_path fs: force_reval_path drop rcu-walk before d_invalidate fs: small rcu-walk documentation fixes Fixed up trivial conflicts in Documentation/filesystems/porting
This commit is contained in:
Коммит
db9effe99a
|
@ -365,8 +365,8 @@ must be done in the RCU callback.
|
|||
[recommended]
|
||||
vfs now tries to do path walking in "rcu-walk mode", which avoids
|
||||
atomic operations and scalability hazards on dentries and inodes (see
|
||||
Documentation/filesystems/path-walk.txt). d_hash and d_compare changes (above)
|
||||
are examples of the changes required to support this. For more complex
|
||||
Documentation/filesystems/path-lookup.txt). d_hash and d_compare changes
|
||||
(above) are examples of the changes required to support this. For more complex
|
||||
filesystem callbacks, the vfs drops out of rcu-walk mode before the fs call, so
|
||||
no changes are required to the filesystem. However, this is costly and loses
|
||||
the benefits of rcu-walk mode. We will begin to add filesystem callbacks that
|
||||
|
@ -383,8 +383,8 @@ Documentation/filesystems/vfs.txt for more details.
|
|||
|
||||
permission and check_acl are inode permission checks that are called
|
||||
on many or all directory inodes on the way down a path walk (to check for
|
||||
exec permission). These must now be rcu-walk aware (flags & IPERM_RCU). See
|
||||
Documentation/filesystems/vfs.txt for more details.
|
||||
exec permission). These must now be rcu-walk aware (flags & IPERM_FLAG_RCU).
|
||||
See Documentation/filesystems/vfs.txt for more details.
|
||||
|
||||
--
|
||||
[mandatory]
|
||||
|
|
|
@ -415,8 +415,8 @@ otherwise noted.
|
|||
permission: called by the VFS to check for access rights on a POSIX-like
|
||||
filesystem.
|
||||
|
||||
May be called in rcu-walk mode (flags & IPERM_RCU). If in rcu-walk
|
||||
mode, the filesystem must check the permission without blocking or
|
||||
May be called in rcu-walk mode (flags & IPERM_FLAG_RCU). If in rcu-walk
|
||||
mode, the filesystem must check the permission without blocking or
|
||||
storing to the inode.
|
||||
|
||||
If a situation is encountered that rcu-walk cannot handle, return
|
||||
|
|
28
fs/namei.c
28
fs/namei.c
|
@ -479,6 +479,14 @@ static int nameidata_dentry_drop_rcu(struct nameidata *nd, struct dentry *dentry
|
|||
struct fs_struct *fs = current->fs;
|
||||
struct dentry *parent = nd->path.dentry;
|
||||
|
||||
/*
|
||||
* It can be possible to revalidate the dentry that we started
|
||||
* the path walk with. force_reval_path may also revalidate the
|
||||
* dentry already committed to the nameidata.
|
||||
*/
|
||||
if (unlikely(parent == dentry))
|
||||
return nameidata_drop_rcu(nd);
|
||||
|
||||
BUG_ON(!(nd->flags & LOOKUP_RCU));
|
||||
if (nd->root.mnt) {
|
||||
spin_lock(&fs->lock);
|
||||
|
@ -583,6 +591,13 @@ void release_open_intent(struct nameidata *nd)
|
|||
fput(nd->intent.open.file);
|
||||
}
|
||||
|
||||
/*
|
||||
* Call d_revalidate and handle filesystems that request rcu-walk
|
||||
* to be dropped. This may be called and return in rcu-walk mode,
|
||||
* regardless of success or error. If -ECHILD is returned, the caller
|
||||
* must return -ECHILD back up the path walk stack so path walk may
|
||||
* be restarted in ref-walk mode.
|
||||
*/
|
||||
static int d_revalidate(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
int status;
|
||||
|
@ -673,6 +688,9 @@ force_reval_path(struct path *path, struct nameidata *nd)
|
|||
return 0;
|
||||
|
||||
if (!status) {
|
||||
/* Don't d_invalidate in rcu-walk mode */
|
||||
if (nameidata_drop_rcu(nd))
|
||||
return -ECHILD;
|
||||
d_invalidate(dentry);
|
||||
status = -ESTALE;
|
||||
}
|
||||
|
@ -2105,11 +2123,13 @@ static struct file *do_last(struct nameidata *nd, struct path *path,
|
|||
dir = nd->path.dentry;
|
||||
case LAST_DOT:
|
||||
if (need_reval_dot(dir)) {
|
||||
error = d_revalidate(nd->path.dentry, nd);
|
||||
if (!error)
|
||||
error = -ESTALE;
|
||||
if (error < 0)
|
||||
int status = d_revalidate(nd->path.dentry, nd);
|
||||
if (!status)
|
||||
status = -ESTALE;
|
||||
if (status < 0) {
|
||||
error = status;
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
/* fallthrough */
|
||||
case LAST_ROOT:
|
||||
|
|
|
@ -1406,11 +1406,15 @@ no_open:
|
|||
static int nfs_open_revalidate(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
struct dentry *parent = NULL;
|
||||
struct inode *inode = dentry->d_inode;
|
||||
struct inode *inode;
|
||||
struct inode *dir;
|
||||
struct nfs_open_context *ctx;
|
||||
int openflags, ret = 0;
|
||||
|
||||
if (nd->flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
inode = dentry->d_inode;
|
||||
if (!is_atomic_open(nd) || d_mountpoint(dentry))
|
||||
goto no_open;
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
* some fast and compact auxiliary data.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK)
|
||||
#if defined(CONFIG_SMP)
|
||||
#define LIST_BL_LOCKMASK 1UL
|
||||
#else
|
||||
#define LIST_BL_LOCKMASK 0UL
|
||||
|
@ -62,7 +62,8 @@ static inline void hlist_bl_set_first(struct hlist_bl_head *h,
|
|||
struct hlist_bl_node *n)
|
||||
{
|
||||
LIST_BL_BUG_ON((unsigned long)n & LIST_BL_LOCKMASK);
|
||||
LIST_BL_BUG_ON(!((unsigned long)h->first & LIST_BL_LOCKMASK));
|
||||
LIST_BL_BUG_ON(((unsigned long)h->first & LIST_BL_LOCKMASK) !=
|
||||
LIST_BL_LOCKMASK);
|
||||
h->first = (struct hlist_bl_node *)((unsigned long)n | LIST_BL_LOCKMASK);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,8 @@ static inline void hlist_bl_set_first_rcu(struct hlist_bl_head *h,
|
|||
struct hlist_bl_node *n)
|
||||
{
|
||||
LIST_BL_BUG_ON((unsigned long)n & LIST_BL_LOCKMASK);
|
||||
LIST_BL_BUG_ON(!((unsigned long)h->first & LIST_BL_LOCKMASK));
|
||||
LIST_BL_BUG_ON(((unsigned long)h->first & LIST_BL_LOCKMASK) !=
|
||||
LIST_BL_LOCKMASK);
|
||||
rcu_assign_pointer(h->first,
|
||||
(struct hlist_bl_node *)((unsigned long)n | LIST_BL_LOCKMASK));
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче