Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
9763f7a4
Commit
9763f7a4
authored
Dec 16, 2016
by
Al Viro
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'work.autofs' into for-linus
Signed-off-by:
Al Viro
<
viro@zeniv.linux.org.uk
>
parents
3c55d6bc
1c4344a5
Changes
13
Hide whitespace changes
Inline
Side-by-side
Showing
13 changed files
with
131 additions
and
75 deletions
+131
-75
Documentation/filesystems/Locking
Documentation/filesystems/Locking
+1
-1
Documentation/filesystems/vfs.txt
Documentation/filesystems/vfs.txt
+1
-1
fs/autofs4/autofs_i.h
fs/autofs4/autofs_i.h
+3
-2
fs/autofs4/dev-ioctl.c
fs/autofs4/dev-ioctl.c
+2
-2
fs/autofs4/expire.c
fs/autofs4/expire.c
+15
-10
fs/autofs4/root.c
fs/autofs4/root.c
+32
-29
fs/autofs4/waitq.c
fs/autofs4/waitq.c
+9
-4
fs/dcache.c
fs/dcache.c
+23
-17
fs/mount.h
fs/mount.h
+6
-0
fs/namei.c
fs/namei.c
+6
-7
fs/namespace.c
fs/namespace.c
+29
-0
include/linux/dcache.h
include/linux/dcache.h
+2
-2
include/linux/mount.h
include/linux/mount.h
+2
-0
No files found.
Documentation/filesystems/Locking
View file @
9763f7a4
...
@@ -20,7 +20,7 @@ prototypes:
...
@@ -20,7 +20,7 @@ prototypes:
void (*d_iput)(struct dentry *, struct inode *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
struct vfsmount *(*d_automount)(struct path *path);
struct vfsmount *(*d_automount)(struct path *path);
int (*d_manage)(
struct dentry
*, bool);
int (*d_manage)(
const struct path
*, bool);
struct dentry *(*d_real)(struct dentry *, const struct inode *,
struct dentry *(*d_real)(struct dentry *, const struct inode *,
unsigned int);
unsigned int);
...
...
Documentation/filesystems/vfs.txt
View file @
9763f7a4
...
@@ -948,7 +948,7 @@ struct dentry_operations {
...
@@ -948,7 +948,7 @@ struct dentry_operations {
void (*d_iput)(struct dentry *, struct inode *);
void (*d_iput)(struct dentry *, struct inode *);
char *(*d_dname)(struct dentry *, char *, int);
char *(*d_dname)(struct dentry *, char *, int);
struct vfsmount *(*d_automount)(struct path *);
struct vfsmount *(*d_automount)(struct path *);
int (*d_manage)(
struct dentry
*, bool);
int (*d_manage)(
const struct path
*, bool);
struct dentry *(*d_real)(struct dentry *, const struct inode *,
struct dentry *(*d_real)(struct dentry *, const struct inode *,
unsigned int);
unsigned int);
};
};
...
...
fs/autofs4/autofs_i.h
View file @
9763f7a4
...
@@ -145,7 +145,7 @@ void autofs4_free_ino(struct autofs_info *);
...
@@ -145,7 +145,7 @@ void autofs4_free_ino(struct autofs_info *);
/* Expiration */
/* Expiration */
int
is_autofs4_dentry
(
struct
dentry
*
);
int
is_autofs4_dentry
(
struct
dentry
*
);
int
autofs4_expire_wait
(
struct
dentry
*
dentry
,
int
rcu_walk
);
int
autofs4_expire_wait
(
const
struct
path
*
path
,
int
rcu_walk
);
int
autofs4_expire_run
(
struct
super_block
*
,
struct
vfsmount
*
,
int
autofs4_expire_run
(
struct
super_block
*
,
struct
vfsmount
*
,
struct
autofs_sb_info
*
,
struct
autofs_sb_info
*
,
struct
autofs_packet_expire
__user
*
);
struct
autofs_packet_expire
__user
*
);
...
@@ -217,7 +217,8 @@ static inline int autofs_prepare_pipe(struct file *pipe)
...
@@ -217,7 +217,8 @@ static inline int autofs_prepare_pipe(struct file *pipe)
/* Queue management functions */
/* Queue management functions */
int
autofs4_wait
(
struct
autofs_sb_info
*
,
struct
dentry
*
,
enum
autofs_notify
);
int
autofs4_wait
(
struct
autofs_sb_info
*
,
const
struct
path
*
,
enum
autofs_notify
);
int
autofs4_wait_release
(
struct
autofs_sb_info
*
,
autofs_wqt_t
,
int
);
int
autofs4_wait_release
(
struct
autofs_sb_info
*
,
autofs_wqt_t
,
int
);
void
autofs4_catatonic_mode
(
struct
autofs_sb_info
*
);
void
autofs4_catatonic_mode
(
struct
autofs_sb_info
*
);
...
...
fs/autofs4/dev-ioctl.c
View file @
9763f7a4
...
@@ -468,7 +468,7 @@ static int autofs_dev_ioctl_requester(struct file *fp,
...
@@ -468,7 +468,7 @@ static int autofs_dev_ioctl_requester(struct file *fp,
ino
=
autofs4_dentry_ino
(
path
.
dentry
);
ino
=
autofs4_dentry_ino
(
path
.
dentry
);
if
(
ino
)
{
if
(
ino
)
{
err
=
0
;
err
=
0
;
autofs4_expire_wait
(
path
.
dentry
,
0
);
autofs4_expire_wait
(
&
path
,
0
);
spin_lock
(
&
sbi
->
fs_lock
);
spin_lock
(
&
sbi
->
fs_lock
);
param
->
requester
.
uid
=
param
->
requester
.
uid
=
from_kuid_munged
(
current_user_ns
(),
ino
->
uid
);
from_kuid_munged
(
current_user_ns
(),
ino
->
uid
);
...
@@ -575,7 +575,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
...
@@ -575,7 +575,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
devid
=
new_encode_dev
(
dev
);
devid
=
new_encode_dev
(
dev
);
err
=
have_submounts
(
path
.
dentry
);
err
=
path_has_submounts
(
&
path
);
if
(
follow_down_one
(
&
path
))
if
(
follow_down_one
(
&
path
))
magic
=
path
.
dentry
->
d_sb
->
s_magic
;
magic
=
path
.
dentry
->
d_sb
->
s_magic
;
...
...
fs/autofs4/expire.c
View file @
9763f7a4
...
@@ -310,26 +310,29 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
...
@@ -310,26 +310,29 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
now
=
jiffies
;
now
=
jiffies
;
timeout
=
sbi
->
exp_timeout
;
timeout
=
sbi
->
exp_timeout
;
spin_lock
(
&
sbi
->
fs_lock
);
ino
=
autofs4_dentry_ino
(
root
);
/* No point expiring a pending mount */
if
(
ino
->
flags
&
AUTOFS_INF_PENDING
)
goto
out
;
if
(
!
autofs4_direct_busy
(
mnt
,
root
,
timeout
,
do_now
))
{
if
(
!
autofs4_direct_busy
(
mnt
,
root
,
timeout
,
do_now
))
{
spin_lock
(
&
sbi
->
fs_lock
);
ino
=
autofs4_dentry_ino
(
root
);
/* No point expiring a pending mount */
if
(
ino
->
flags
&
AUTOFS_INF_PENDING
)
{
spin_unlock
(
&
sbi
->
fs_lock
);
goto
out
;
}
ino
->
flags
|=
AUTOFS_INF_WANT_EXPIRE
;
ino
->
flags
|=
AUTOFS_INF_WANT_EXPIRE
;
spin_unlock
(
&
sbi
->
fs_lock
);
spin_unlock
(
&
sbi
->
fs_lock
);
synchronize_rcu
();
synchronize_rcu
();
spin_lock
(
&
sbi
->
fs_lock
);
if
(
!
autofs4_direct_busy
(
mnt
,
root
,
timeout
,
do_now
))
{
if
(
!
autofs4_direct_busy
(
mnt
,
root
,
timeout
,
do_now
))
{
spin_lock
(
&
sbi
->
fs_lock
);
ino
->
flags
|=
AUTOFS_INF_EXPIRING
;
ino
->
flags
|=
AUTOFS_INF_EXPIRING
;
init_completion
(
&
ino
->
expire_complete
);
init_completion
(
&
ino
->
expire_complete
);
spin_unlock
(
&
sbi
->
fs_lock
);
spin_unlock
(
&
sbi
->
fs_lock
);
return
root
;
return
root
;
}
}
spin_lock
(
&
sbi
->
fs_lock
);
ino
->
flags
&=
~
AUTOFS_INF_WANT_EXPIRE
;
ino
->
flags
&=
~
AUTOFS_INF_WANT_EXPIRE
;
spin_unlock
(
&
sbi
->
fs_lock
);
}
}
out:
out:
spin_unlock
(
&
sbi
->
fs_lock
);
dput
(
root
);
dput
(
root
);
return
NULL
;
return
NULL
;
...
@@ -495,8 +498,9 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
...
@@ -495,8 +498,9 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
return
expired
;
return
expired
;
}
}
int
autofs4_expire_wait
(
struct
dentry
*
dentry
,
int
rcu_walk
)
int
autofs4_expire_wait
(
const
struct
path
*
path
,
int
rcu_walk
)
{
{
struct
dentry
*
dentry
=
path
->
dentry
;
struct
autofs_sb_info
*
sbi
=
autofs4_sbi
(
dentry
->
d_sb
);
struct
autofs_sb_info
*
sbi
=
autofs4_sbi
(
dentry
->
d_sb
);
struct
autofs_info
*
ino
=
autofs4_dentry_ino
(
dentry
);
struct
autofs_info
*
ino
=
autofs4_dentry_ino
(
dentry
);
int
status
;
int
status
;
...
@@ -525,7 +529,7 @@ int autofs4_expire_wait(struct dentry *dentry, int rcu_walk)
...
@@ -525,7 +529,7 @@ int autofs4_expire_wait(struct dentry *dentry, int rcu_walk)
pr_debug
(
"waiting for expire %p name=%pd
\n
"
,
dentry
,
dentry
);
pr_debug
(
"waiting for expire %p name=%pd
\n
"
,
dentry
,
dentry
);
status
=
autofs4_wait
(
sbi
,
dentry
,
NFY_NONE
);
status
=
autofs4_wait
(
sbi
,
path
,
NFY_NONE
);
wait_for_completion
(
&
ino
->
expire_complete
);
wait_for_completion
(
&
ino
->
expire_complete
);
pr_debug
(
"expire done status=%d
\n
"
,
status
);
pr_debug
(
"expire done status=%d
\n
"
,
status
);
...
@@ -592,11 +596,12 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
...
@@ -592,11 +596,12 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
if
(
dentry
)
{
if
(
dentry
)
{
struct
autofs_info
*
ino
=
autofs4_dentry_ino
(
dentry
);
struct
autofs_info
*
ino
=
autofs4_dentry_ino
(
dentry
);
const
struct
path
path
=
{
.
mnt
=
mnt
,
.
dentry
=
dentry
};
/* This is synchronous because it makes the daemon a
/* This is synchronous because it makes the daemon a
* little easier
* little easier
*/
*/
ret
=
autofs4_wait
(
sbi
,
dentry
,
NFY_EXPIRE
);
ret
=
autofs4_wait
(
sbi
,
&
path
,
NFY_EXPIRE
);
spin_lock
(
&
sbi
->
fs_lock
);
spin_lock
(
&
sbi
->
fs_lock
);
/* avoid rapid-fire expire attempts if expiry fails */
/* avoid rapid-fire expire attempts if expiry fails */
...
...
fs/autofs4/root.c
View file @
9763f7a4
...
@@ -32,7 +32,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file);
...
@@ -32,7 +32,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file);
static
struct
dentry
*
autofs4_lookup
(
struct
inode
*
,
static
struct
dentry
*
autofs4_lookup
(
struct
inode
*
,
struct
dentry
*
,
unsigned
int
);
struct
dentry
*
,
unsigned
int
);
static
struct
vfsmount
*
autofs4_d_automount
(
struct
path
*
);
static
struct
vfsmount
*
autofs4_d_automount
(
struct
path
*
);
static
int
autofs4_d_manage
(
struct
dentry
*
,
bool
);
static
int
autofs4_d_manage
(
const
struct
path
*
,
bool
);
static
void
autofs4_dentry_release
(
struct
dentry
*
);
static
void
autofs4_dentry_release
(
struct
dentry
*
);
const
struct
file_operations
autofs4_root_operations
=
{
const
struct
file_operations
autofs4_root_operations
=
{
...
@@ -123,7 +123,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
...
@@ -123,7 +123,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
* it.
* it.
*/
*/
spin_lock
(
&
sbi
->
lookup_lock
);
spin_lock
(
&
sbi
->
lookup_lock
);
if
(
!
d_mountpoint
(
dentry
)
&&
simple_empty
(
dentry
))
{
if
(
!
path_is_mountpoint
(
&
file
->
f_path
)
&&
simple_empty
(
dentry
))
{
spin_unlock
(
&
sbi
->
lookup_lock
);
spin_unlock
(
&
sbi
->
lookup_lock
);
return
-
ENOENT
;
return
-
ENOENT
;
}
}
...
@@ -269,39 +269,41 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry,
...
@@ -269,39 +269,41 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry,
return
NULL
;
return
NULL
;
}
}
static
int
autofs4_mount_wait
(
struct
dentry
*
dentry
,
bool
rcu_walk
)
static
int
autofs4_mount_wait
(
const
struct
path
*
path
,
bool
rcu_walk
)
{
{
struct
autofs_sb_info
*
sbi
=
autofs4_sbi
(
dentry
->
d_sb
);
struct
autofs_sb_info
*
sbi
=
autofs4_sbi
(
path
->
dentry
->
d_sb
);
struct
autofs_info
*
ino
=
autofs4_dentry_ino
(
dentry
);
struct
autofs_info
*
ino
=
autofs4_dentry_ino
(
path
->
dentry
);
int
status
=
0
;
int
status
=
0
;
if
(
ino
->
flags
&
AUTOFS_INF_PENDING
)
{
if
(
ino
->
flags
&
AUTOFS_INF_PENDING
)
{
if
(
rcu_walk
)
if
(
rcu_walk
)
return
-
ECHILD
;
return
-
ECHILD
;
pr_debug
(
"waiting for mount name=%pd
\n
"
,
dentry
);
pr_debug
(
"waiting for mount name=%pd
\n
"
,
path
->
dentry
);
status
=
autofs4_wait
(
sbi
,
dentry
,
NFY_MOUNT
);
status
=
autofs4_wait
(
sbi
,
path
,
NFY_MOUNT
);
pr_debug
(
"mount wait done status=%d
\n
"
,
status
);
pr_debug
(
"mount wait done status=%d
\n
"
,
status
);
}
}
ino
->
last_used
=
jiffies
;
ino
->
last_used
=
jiffies
;
return
status
;
return
status
;
}
}
static
int
do_expire_wait
(
struct
dentry
*
dentry
,
bool
rcu_walk
)
static
int
do_expire_wait
(
const
struct
path
*
path
,
bool
rcu_walk
)
{
{
struct
dentry
*
dentry
=
path
->
dentry
;
struct
dentry
*
expiring
;
struct
dentry
*
expiring
;
expiring
=
autofs4_lookup_expiring
(
dentry
,
rcu_walk
);
expiring
=
autofs4_lookup_expiring
(
dentry
,
rcu_walk
);
if
(
IS_ERR
(
expiring
))
if
(
IS_ERR
(
expiring
))
return
PTR_ERR
(
expiring
);
return
PTR_ERR
(
expiring
);
if
(
!
expiring
)
if
(
!
expiring
)
return
autofs4_expire_wait
(
dentry
,
rcu_walk
);
return
autofs4_expire_wait
(
path
,
rcu_walk
);
else
{
else
{
const
struct
path
this
=
{
.
mnt
=
path
->
mnt
,
.
dentry
=
expiring
};
/*
/*
* If we are racing with expire the request might not
* If we are racing with expire the request might not
* be quite complete, but the directory has been removed
* be quite complete, but the directory has been removed
* so it must have been successful, just wait for it.
* so it must have been successful, just wait for it.
*/
*/
autofs4_expire_wait
(
expiring
,
0
);
autofs4_expire_wait
(
&
this
,
0
);
autofs4_del_expiring
(
expiring
);
autofs4_del_expiring
(
expiring
);
dput
(
expiring
);
dput
(
expiring
);
}
}
...
@@ -354,7 +356,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
...
@@ -354,7 +356,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
* and the directory was removed, so just go ahead and try
* and the directory was removed, so just go ahead and try
* the mount.
* the mount.
*/
*/
status
=
do_expire_wait
(
dentry
,
0
);
status
=
do_expire_wait
(
path
,
0
);
if
(
status
&&
status
!=
-
EAGAIN
)
if
(
status
&&
status
!=
-
EAGAIN
)
return
NULL
;
return
NULL
;
...
@@ -362,7 +364,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
...
@@ -362,7 +364,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
spin_lock
(
&
sbi
->
fs_lock
);
spin_lock
(
&
sbi
->
fs_lock
);
if
(
ino
->
flags
&
AUTOFS_INF_PENDING
)
{
if
(
ino
->
flags
&
AUTOFS_INF_PENDING
)
{
spin_unlock
(
&
sbi
->
fs_lock
);
spin_unlock
(
&
sbi
->
fs_lock
);
status
=
autofs4_mount_wait
(
dentry
,
0
);
status
=
autofs4_mount_wait
(
path
,
0
);
if
(
status
)
if
(
status
)
return
ERR_PTR
(
status
);
return
ERR_PTR
(
status
);
goto
done
;
goto
done
;
...
@@ -370,28 +372,28 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
...
@@ -370,28 +372,28 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
/*
/*
* If the dentry is a symlink it's equivalent to a directory
* If the dentry is a symlink it's equivalent to a directory
* having
d_mountpoint() true, so there's no need to call back
* having
path_is_mountpoint() true, so there's no need to call
* to the daemon.
*
back
to the daemon.
*/
*/
if
(
d_really_is_positive
(
dentry
)
&&
d_is_symlink
(
dentry
))
{
if
(
d_really_is_positive
(
dentry
)
&&
d_is_symlink
(
dentry
))
{
spin_unlock
(
&
sbi
->
fs_lock
);
spin_unlock
(
&
sbi
->
fs_lock
);
goto
done
;
goto
done
;
}
}
if
(
!
d_mountpoint
(
dentry
))
{
if
(
!
path_is_mountpoint
(
path
))
{
/*
/*
* It's possible that user space hasn't removed directories
* It's possible that user space hasn't removed directories
* after umounting a rootless multi-mount, although it
* after umounting a rootless multi-mount, although it
* should. For v5
have_submounts() is sufficient to handle
* should. For v5
path_has_submounts() is sufficient to
*
this because the leaves of the directory tree under the
*
handle this because the leaves of the directory tree under
*
mount never trigger mounts themselves (they have an autofs
*
the mount never trigger mounts themselves (they have an
*
trigger mount mounted on them). But v4 pseudo direct mounts
*
autofs trigger mount mounted on them). But v4 pseudo direct
*
do need the leaves to trigger mounts. In this case w
e
*
mounts do need the leaves to trigger mounts. In this cas
e
* have no choice but to use the list_empty() check and
*
we
have no choice but to use the list_empty() check and
* require user space behave.
* require user space behave.
*/
*/
if
(
sbi
->
version
>
4
)
{
if
(
sbi
->
version
>
4
)
{
if
(
have_submounts
(
dentry
))
{
if
(
path_has_submounts
(
path
))
{
spin_unlock
(
&
sbi
->
fs_lock
);
spin_unlock
(
&
sbi
->
fs_lock
);
goto
done
;
goto
done
;
}
}
...
@@ -403,7 +405,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
...
@@ -403,7 +405,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
}
}
ino
->
flags
|=
AUTOFS_INF_PENDING
;
ino
->
flags
|=
AUTOFS_INF_PENDING
;
spin_unlock
(
&
sbi
->
fs_lock
);
spin_unlock
(
&
sbi
->
fs_lock
);
status
=
autofs4_mount_wait
(
dentry
,
0
);
status
=
autofs4_mount_wait
(
path
,
0
);
spin_lock
(
&
sbi
->
fs_lock
);
spin_lock
(
&
sbi
->
fs_lock
);
ino
->
flags
&=
~
AUTOFS_INF_PENDING
;
ino
->
flags
&=
~
AUTOFS_INF_PENDING
;
if
(
status
)
{
if
(
status
)
{
...
@@ -421,8 +423,9 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
...
@@ -421,8 +423,9 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
return
NULL
;
return
NULL
;
}
}
static
int
autofs4_d_manage
(
struct
dentry
*
dentry
,
bool
rcu_walk
)
static
int
autofs4_d_manage
(
const
struct
path
*
path
,
bool
rcu_walk
)
{
{
struct
dentry
*
dentry
=
path
->
dentry
;
struct
autofs_sb_info
*
sbi
=
autofs4_sbi
(
dentry
->
d_sb
);
struct
autofs_sb_info
*
sbi
=
autofs4_sbi
(
dentry
->
d_sb
);
struct
autofs_info
*
ino
=
autofs4_dentry_ino
(
dentry
);
struct
autofs_info
*
ino
=
autofs4_dentry_ino
(
dentry
);
int
status
;
int
status
;
...
@@ -431,20 +434,20 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
...
@@ -431,20 +434,20 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
/* The daemon never waits. */
/* The daemon never waits. */
if
(
autofs4_oz_mode
(
sbi
))
{
if
(
autofs4_oz_mode
(
sbi
))
{
if
(
!
d_mountpoint
(
dentry
))
if
(
!
path_is_mountpoint
(
path
))
return
-
EISDIR
;
return
-
EISDIR
;
return
0
;
return
0
;
}
}
/* Wait for pending expires */
/* Wait for pending expires */
if
(
do_expire_wait
(
dentry
,
rcu_walk
)
==
-
ECHILD
)
if
(
do_expire_wait
(
path
,
rcu_walk
)
==
-
ECHILD
)
return
-
ECHILD
;
return
-
ECHILD
;
/*
/*
* This dentry may be under construction so wait on mount
* This dentry may be under construction so wait on mount
* completion.
* completion.
*/
*/
status
=
autofs4_mount_wait
(
dentry
,
rcu_walk
);
status
=
autofs4_mount_wait
(
path
,
rcu_walk
);
if
(
status
)
if
(
status
)
return
status
;
return
status
;
...
@@ -460,7 +463,7 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
...
@@ -460,7 +463,7 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
if
(
ino
->
flags
&
AUTOFS_INF_WANT_EXPIRE
)
if
(
ino
->
flags
&
AUTOFS_INF_WANT_EXPIRE
)
return
0
;
return
0
;
if
(
d_mountpoint
(
dentry
))
if
(
path_is_mountpoint
(
path
))
return
0
;
return
0
;
inode
=
d_inode_rcu
(
dentry
);
inode
=
d_inode_rcu
(
dentry
);
if
(
inode
&&
S_ISLNK
(
inode
->
i_mode
))
if
(
inode
&&
S_ISLNK
(
inode
->
i_mode
))
...
@@ -487,7 +490,7 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
...
@@ -487,7 +490,7 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
* we can avoid needless calls ->d_automount() and avoid
* we can avoid needless calls ->d_automount() and avoid
* an incorrect ELOOP error return.
* an incorrect ELOOP error return.
*/
*/
if
((
!
d_mountpoint
(
dentry
)
&&
!
simple_empty
(
dentry
))
||
if
((
!
path_is_mountpoint
(
path
)
&&
!
simple_empty
(
dentry
))
||
(
d_really_is_positive
(
dentry
)
&&
d_is_symlink
(
dentry
)))
(
d_really_is_positive
(
dentry
)
&&
d_is_symlink
(
dentry
)))
status
=
-
EISDIR
;
status
=
-
EISDIR
;
}
}
...
...
fs/autofs4/waitq.c
View file @
9763f7a4
...
@@ -250,8 +250,9 @@ autofs4_find_wait(struct autofs_sb_info *sbi, const struct qstr *qstr)
...
@@ -250,8 +250,9 @@ autofs4_find_wait(struct autofs_sb_info *sbi, const struct qstr *qstr)
static
int
validate_request
(
struct
autofs_wait_queue
**
wait
,
static
int
validate_request
(
struct
autofs_wait_queue
**
wait
,
struct
autofs_sb_info
*
sbi
,
struct
autofs_sb_info
*
sbi
,
const
struct
qstr
*
qstr
,
const
struct
qstr
*
qstr
,
struct
dentry
*
dentry
,
enum
autofs_notify
notify
)
const
struct
path
*
path
,
enum
autofs_notify
notify
)
{
{
struct
dentry
*
dentry
=
path
->
dentry
;
struct
autofs_wait_queue
*
wq
;
struct
autofs_wait_queue
*
wq
;
struct
autofs_info
*
ino
;
struct
autofs_info
*
ino
;
...
@@ -314,6 +315,7 @@ static int validate_request(struct autofs_wait_queue **wait,
...
@@ -314,6 +315,7 @@ static int validate_request(struct autofs_wait_queue **wait,
*/
*/
if
(
notify
==
NFY_MOUNT
)
{
if
(
notify
==
NFY_MOUNT
)
{
struct
dentry
*
new
=
NULL
;
struct
dentry
*
new
=
NULL
;
struct
path
this
;
int
valid
=
1
;
int
valid
=
1
;
/*
/*
...
@@ -333,7 +335,9 @@ static int validate_request(struct autofs_wait_queue **wait,
...
@@ -333,7 +335,9 @@ static int validate_request(struct autofs_wait_queue **wait,
dentry
=
new
;
dentry
=
new
;
}
}
}
}
if
(
have_submounts
(
dentry
))
this
.
mnt
=
path
->
mnt
;
this
.
dentry
=
dentry
;
if
(
path_has_submounts
(
&
this
))
valid
=
0
;
valid
=
0
;
if
(
new
)
if
(
new
)
...
@@ -345,8 +349,9 @@ static int validate_request(struct autofs_wait_queue **wait,
...
@@ -345,8 +349,9 @@ static int validate_request(struct autofs_wait_queue **wait,
}
}
int
autofs4_wait
(
struct
autofs_sb_info
*
sbi
,
int
autofs4_wait
(
struct
autofs_sb_info
*
sbi
,
struct
dentry
*
dentry
,
enum
autofs_notify
notify
)
const
struct
path
*
path
,
enum
autofs_notify
notify
)
{
{
struct
dentry
*
dentry
=
path
->
dentry
;
struct
autofs_wait_queue
*
wq
;
struct
autofs_wait_queue
*
wq
;
struct
qstr
qstr
;
struct
qstr
qstr
;
char
*
name
;
char
*
name
;
...
@@ -405,7 +410,7 @@ int autofs4_wait(struct autofs_sb_info *sbi,
...
@@ -405,7 +410,7 @@ int autofs4_wait(struct autofs_sb_info *sbi,
return
-
EINTR
;
return
-
EINTR
;
}
}
ret
=
validate_request
(
&
wq
,
sbi
,
&
qstr
,
dentry
,
notify
);
ret
=
validate_request
(
&
wq
,
sbi
,
&
qstr
,
path
,
notify
);
if
(
ret
<=
0
)
{
if
(
ret
<=
0
)
{
if
(
ret
!=
-
EINTR
)
if
(
ret
!=
-
EINTR
)
mutex_unlock
(
&
sbi
->
wq_mutex
);
mutex_unlock
(
&
sbi
->
wq_mutex
);
...
...
fs/dcache.c
View file @
9763f7a4
...
@@ -1273,38 +1273,44 @@ static void d_walk(struct dentry *parent, void *data,
...
@@ -1273,38 +1273,44 @@ static void d_walk(struct dentry *parent, void *data,
goto
again
;
goto
again
;
}
}
/*
struct
check_mount
{
* Search for at least 1 mount point in the dentry's subdirs.
struct
vfsmount
*
mnt
;
* We descend to the next level whenever the d_subdirs
unsigned
int
mounted
;
* list is non-empty and continue searching.
};
*/
static
enum
d_walk_ret
check_mount
(
void
*
data
,
struct
dentry
*
dentry
)
static
enum
d_walk_ret
path_
check_mount
(
void
*
data
,
struct
dentry
*
dentry
)
{
{
int
*
ret
=
data
;
struct
check_mount
*
info
=
data
;
if
(
d_mountpoint
(
dentry
))
{
struct
path
path
=
{
.
mnt
=
info
->
mnt
,
.
dentry
=
dentry
};
*
ret
=
1
;
if
(
likely
(
!
d_mountpoint
(
dentry
)))
return
D_WALK_CONTINUE
;
if
(
__path_is_mountpoint
(
&
path
))
{
info
->
mounted
=
1
;
return
D_WALK_QUIT
;
return
D_WALK_QUIT
;
}
}
return
D_WALK_CONTINUE
;
return
D_WALK_CONTINUE
;
}
}
/**
/**
* have_submounts - check for mounts over a dentry
* path_has_submounts - check for mounts over a dentry in the
* @parent: dentry to check.
* current namespace.
* @parent: path to check.
*
*
* Return true if the parent or its subdirectories contain
* Return true if the parent or its subdirectories contain
* a mount point
* a mount point
in the current namespace.
*/
*/
int
have_submounts
(
struct
dentry
*
parent
)
int
path_has_submounts
(
const
struct
path
*
parent
)
{
{
int
ret
=
0
;
struct
check_mount
data
=
{
.
mnt
=
parent
->
mnt
,
.
mounted
=
0
}
;
d_walk
(
parent
,
&
ret
,
check_mount
,
NULL
);
read_seqlock_excl
(
&
mount_lock
);
d_walk
(
parent
->
dentry
,
&
data
,
path_check_mount
,
NULL
);
read_sequnlock_excl
(
&
mount_lock
);
return
ret
;
return
data
.
mounted
;
}
}
EXPORT_SYMBOL
(
have
_submounts
);
EXPORT_SYMBOL
(
path_has
_submounts
);
/*
/*
* Called by mount code to set a mountpoint and check if the mountpoint is
* Called by mount code to set a mountpoint and check if the mountpoint is
...
...
fs/mount.h
View file @
9763f7a4
...
@@ -94,6 +94,12 @@ extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *);
...
@@ -94,6 +94,12 @@ extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *);
extern
int
__legitimize_mnt
(
struct
vfsmount
*
,
unsigned
);
extern
int
__legitimize_mnt
(
struct
vfsmount
*
,
unsigned
);
extern
bool
legitimize_mnt
(
struct
vfsmount
*
,
unsigned
);
extern
bool
legitimize_mnt
(
struct
vfsmount
*
,
unsigned
);
static
inline
bool
__path_is_mountpoint
(
const
struct
path
*
path
)
{
struct
mount
*
m
=
__lookup_mnt
(
path
->
mnt
,
path
->
dentry
);
return
m
&&
likely
(
!
(
m
->
mnt
.
mnt_flags
&
MNT_SYNC_UMOUNT
));
}
extern
void
__detach_mounts
(
struct
dentry
*
dentry
);
extern
void
__detach_mounts
(
struct
dentry
*
dentry
);
static
inline
void
detach_mounts
(
struct
dentry
*
dentry
)
static
inline
void
detach_mounts
(
struct
dentry
*
dentry
)
...
...
fs/namei.c
View file @
9763f7a4
...
@@ -1200,7 +1200,7 @@ static int follow_managed(struct path *path, struct nameidata *nd)
...
@@ -1200,7 +1200,7 @@ static int follow_managed(struct path *path, struct nameidata *nd)
if
(
managed
&
DCACHE_MANAGE_TRANSIT
)
{
if
(
managed
&
DCACHE_MANAGE_TRANSIT
)
{
BUG_ON
(
!
path
->
dentry
->
d_op
);
BUG_ON
(
!
path
->
dentry
->
d_op
);
BUG_ON
(
!
path
->
dentry
->
d_op
->
d_manage
);
BUG_ON
(
!
path
->
dentry
->
d_op
->
d_manage
);
ret
=
path
->
dentry
->
d_op
->
d_manage
(
path
->
dentry
,
false
);
ret
=
path
->
dentry
->
d_op
->
d_manage
(
path
,
false
);
if
(
ret
<
0
)
if
(
ret
<
0
)
break
;
break
;
}
}
...
@@ -1263,10 +1263,10 @@ int follow_down_one(struct path *path)
...
@@ -1263,10 +1263,10 @@ int follow_down_one(struct path *path)
}
}
EXPORT_SYMBOL
(
follow_down_one
);
EXPORT_SYMBOL
(
follow_down_one
);
static
inline
int
managed_dentry_rcu
(
struct
dentry
*
dentry
)
static
inline
int
managed_dentry_rcu
(
const
struct
path
*
path
)
{
{
return
(
dentry
->
d_flags
&
DCACHE_MANAGE_TRANSIT
)
?
return
(
path
->
dentry
->
d_flags
&
DCACHE_MANAGE_TRANSIT
)
?
dentry
->
d_op
->
d_manage
(
dentry
,
true
)
:
0
;
path
->
dentry
->
d_op
->
d_manage
(
path
,
true
)
:
0
;
}
}
/*
/*
...
@@ -1282,7 +1282,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
...
@@ -1282,7 +1282,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
* Don't forget we might have a non-mountpoint managed dentry
* Don't forget we might have a non-mountpoint managed dentry
* that wants to block transit.
* that wants to block transit.
*/
*/
switch
(
managed_dentry_rcu
(
path
->
dentry
))
{
switch
(
managed_dentry_rcu
(
path
))
{
case
-
ECHILD
:
case
-
ECHILD
:
default:
default:
return
false
;
return
false
;
...
@@ -1392,8 +1392,7 @@ int follow_down(struct path *path)
...
@@ -1392,8 +1392,7 @@ int follow_down(struct path *path)
if
(
managed
&
DCACHE_MANAGE_TRANSIT
)
{
if
(
managed
&
DCACHE_MANAGE_TRANSIT
)
{
BUG_ON
(
!
path
->
dentry
->
d_op
);
BUG_ON
(
!
path
->
dentry
->
d_op
);
BUG_ON
(
!
path
->
dentry
->
d_op
->
d_manage
);
BUG_ON
(
!
path
->
dentry
->
d_op
->
d_manage
);
ret
=
path
->
dentry
->
d_op
->
d_manage
(
ret
=
path
->
dentry
->
d_op
->
d_manage
(
path
,
false
);
path
->
dentry
,
false
);
if
(
ret
<
0
)
if
(
ret
<
0
)
return
ret
==
-
EISDIR
?
0
:
ret
;
return
ret
==
-
EISDIR
?
0
:
ret
;
}
}
...
...
fs/namespace.c
View file @
9763f7a4
...
@@ -1159,6 +1159,35 @@ struct vfsmount *mntget(struct vfsmount *mnt)
...
@@ -1159,6 +1159,35 @@ struct vfsmount *mntget(struct vfsmount *mnt)
}
}
EXPORT_SYMBOL
(
mntget
);
EXPORT_SYMBOL
(
mntget
);
/* path_is_mountpoint() - Check if path is a mount in the current
* namespace.
*
* d_mountpoint() can only be used reliably to establish if a dentry is
* not mounted in any namespace and that common case is handled inline.
* d_mountpoint() isn't aware of the possibility there may be multiple
* mounts using a given dentry in a different namespace. This function
* checks if the passed in path is a mountpoint rather than the dentry
* alone.
*/
bool
path_is_mountpoint
(
const
struct
path
*
path
)
{
unsigned
seq
;
bool
res
;
if
(
!
d_mountpoint
(
path
->
dentry
))
return
false
;
rcu_read_lock
();
do
{
seq
=
read_seqbegin
(
&
mount_lock
);
res
=
__path_is_mountpoint
(
path
);
}
while
(
read_seqretry
(
&
mount_lock
,
seq
));
rcu_read_unlock
();
return
res
;
}
EXPORT_SYMBOL
(
path_is_mountpoint
);
struct
vfsmount
*
mnt_clone_internal
(
const
struct
path
*
path
)
struct
vfsmount
*
mnt_clone_internal
(
const
struct
path
*
path
)
{
{
struct
mount
*
p
;
struct
mount
*
p
;
...
...
include/linux/dcache.h
View file @
9763f7a4
...
@@ -139,7 +139,7 @@ struct dentry_operations {
...
@@ -139,7 +139,7 @@ struct dentry_operations {
void
(
*
d_iput
)(
struct
dentry
*
,
struct
inode
*
);
void
(
*
d_iput
)(
struct
dentry
*
,
struct
inode
*
);
char
*
(
*
d_dname
)(
struct
dentry
*
,
char
*
,
int
);
char
*
(
*
d_dname
)(
struct
dentry
*
,
char
*
,
int
);
struct
vfsmount
*
(
*
d_automount
)(
struct
path
*
);
struct
vfsmount
*
(
*
d_automount
)(
struct
path
*
);
int
(
*
d_manage
)(
struct
dentry
*
,
bool
);
int
(
*
d_manage
)(
const
struct
path
*
,
bool
);
struct
dentry
*
(
*
d_real
)(
struct
dentry
*
,
const
struct
inode
*
,
struct
dentry
*
(
*
d_real
)(
struct
dentry
*
,
const
struct
inode
*
,
unsigned
int
);
unsigned
int
);
}
____cacheline_aligned
;
}
____cacheline_aligned
;
...
@@ -254,7 +254,7 @@ extern struct dentry *d_find_alias(struct inode *);
...
@@ -254,7 +254,7 @@ extern struct dentry *d_find_alias(struct inode *);
extern
void
d_prune_aliases
(
struct
inode
*
);
extern
void
d_prune_aliases
(
struct
inode
*
);
/* test whether we have any submounts in a subdir tree */
/* test whether we have any submounts in a subdir tree */
extern
int
have_submounts
(
struct
dentry
*
);
extern
int
path_has_submounts
(
const
struct
path
*
);
/*
/*
* This adds the entry to the hash queues.
* This adds the entry to the hash queues.
...
...
include/linux/mount.h
View file @
9763f7a4
...
@@ -98,4 +98,6 @@ extern dev_t name_to_dev_t(const char *name);
...
@@ -98,4 +98,6 @@ extern dev_t name_to_dev_t(const char *name);
extern
unsigned
int
sysctl_mount_max
;
extern
unsigned
int
sysctl_mount_max
;
extern
bool
path_is_mountpoint
(
const
struct
path
*
path
);
#endif
/* _LINUX_MOUNT_H */
#endif
/* _LINUX_MOUNT_H */
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment