Merge branch 'work.autofs' into for-linus
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
commit
9763f7a4a5
|
@ -20,7 +20,7 @@ prototypes:
|
|||
void (*d_iput)(struct dentry *, struct inode *);
|
||||
char *(*d_dname)((struct dentry *dentry, char *buffer, int buflen);
|
||||
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 *,
|
||||
unsigned int);
|
||||
|
||||
|
|
|
@ -948,7 +948,7 @@ struct dentry_operations {
|
|||
void (*d_iput)(struct dentry *, struct inode *);
|
||||
char *(*d_dname)(struct dentry *, char *, int);
|
||||
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 *,
|
||||
unsigned int);
|
||||
};
|
||||
|
|
|
@ -145,7 +145,7 @@ void autofs4_free_ino(struct autofs_info *);
|
|||
|
||||
/* Expiration */
|
||||
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 *,
|
||||
struct autofs_sb_info *,
|
||||
struct autofs_packet_expire __user *);
|
||||
|
@ -217,7 +217,8 @@ static inline int autofs_prepare_pipe(struct file *pipe)
|
|||
|
||||
/* 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);
|
||||
void autofs4_catatonic_mode(struct autofs_sb_info *);
|
||||
|
||||
|
|
|
@ -468,7 +468,7 @@ static int autofs_dev_ioctl_requester(struct file *fp,
|
|||
ino = autofs4_dentry_ino(path.dentry);
|
||||
if (ino) {
|
||||
err = 0;
|
||||
autofs4_expire_wait(path.dentry, 0);
|
||||
autofs4_expire_wait(&path, 0);
|
||||
spin_lock(&sbi->fs_lock);
|
||||
param->requester.uid =
|
||||
from_kuid_munged(current_user_ns(), ino->uid);
|
||||
|
@ -575,7 +575,7 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
|
|||
|
||||
devid = new_encode_dev(dev);
|
||||
|
||||
err = have_submounts(path.dentry);
|
||||
err = path_has_submounts(&path);
|
||||
|
||||
if (follow_down_one(&path))
|
||||
magic = path.dentry->d_sb->s_magic;
|
||||
|
|
|
@ -310,26 +310,29 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
|
|||
now = jiffies;
|
||||
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)) {
|
||||
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;
|
||||
spin_unlock(&sbi->fs_lock);
|
||||
synchronize_rcu();
|
||||
spin_lock(&sbi->fs_lock);
|
||||
if (!autofs4_direct_busy(mnt, root, timeout, do_now)) {
|
||||
spin_lock(&sbi->fs_lock);
|
||||
ino->flags |= AUTOFS_INF_EXPIRING;
|
||||
init_completion(&ino->expire_complete);
|
||||
spin_unlock(&sbi->fs_lock);
|
||||
return root;
|
||||
}
|
||||
spin_lock(&sbi->fs_lock);
|
||||
ino->flags &= ~AUTOFS_INF_WANT_EXPIRE;
|
||||
spin_unlock(&sbi->fs_lock);
|
||||
}
|
||||
out:
|
||||
spin_unlock(&sbi->fs_lock);
|
||||
dput(root);
|
||||
|
||||
return NULL;
|
||||
|
@ -495,8 +498,9 @@ found:
|
|||
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_info *ino = autofs4_dentry_ino(dentry);
|
||||
int status;
|
||||
|
@ -525,7 +529,7 @@ retry:
|
|||
|
||||
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);
|
||||
|
||||
pr_debug("expire done status=%d\n", status);
|
||||
|
@ -592,11 +596,12 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
|
|||
|
||||
if (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
|
||||
* little easier
|
||||
*/
|
||||
ret = autofs4_wait(sbi, dentry, NFY_EXPIRE);
|
||||
ret = autofs4_wait(sbi, &path, NFY_EXPIRE);
|
||||
|
||||
spin_lock(&sbi->fs_lock);
|
||||
/* avoid rapid-fire expire attempts if expiry fails */
|
||||
|
|
|
@ -32,7 +32,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file);
|
|||
static struct dentry *autofs4_lookup(struct inode *,
|
||||
struct dentry *, unsigned int);
|
||||
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 *);
|
||||
|
||||
const struct file_operations autofs4_root_operations = {
|
||||
|
@ -123,7 +123,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
|
|||
* it.
|
||||
*/
|
||||
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);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
@ -269,39 +269,41 @@ next:
|
|||
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_info *ino = autofs4_dentry_ino(dentry);
|
||||
struct autofs_sb_info *sbi = autofs4_sbi(path->dentry->d_sb);
|
||||
struct autofs_info *ino = autofs4_dentry_ino(path->dentry);
|
||||
int status = 0;
|
||||
|
||||
if (ino->flags & AUTOFS_INF_PENDING) {
|
||||
if (rcu_walk)
|
||||
return -ECHILD;
|
||||
pr_debug("waiting for mount name=%pd\n", dentry);
|
||||
status = autofs4_wait(sbi, dentry, NFY_MOUNT);
|
||||
pr_debug("waiting for mount name=%pd\n", path->dentry);
|
||||
status = autofs4_wait(sbi, path, NFY_MOUNT);
|
||||
pr_debug("mount wait done status=%d\n", status);
|
||||
}
|
||||
ino->last_used = jiffies;
|
||||
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;
|
||||
|
||||
expiring = autofs4_lookup_expiring(dentry, rcu_walk);
|
||||
if (IS_ERR(expiring))
|
||||
return PTR_ERR(expiring);
|
||||
if (!expiring)
|
||||
return autofs4_expire_wait(dentry, rcu_walk);
|
||||
return autofs4_expire_wait(path, rcu_walk);
|
||||
else {
|
||||
const struct path this = { .mnt = path->mnt, .dentry = expiring };
|
||||
/*
|
||||
* If we are racing with expire the request might not
|
||||
* be quite complete, but the directory has been removed
|
||||
* so it must have been successful, just wait for it.
|
||||
*/
|
||||
autofs4_expire_wait(expiring, 0);
|
||||
autofs4_expire_wait(&this, 0);
|
||||
autofs4_del_expiring(expiring);
|
||||
dput(expiring);
|
||||
}
|
||||
|
@ -354,7 +356,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
|
|||
* and the directory was removed, so just go ahead and try
|
||||
* the mount.
|
||||
*/
|
||||
status = do_expire_wait(dentry, 0);
|
||||
status = do_expire_wait(path, 0);
|
||||
if (status && status != -EAGAIN)
|
||||
return NULL;
|
||||
|
||||
|
@ -362,7 +364,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
|
|||
spin_lock(&sbi->fs_lock);
|
||||
if (ino->flags & AUTOFS_INF_PENDING) {
|
||||
spin_unlock(&sbi->fs_lock);
|
||||
status = autofs4_mount_wait(dentry, 0);
|
||||
status = autofs4_mount_wait(path, 0);
|
||||
if (status)
|
||||
return ERR_PTR(status);
|
||||
goto done;
|
||||
|
@ -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
|
||||
* having d_mountpoint() true, so there's no need to call back
|
||||
* to the daemon.
|
||||
* having path_is_mountpoint() true, so there's no need to call
|
||||
* back to the daemon.
|
||||
*/
|
||||
if (d_really_is_positive(dentry) && d_is_symlink(dentry)) {
|
||||
spin_unlock(&sbi->fs_lock);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (!d_mountpoint(dentry)) {
|
||||
if (!path_is_mountpoint(path)) {
|
||||
/*
|
||||
* It's possible that user space hasn't removed directories
|
||||
* after umounting a rootless multi-mount, although it
|
||||
* should. For v5 have_submounts() is sufficient to handle
|
||||
* this because the leaves of the directory tree under the
|
||||
* mount never trigger mounts themselves (they have an autofs
|
||||
* trigger mount mounted on them). But v4 pseudo direct mounts
|
||||
* do need the leaves to trigger mounts. In this case we
|
||||
* have no choice but to use the list_empty() check and
|
||||
* should. For v5 path_has_submounts() is sufficient to
|
||||
* handle this because the leaves of the directory tree under
|
||||
* the mount never trigger mounts themselves (they have an
|
||||
* autofs trigger mount mounted on them). But v4 pseudo direct
|
||||
* mounts do need the leaves to trigger mounts. In this case
|
||||
* we have no choice but to use the list_empty() check and
|
||||
* require user space behave.
|
||||
*/
|
||||
if (sbi->version > 4) {
|
||||
if (have_submounts(dentry)) {
|
||||
if (path_has_submounts(path)) {
|
||||
spin_unlock(&sbi->fs_lock);
|
||||
goto done;
|
||||
}
|
||||
|
@ -403,7 +405,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
|
|||
}
|
||||
ino->flags |= AUTOFS_INF_PENDING;
|
||||
spin_unlock(&sbi->fs_lock);
|
||||
status = autofs4_mount_wait(dentry, 0);
|
||||
status = autofs4_mount_wait(path, 0);
|
||||
spin_lock(&sbi->fs_lock);
|
||||
ino->flags &= ~AUTOFS_INF_PENDING;
|
||||
if (status) {
|
||||
|
@ -421,8 +423,9 @@ done:
|
|||
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_info *ino = autofs4_dentry_ino(dentry);
|
||||
int status;
|
||||
|
@ -431,20 +434,20 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
|
|||
|
||||
/* The daemon never waits. */
|
||||
if (autofs4_oz_mode(sbi)) {
|
||||
if (!d_mountpoint(dentry))
|
||||
if (!path_is_mountpoint(path))
|
||||
return -EISDIR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Wait for pending expires */
|
||||
if (do_expire_wait(dentry, rcu_walk) == -ECHILD)
|
||||
if (do_expire_wait(path, rcu_walk) == -ECHILD)
|
||||
return -ECHILD;
|
||||
|
||||
/*
|
||||
* This dentry may be under construction so wait on mount
|
||||
* completion.
|
||||
*/
|
||||
status = autofs4_mount_wait(dentry, rcu_walk);
|
||||
status = autofs4_mount_wait(path, rcu_walk);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
|
@ -460,7 +463,7 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
|
|||
|
||||
if (ino->flags & AUTOFS_INF_WANT_EXPIRE)
|
||||
return 0;
|
||||
if (d_mountpoint(dentry))
|
||||
if (path_is_mountpoint(path))
|
||||
return 0;
|
||||
inode = d_inode_rcu(dentry);
|
||||
if (inode && S_ISLNK(inode->i_mode))
|
||||
|
@ -487,7 +490,7 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
|
|||
* we can avoid needless calls ->d_automount() and avoid
|
||||
* 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)))
|
||||
status = -EISDIR;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
struct autofs_sb_info *sbi,
|
||||
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_info *ino;
|
||||
|
||||
|
@ -314,6 +315,7 @@ static int validate_request(struct autofs_wait_queue **wait,
|
|||
*/
|
||||
if (notify == NFY_MOUNT) {
|
||||
struct dentry *new = NULL;
|
||||
struct path this;
|
||||
int valid = 1;
|
||||
|
||||
/*
|
||||
|
@ -333,7 +335,9 @@ static int validate_request(struct autofs_wait_queue **wait,
|
|||
dentry = new;
|
||||
}
|
||||
}
|
||||
if (have_submounts(dentry))
|
||||
this.mnt = path->mnt;
|
||||
this.dentry = dentry;
|
||||
if (path_has_submounts(&this))
|
||||
valid = 0;
|
||||
|
||||
if (new)
|
||||
|
@ -345,8 +349,9 @@ static int validate_request(struct autofs_wait_queue **wait,
|
|||
}
|
||||
|
||||
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 qstr qstr;
|
||||
char *name;
|
||||
|
@ -405,7 +410,7 @@ int autofs4_wait(struct autofs_sb_info *sbi,
|
|||
return -EINTR;
|
||||
}
|
||||
|
||||
ret = validate_request(&wq, sbi, &qstr, dentry, notify);
|
||||
ret = validate_request(&wq, sbi, &qstr, path, notify);
|
||||
if (ret <= 0) {
|
||||
if (ret != -EINTR)
|
||||
mutex_unlock(&sbi->wq_mutex);
|
||||
|
|
40
fs/dcache.c
40
fs/dcache.c
|
@ -1273,38 +1273,44 @@ rename_retry:
|
|||
goto again;
|
||||
}
|
||||
|
||||
/*
|
||||
* Search for at least 1 mount point in the dentry's subdirs.
|
||||
* We descend to the next level whenever the d_subdirs
|
||||
* list is non-empty and continue searching.
|
||||
*/
|
||||
struct check_mount {
|
||||
struct vfsmount *mnt;
|
||||
unsigned int mounted;
|
||||
};
|
||||
|
||||
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;
|
||||
if (d_mountpoint(dentry)) {
|
||||
*ret = 1;
|
||||
struct check_mount *info = data;
|
||||
struct path path = { .mnt = info->mnt, .dentry = dentry };
|
||||
|
||||
if (likely(!d_mountpoint(dentry)))
|
||||
return D_WALK_CONTINUE;
|
||||
if (__path_is_mountpoint(&path)) {
|
||||
info->mounted = 1;
|
||||
return D_WALK_QUIT;
|
||||
}
|
||||
return D_WALK_CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* have_submounts - check for mounts over a dentry
|
||||
* @parent: dentry to check.
|
||||
* path_has_submounts - check for mounts over a dentry in the
|
||||
* current namespace.
|
||||
* @parent: path to check.
|
||||
*
|
||||
* 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
|
||||
|
|
|
@ -94,6 +94,12 @@ extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *);
|
|||
extern int __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);
|
||||
|
||||
static inline void detach_mounts(struct dentry *dentry)
|
||||
|
|
13
fs/namei.c
13
fs/namei.c
|
@ -1200,7 +1200,7 @@ static int follow_managed(struct path *path, struct nameidata *nd)
|
|||
if (managed & DCACHE_MANAGE_TRANSIT) {
|
||||
BUG_ON(!path->dentry->d_op);
|
||||
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)
|
||||
break;
|
||||
}
|
||||
|
@ -1263,10 +1263,10 @@ int follow_down_one(struct path *path)
|
|||
}
|
||||
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) ?
|
||||
dentry->d_op->d_manage(dentry, true) : 0;
|
||||
return (path->dentry->d_flags & DCACHE_MANAGE_TRANSIT) ?
|
||||
path->dentry->d_op->d_manage(path, true) : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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
|
||||
* that wants to block transit.
|
||||
*/
|
||||
switch (managed_dentry_rcu(path->dentry)) {
|
||||
switch (managed_dentry_rcu(path)) {
|
||||
case -ECHILD:
|
||||
default:
|
||||
return false;
|
||||
|
@ -1392,8 +1392,7 @@ int follow_down(struct path *path)
|
|||
if (managed & DCACHE_MANAGE_TRANSIT) {
|
||||
BUG_ON(!path->dentry->d_op);
|
||||
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)
|
||||
return ret == -EISDIR ? 0 : ret;
|
||||
}
|
||||
|
|
|
@ -1159,6 +1159,35 @@ struct vfsmount *mntget(struct vfsmount *mnt)
|
|||
}
|
||||
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 mount *p;
|
||||
|
|
|
@ -139,7 +139,7 @@ struct dentry_operations {
|
|||
void (*d_iput)(struct dentry *, struct inode *);
|
||||
char *(*d_dname)(struct dentry *, char *, int);
|
||||
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 *,
|
||||
unsigned int);
|
||||
} ____cacheline_aligned;
|
||||
|
@ -254,7 +254,7 @@ extern struct dentry *d_find_alias(struct inode *);
|
|||
extern void d_prune_aliases(struct inode *);
|
||||
|
||||
/* 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.
|
||||
|
|
|
@ -98,4 +98,6 @@ extern dev_t name_to_dev_t(const char *name);
|
|||
|
||||
extern unsigned int sysctl_mount_max;
|
||||
|
||||
extern bool path_is_mountpoint(const struct path *path);
|
||||
|
||||
#endif /* _LINUX_MOUNT_H */
|
||||
|
|
Loading…
Reference in New Issue