forked from Minki/linux
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: fs: call security_d_instantiate in d_obtain_alias V2 lose 'mounting_here' argument in ->d_manage() don't pass 'mounting_here' flag to follow_down() change the locking order for namespace_sem fix deadlock in pivot_root() vfs: split off vfsmount-related parts of vfs_kern_mount() Some fixes for pstore kill simple_set_mnt()
This commit is contained in:
commit
f539abece1
@ -873,7 +873,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, bool);
|
int (*d_manage)(struct dentry *, bool);
|
||||||
};
|
};
|
||||||
|
|
||||||
d_revalidate: called when the VFS needs to revalidate a dentry. This
|
d_revalidate: called when the VFS needs to revalidate a dentry. This
|
||||||
@ -969,10 +969,6 @@ struct dentry_operations {
|
|||||||
mounted on it and not to check the automount flag. Any other error
|
mounted on it and not to check the automount flag. Any other error
|
||||||
code will abort pathwalk completely.
|
code will abort pathwalk completely.
|
||||||
|
|
||||||
If the 'mounting_here' parameter is true, then namespace_sem is being
|
|
||||||
held by the caller and the function should not initiate any mounts or
|
|
||||||
unmounts that it will then wait for.
|
|
||||||
|
|
||||||
If the 'rcu_walk' parameter is true, then the caller is doing a
|
If the 'rcu_walk' parameter is true, then the caller is doing a
|
||||||
pathwalk in RCU-walk mode. Sleeping is not permitted in this mode,
|
pathwalk in RCU-walk mode. Sleeping is not permitted in this mode,
|
||||||
and the caller can be asked to leave it and call again by returing
|
and the caller can be asked to leave it and call again by returing
|
||||||
|
@ -36,7 +36,7 @@ static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long);
|
|||||||
static int autofs4_dir_open(struct inode *inode, struct file *file);
|
static int autofs4_dir_open(struct inode *inode, struct file *file);
|
||||||
static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
|
static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
|
||||||
static struct vfsmount *autofs4_d_automount(struct path *);
|
static struct vfsmount *autofs4_d_automount(struct path *);
|
||||||
static int autofs4_d_manage(struct dentry *, bool, bool);
|
static int autofs4_d_manage(struct dentry *, 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 = {
|
||||||
@ -446,7 +446,7 @@ done:
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int autofs4_d_manage(struct dentry *dentry, bool mounting_here, bool rcu_walk)
|
int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
|
||||||
{
|
{
|
||||||
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
|
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
|
||||||
|
|
||||||
@ -454,7 +454,7 @@ int autofs4_d_manage(struct dentry *dentry, bool mounting_here, bool rcu_walk)
|
|||||||
dentry, dentry->d_name.len, dentry->d_name.name);
|
dentry, dentry->d_name.len, dentry->d_name.name);
|
||||||
|
|
||||||
/* The daemon never waits. */
|
/* The daemon never waits. */
|
||||||
if (autofs4_oz_mode(sbi) || mounting_here) {
|
if (autofs4_oz_mode(sbi)) {
|
||||||
if (!d_mountpoint(dentry))
|
if (!d_mountpoint(dentry))
|
||||||
return -EISDIR;
|
return -EISDIR;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1612,10 +1612,13 @@ struct dentry *d_obtain_alias(struct inode *inode)
|
|||||||
__bit_spin_unlock(0, (unsigned long *)&tmp->d_sb->s_anon.first);
|
__bit_spin_unlock(0, (unsigned long *)&tmp->d_sb->s_anon.first);
|
||||||
spin_unlock(&tmp->d_lock);
|
spin_unlock(&tmp->d_lock);
|
||||||
spin_unlock(&inode->i_lock);
|
spin_unlock(&inode->i_lock);
|
||||||
|
security_d_instantiate(tmp, inode);
|
||||||
|
|
||||||
return tmp;
|
return tmp;
|
||||||
|
|
||||||
out_iput:
|
out_iput:
|
||||||
|
if (res && !IS_ERR(res))
|
||||||
|
security_d_instantiate(res, inode);
|
||||||
iput(inode);
|
iput(inode);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@
|
|||||||
#include <linux/lglock.h>
|
#include <linux/lglock.h>
|
||||||
|
|
||||||
struct super_block;
|
struct super_block;
|
||||||
|
struct file_system_type;
|
||||||
struct linux_binprm;
|
struct linux_binprm;
|
||||||
struct path;
|
struct path;
|
||||||
|
|
||||||
@ -61,8 +62,6 @@ extern int check_unsafe_exec(struct linux_binprm *);
|
|||||||
extern int copy_mount_options(const void __user *, unsigned long *);
|
extern int copy_mount_options(const void __user *, unsigned long *);
|
||||||
extern int copy_mount_string(const void __user *, char **);
|
extern int copy_mount_string(const void __user *, char **);
|
||||||
|
|
||||||
extern void free_vfsmnt(struct vfsmount *);
|
|
||||||
extern struct vfsmount *alloc_vfsmnt(const char *);
|
|
||||||
extern unsigned int mnt_get_count(struct vfsmount *mnt);
|
extern unsigned int mnt_get_count(struct vfsmount *mnt);
|
||||||
extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int);
|
extern struct vfsmount *__lookup_mnt(struct vfsmount *, struct dentry *, int);
|
||||||
extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
|
extern void mnt_set_mountpoint(struct vfsmount *, struct dentry *,
|
||||||
@ -99,6 +98,8 @@ extern struct file *get_empty_filp(void);
|
|||||||
extern int do_remount_sb(struct super_block *, int, void *, int);
|
extern int do_remount_sb(struct super_block *, int, void *, int);
|
||||||
extern void __put_super(struct super_block *sb);
|
extern void __put_super(struct super_block *sb);
|
||||||
extern void put_super(struct super_block *sb);
|
extern void put_super(struct super_block *sb);
|
||||||
|
extern struct dentry *mount_fs(struct file_system_type *,
|
||||||
|
int, const char *, void *);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* open.c
|
* open.c
|
||||||
|
@ -933,8 +933,7 @@ static int follow_managed(struct path *path, unsigned flags)
|
|||||||
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,
|
ret = path->dentry->d_op->d_manage(path->dentry, false);
|
||||||
false, false);
|
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret == -EISDIR ? 0 : ret;
|
return ret == -EISDIR ? 0 : ret;
|
||||||
}
|
}
|
||||||
@ -999,7 +998,7 @@ static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
|
|||||||
struct vfsmount *mounted;
|
struct vfsmount *mounted;
|
||||||
if (unlikely(path->dentry->d_flags & DCACHE_MANAGE_TRANSIT) &&
|
if (unlikely(path->dentry->d_flags & DCACHE_MANAGE_TRANSIT) &&
|
||||||
!reverse_transit &&
|
!reverse_transit &&
|
||||||
path->dentry->d_op->d_manage(path->dentry, false, true) < 0)
|
path->dentry->d_op->d_manage(path->dentry, true) < 0)
|
||||||
return false;
|
return false;
|
||||||
mounted = __lookup_mnt(path->mnt, path->dentry, 1);
|
mounted = __lookup_mnt(path->mnt, path->dentry, 1);
|
||||||
if (!mounted)
|
if (!mounted)
|
||||||
@ -1065,7 +1064,7 @@ failed:
|
|||||||
* Care must be taken as namespace_sem may be held (indicated by mounting_here
|
* Care must be taken as namespace_sem may be held (indicated by mounting_here
|
||||||
* being true).
|
* being true).
|
||||||
*/
|
*/
|
||||||
int follow_down(struct path *path, bool mounting_here)
|
int follow_down(struct path *path)
|
||||||
{
|
{
|
||||||
unsigned managed;
|
unsigned managed;
|
||||||
int ret;
|
int ret;
|
||||||
@ -1086,7 +1085,7 @@ int follow_down(struct path *path, bool mounting_here)
|
|||||||
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->dentry, mounting_here, false);
|
path->dentry, false);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret == -EISDIR ? 0 : ret;
|
return ret == -EISDIR ? 0 : ret;
|
||||||
}
|
}
|
||||||
|
294
fs/namespace.c
294
fs/namespace.c
@ -196,7 +196,7 @@ unsigned int mnt_get_count(struct vfsmount *mnt)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
struct vfsmount *alloc_vfsmnt(const char *name)
|
static struct vfsmount *alloc_vfsmnt(const char *name)
|
||||||
{
|
{
|
||||||
struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
|
struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL);
|
||||||
if (mnt) {
|
if (mnt) {
|
||||||
@ -466,15 +466,7 @@ static void __mnt_unmake_readonly(struct vfsmount *mnt)
|
|||||||
br_write_unlock(vfsmount_lock);
|
br_write_unlock(vfsmount_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)
|
static void free_vfsmnt(struct vfsmount *mnt)
|
||||||
{
|
|
||||||
mnt->mnt_sb = sb;
|
|
||||||
mnt->mnt_root = dget(sb->s_root);
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT_SYMBOL(simple_set_mnt);
|
|
||||||
|
|
||||||
void free_vfsmnt(struct vfsmount *mnt)
|
|
||||||
{
|
{
|
||||||
kfree(mnt->mnt_devname);
|
kfree(mnt->mnt_devname);
|
||||||
mnt_free_id(mnt);
|
mnt_free_id(mnt);
|
||||||
@ -678,6 +670,36 @@ static struct vfsmount *skip_mnt_tree(struct vfsmount *p)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct vfsmount *
|
||||||
|
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
|
||||||
|
{
|
||||||
|
struct vfsmount *mnt;
|
||||||
|
struct dentry *root;
|
||||||
|
|
||||||
|
if (!type)
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
|
||||||
|
mnt = alloc_vfsmnt(name);
|
||||||
|
if (!mnt)
|
||||||
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
|
if (flags & MS_KERNMOUNT)
|
||||||
|
mnt->mnt_flags = MNT_INTERNAL;
|
||||||
|
|
||||||
|
root = mount_fs(type, flags, name, data);
|
||||||
|
if (IS_ERR(root)) {
|
||||||
|
free_vfsmnt(mnt);
|
||||||
|
return ERR_CAST(root);
|
||||||
|
}
|
||||||
|
|
||||||
|
mnt->mnt_root = root;
|
||||||
|
mnt->mnt_sb = root->d_sb;
|
||||||
|
mnt->mnt_mountpoint = mnt->mnt_root;
|
||||||
|
mnt->mnt_parent = mnt;
|
||||||
|
return mnt;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(vfs_kern_mount);
|
||||||
|
|
||||||
static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
|
static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
|
||||||
int flag)
|
int flag)
|
||||||
{
|
{
|
||||||
@ -1641,9 +1663,35 @@ static int attach_recursive_mnt(struct vfsmount *source_mnt,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int lock_mount(struct path *path)
|
||||||
|
{
|
||||||
|
struct vfsmount *mnt;
|
||||||
|
retry:
|
||||||
|
mutex_lock(&path->dentry->d_inode->i_mutex);
|
||||||
|
if (unlikely(cant_mount(path->dentry))) {
|
||||||
|
mutex_unlock(&path->dentry->d_inode->i_mutex);
|
||||||
|
return -ENOENT;
|
||||||
|
}
|
||||||
|
down_write(&namespace_sem);
|
||||||
|
mnt = lookup_mnt(path);
|
||||||
|
if (likely(!mnt))
|
||||||
|
return 0;
|
||||||
|
up_write(&namespace_sem);
|
||||||
|
mutex_unlock(&path->dentry->d_inode->i_mutex);
|
||||||
|
path_put(path);
|
||||||
|
path->mnt = mnt;
|
||||||
|
path->dentry = dget(mnt->mnt_root);
|
||||||
|
goto retry;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unlock_mount(struct path *path)
|
||||||
|
{
|
||||||
|
up_write(&namespace_sem);
|
||||||
|
mutex_unlock(&path->dentry->d_inode->i_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
static int graft_tree(struct vfsmount *mnt, struct path *path)
|
static int graft_tree(struct vfsmount *mnt, struct path *path)
|
||||||
{
|
{
|
||||||
int err;
|
|
||||||
if (mnt->mnt_sb->s_flags & MS_NOUSER)
|
if (mnt->mnt_sb->s_flags & MS_NOUSER)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
@ -1651,16 +1699,10 @@ static int graft_tree(struct vfsmount *mnt, struct path *path)
|
|||||||
S_ISDIR(mnt->mnt_root->d_inode->i_mode))
|
S_ISDIR(mnt->mnt_root->d_inode->i_mode))
|
||||||
return -ENOTDIR;
|
return -ENOTDIR;
|
||||||
|
|
||||||
err = -ENOENT;
|
if (d_unlinked(path->dentry))
|
||||||
mutex_lock(&path->dentry->d_inode->i_mutex);
|
return -ENOENT;
|
||||||
if (cant_mount(path->dentry))
|
|
||||||
goto out_unlock;
|
|
||||||
|
|
||||||
if (!d_unlinked(path->dentry))
|
return attach_recursive_mnt(mnt, path, NULL);
|
||||||
err = attach_recursive_mnt(mnt, path, NULL);
|
|
||||||
out_unlock:
|
|
||||||
mutex_unlock(&path->dentry->d_inode->i_mutex);
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1723,6 +1765,7 @@ static int do_change_type(struct path *path, int flag)
|
|||||||
static int do_loopback(struct path *path, char *old_name,
|
static int do_loopback(struct path *path, char *old_name,
|
||||||
int recurse)
|
int recurse)
|
||||||
{
|
{
|
||||||
|
LIST_HEAD(umount_list);
|
||||||
struct path old_path;
|
struct path old_path;
|
||||||
struct vfsmount *mnt = NULL;
|
struct vfsmount *mnt = NULL;
|
||||||
int err = mount_is_safe(path);
|
int err = mount_is_safe(path);
|
||||||
@ -1734,13 +1777,16 @@ static int do_loopback(struct path *path, char *old_name,
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
down_write(&namespace_sem);
|
err = lock_mount(path);
|
||||||
err = -EINVAL;
|
if (err)
|
||||||
if (IS_MNT_UNBINDABLE(old_path.mnt))
|
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
err = -EINVAL;
|
||||||
|
if (IS_MNT_UNBINDABLE(old_path.mnt))
|
||||||
|
goto out2;
|
||||||
|
|
||||||
if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
|
if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
|
||||||
goto out;
|
goto out2;
|
||||||
|
|
||||||
err = -ENOMEM;
|
err = -ENOMEM;
|
||||||
if (recurse)
|
if (recurse)
|
||||||
@ -1749,20 +1795,18 @@ static int do_loopback(struct path *path, char *old_name,
|
|||||||
mnt = clone_mnt(old_path.mnt, old_path.dentry, 0);
|
mnt = clone_mnt(old_path.mnt, old_path.dentry, 0);
|
||||||
|
|
||||||
if (!mnt)
|
if (!mnt)
|
||||||
goto out;
|
goto out2;
|
||||||
|
|
||||||
err = graft_tree(mnt, path);
|
err = graft_tree(mnt, path);
|
||||||
if (err) {
|
if (err) {
|
||||||
LIST_HEAD(umount_list);
|
|
||||||
|
|
||||||
br_write_lock(vfsmount_lock);
|
br_write_lock(vfsmount_lock);
|
||||||
umount_tree(mnt, 0, &umount_list);
|
umount_tree(mnt, 0, &umount_list);
|
||||||
br_write_unlock(vfsmount_lock);
|
br_write_unlock(vfsmount_lock);
|
||||||
release_mounts(&umount_list);
|
|
||||||
}
|
}
|
||||||
|
out2:
|
||||||
|
unlock_mount(path);
|
||||||
|
release_mounts(&umount_list);
|
||||||
out:
|
out:
|
||||||
up_write(&namespace_sem);
|
|
||||||
path_put(&old_path);
|
path_put(&old_path);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@ -1851,18 +1895,12 @@ static int do_move_mount(struct path *path, char *old_name)
|
|||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
down_write(&namespace_sem);
|
err = lock_mount(path);
|
||||||
err = follow_down(path, true);
|
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
err = -EINVAL;
|
err = -EINVAL;
|
||||||
if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
|
if (!check_mnt(path->mnt) || !check_mnt(old_path.mnt))
|
||||||
goto out;
|
|
||||||
|
|
||||||
err = -ENOENT;
|
|
||||||
mutex_lock(&path->dentry->d_inode->i_mutex);
|
|
||||||
if (cant_mount(path->dentry))
|
|
||||||
goto out1;
|
goto out1;
|
||||||
|
|
||||||
if (d_unlinked(path->dentry))
|
if (d_unlinked(path->dentry))
|
||||||
@ -1904,16 +1942,87 @@ static int do_move_mount(struct path *path, char *old_name)
|
|||||||
* automatically */
|
* automatically */
|
||||||
list_del_init(&old_path.mnt->mnt_expire);
|
list_del_init(&old_path.mnt->mnt_expire);
|
||||||
out1:
|
out1:
|
||||||
mutex_unlock(&path->dentry->d_inode->i_mutex);
|
unlock_mount(path);
|
||||||
out:
|
out:
|
||||||
up_write(&namespace_sem);
|
|
||||||
if (!err)
|
if (!err)
|
||||||
path_put(&parent_path);
|
path_put(&parent_path);
|
||||||
path_put(&old_path);
|
path_put(&old_path);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_add_mount(struct vfsmount *, struct path *, int);
|
static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
const char *subtype = strchr(fstype, '.');
|
||||||
|
if (subtype) {
|
||||||
|
subtype++;
|
||||||
|
err = -EINVAL;
|
||||||
|
if (!subtype[0])
|
||||||
|
goto err;
|
||||||
|
} else
|
||||||
|
subtype = "";
|
||||||
|
|
||||||
|
mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL);
|
||||||
|
err = -ENOMEM;
|
||||||
|
if (!mnt->mnt_sb->s_subtype)
|
||||||
|
goto err;
|
||||||
|
return mnt;
|
||||||
|
|
||||||
|
err:
|
||||||
|
mntput(mnt);
|
||||||
|
return ERR_PTR(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct vfsmount *
|
||||||
|
do_kern_mount(const char *fstype, int flags, const char *name, void *data)
|
||||||
|
{
|
||||||
|
struct file_system_type *type = get_fs_type(fstype);
|
||||||
|
struct vfsmount *mnt;
|
||||||
|
if (!type)
|
||||||
|
return ERR_PTR(-ENODEV);
|
||||||
|
mnt = vfs_kern_mount(type, flags, name, data);
|
||||||
|
if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
|
||||||
|
!mnt->mnt_sb->s_subtype)
|
||||||
|
mnt = fs_set_subtype(mnt, fstype);
|
||||||
|
put_filesystem(type);
|
||||||
|
return mnt;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(do_kern_mount);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* add a mount into a namespace's mount tree
|
||||||
|
*/
|
||||||
|
static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
|
||||||
|
mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL);
|
||||||
|
|
||||||
|
err = lock_mount(path);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
err = -EINVAL;
|
||||||
|
if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
|
/* Refuse the same filesystem on the same mount point */
|
||||||
|
err = -EBUSY;
|
||||||
|
if (path->mnt->mnt_sb == newmnt->mnt_sb &&
|
||||||
|
path->mnt->mnt_root == path->dentry)
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
|
err = -EINVAL;
|
||||||
|
if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode))
|
||||||
|
goto unlock;
|
||||||
|
|
||||||
|
newmnt->mnt_flags = mnt_flags;
|
||||||
|
err = graft_tree(newmnt, path);
|
||||||
|
|
||||||
|
unlock:
|
||||||
|
unlock_mount(path);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create a new mount for userspace and request it to be added into the
|
* create a new mount for userspace and request it to be added into the
|
||||||
@ -1973,43 +2082,6 @@ fail:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* add a mount into a namespace's mount tree
|
|
||||||
*/
|
|
||||||
static int do_add_mount(struct vfsmount *newmnt, struct path *path, int mnt_flags)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
|
|
||||||
mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL);
|
|
||||||
|
|
||||||
down_write(&namespace_sem);
|
|
||||||
/* Something was mounted here while we slept */
|
|
||||||
err = follow_down(path, true);
|
|
||||||
if (err < 0)
|
|
||||||
goto unlock;
|
|
||||||
|
|
||||||
err = -EINVAL;
|
|
||||||
if (!(mnt_flags & MNT_SHRINKABLE) && !check_mnt(path->mnt))
|
|
||||||
goto unlock;
|
|
||||||
|
|
||||||
/* Refuse the same filesystem on the same mount point */
|
|
||||||
err = -EBUSY;
|
|
||||||
if (path->mnt->mnt_sb == newmnt->mnt_sb &&
|
|
||||||
path->mnt->mnt_root == path->dentry)
|
|
||||||
goto unlock;
|
|
||||||
|
|
||||||
err = -EINVAL;
|
|
||||||
if (S_ISLNK(newmnt->mnt_root->d_inode->i_mode))
|
|
||||||
goto unlock;
|
|
||||||
|
|
||||||
newmnt->mnt_flags = mnt_flags;
|
|
||||||
err = graft_tree(newmnt, path);
|
|
||||||
|
|
||||||
unlock:
|
|
||||||
up_write(&namespace_sem);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* mnt_set_expiry - Put a mount on an expiration list
|
* mnt_set_expiry - Put a mount on an expiration list
|
||||||
* @mnt: The mount to list.
|
* @mnt: The mount to list.
|
||||||
@ -2510,65 +2582,60 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
|
|||||||
error = user_path_dir(new_root, &new);
|
error = user_path_dir(new_root, &new);
|
||||||
if (error)
|
if (error)
|
||||||
goto out0;
|
goto out0;
|
||||||
error = -EINVAL;
|
|
||||||
if (!check_mnt(new.mnt))
|
|
||||||
goto out1;
|
|
||||||
|
|
||||||
error = user_path_dir(put_old, &old);
|
error = user_path_dir(put_old, &old);
|
||||||
if (error)
|
if (error)
|
||||||
goto out1;
|
goto out1;
|
||||||
|
|
||||||
error = security_sb_pivotroot(&old, &new);
|
error = security_sb_pivotroot(&old, &new);
|
||||||
if (error) {
|
if (error)
|
||||||
path_put(&old);
|
goto out2;
|
||||||
goto out1;
|
|
||||||
}
|
|
||||||
|
|
||||||
get_fs_root(current->fs, &root);
|
get_fs_root(current->fs, &root);
|
||||||
down_write(&namespace_sem);
|
error = lock_mount(&old);
|
||||||
mutex_lock(&old.dentry->d_inode->i_mutex);
|
if (error)
|
||||||
|
goto out3;
|
||||||
|
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
if (IS_MNT_SHARED(old.mnt) ||
|
if (IS_MNT_SHARED(old.mnt) ||
|
||||||
IS_MNT_SHARED(new.mnt->mnt_parent) ||
|
IS_MNT_SHARED(new.mnt->mnt_parent) ||
|
||||||
IS_MNT_SHARED(root.mnt->mnt_parent))
|
IS_MNT_SHARED(root.mnt->mnt_parent))
|
||||||
goto out2;
|
goto out4;
|
||||||
if (!check_mnt(root.mnt))
|
if (!check_mnt(root.mnt) || !check_mnt(new.mnt))
|
||||||
goto out2;
|
goto out4;
|
||||||
error = -ENOENT;
|
error = -ENOENT;
|
||||||
if (cant_mount(old.dentry))
|
|
||||||
goto out2;
|
|
||||||
if (d_unlinked(new.dentry))
|
if (d_unlinked(new.dentry))
|
||||||
goto out2;
|
goto out4;
|
||||||
if (d_unlinked(old.dentry))
|
if (d_unlinked(old.dentry))
|
||||||
goto out2;
|
goto out4;
|
||||||
error = -EBUSY;
|
error = -EBUSY;
|
||||||
if (new.mnt == root.mnt ||
|
if (new.mnt == root.mnt ||
|
||||||
old.mnt == root.mnt)
|
old.mnt == root.mnt)
|
||||||
goto out2; /* loop, on the same file system */
|
goto out4; /* loop, on the same file system */
|
||||||
error = -EINVAL;
|
error = -EINVAL;
|
||||||
if (root.mnt->mnt_root != root.dentry)
|
if (root.mnt->mnt_root != root.dentry)
|
||||||
goto out2; /* not a mountpoint */
|
goto out4; /* not a mountpoint */
|
||||||
if (root.mnt->mnt_parent == root.mnt)
|
if (root.mnt->mnt_parent == root.mnt)
|
||||||
goto out2; /* not attached */
|
goto out4; /* not attached */
|
||||||
if (new.mnt->mnt_root != new.dentry)
|
if (new.mnt->mnt_root != new.dentry)
|
||||||
goto out2; /* not a mountpoint */
|
goto out4; /* not a mountpoint */
|
||||||
if (new.mnt->mnt_parent == new.mnt)
|
if (new.mnt->mnt_parent == new.mnt)
|
||||||
goto out2; /* not attached */
|
goto out4; /* not attached */
|
||||||
/* make sure we can reach put_old from new_root */
|
/* make sure we can reach put_old from new_root */
|
||||||
tmp = old.mnt;
|
tmp = old.mnt;
|
||||||
br_write_lock(vfsmount_lock);
|
|
||||||
if (tmp != new.mnt) {
|
if (tmp != new.mnt) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (tmp->mnt_parent == tmp)
|
if (tmp->mnt_parent == tmp)
|
||||||
goto out3; /* already mounted on put_old */
|
goto out4; /* already mounted on put_old */
|
||||||
if (tmp->mnt_parent == new.mnt)
|
if (tmp->mnt_parent == new.mnt)
|
||||||
break;
|
break;
|
||||||
tmp = tmp->mnt_parent;
|
tmp = tmp->mnt_parent;
|
||||||
}
|
}
|
||||||
if (!is_subdir(tmp->mnt_mountpoint, new.dentry))
|
if (!is_subdir(tmp->mnt_mountpoint, new.dentry))
|
||||||
goto out3;
|
goto out4;
|
||||||
} else if (!is_subdir(old.dentry, new.dentry))
|
} else if (!is_subdir(old.dentry, new.dentry))
|
||||||
goto out3;
|
goto out4;
|
||||||
|
br_write_lock(vfsmount_lock);
|
||||||
detach_mnt(new.mnt, &parent_path);
|
detach_mnt(new.mnt, &parent_path);
|
||||||
detach_mnt(root.mnt, &root_parent);
|
detach_mnt(root.mnt, &root_parent);
|
||||||
/* mount old root on put_old */
|
/* mount old root on put_old */
|
||||||
@ -2578,22 +2645,21 @@ SYSCALL_DEFINE2(pivot_root, const char __user *, new_root,
|
|||||||
touch_mnt_namespace(current->nsproxy->mnt_ns);
|
touch_mnt_namespace(current->nsproxy->mnt_ns);
|
||||||
br_write_unlock(vfsmount_lock);
|
br_write_unlock(vfsmount_lock);
|
||||||
chroot_fs_refs(&root, &new);
|
chroot_fs_refs(&root, &new);
|
||||||
|
|
||||||
error = 0;
|
error = 0;
|
||||||
path_put(&root_parent);
|
out4:
|
||||||
path_put(&parent_path);
|
unlock_mount(&old);
|
||||||
out2:
|
if (!error) {
|
||||||
mutex_unlock(&old.dentry->d_inode->i_mutex);
|
path_put(&root_parent);
|
||||||
up_write(&namespace_sem);
|
path_put(&parent_path);
|
||||||
|
}
|
||||||
|
out3:
|
||||||
path_put(&root);
|
path_put(&root);
|
||||||
|
out2:
|
||||||
path_put(&old);
|
path_put(&old);
|
||||||
out1:
|
out1:
|
||||||
path_put(&new);
|
path_put(&new);
|
||||||
out0:
|
out0:
|
||||||
return error;
|
return error;
|
||||||
out3:
|
|
||||||
br_write_unlock(vfsmount_lock);
|
|
||||||
goto out2;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __init init_mount_tree(void)
|
static void __init init_mount_tree(void)
|
||||||
@ -2668,3 +2734,9 @@ void put_mnt_ns(struct mnt_namespace *ns)
|
|||||||
kfree(ns);
|
kfree(ns);
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(put_mnt_ns);
|
EXPORT_SYMBOL(put_mnt_ns);
|
||||||
|
|
||||||
|
struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
|
||||||
|
{
|
||||||
|
return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(kern_mount_data);
|
||||||
|
@ -87,7 +87,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp,
|
|||||||
.dentry = dget(dentry)};
|
.dentry = dget(dentry)};
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
err = follow_down(&path, false);
|
err = follow_down(&path);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -40,9 +40,29 @@
|
|||||||
struct pstore_private {
|
struct pstore_private {
|
||||||
u64 id;
|
u64 id;
|
||||||
int (*erase)(u64);
|
int (*erase)(u64);
|
||||||
|
ssize_t size;
|
||||||
|
char data[];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define pstore_get_inode ramfs_get_inode
|
static int pstore_file_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
file->private_data = inode->i_private;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static ssize_t pstore_file_read(struct file *file, char __user *userbuf,
|
||||||
|
size_t count, loff_t *ppos)
|
||||||
|
{
|
||||||
|
struct pstore_private *ps = file->private_data;
|
||||||
|
|
||||||
|
return simple_read_from_buffer(userbuf, count, ppos, ps->data, ps->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations pstore_file_operations = {
|
||||||
|
.open = pstore_file_open,
|
||||||
|
.read = pstore_file_read,
|
||||||
|
.llseek = default_llseek,
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When a file is unlinked from our file system we call the
|
* When a file is unlinked from our file system we call the
|
||||||
@ -63,6 +83,30 @@ static const struct inode_operations pstore_dir_inode_operations = {
|
|||||||
.unlink = pstore_unlink,
|
.unlink = pstore_unlink,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static struct inode *pstore_get_inode(struct super_block *sb,
|
||||||
|
const struct inode *dir, int mode, dev_t dev)
|
||||||
|
{
|
||||||
|
struct inode *inode = new_inode(sb);
|
||||||
|
|
||||||
|
if (inode) {
|
||||||
|
inode->i_ino = get_next_ino();
|
||||||
|
inode->i_uid = inode->i_gid = 0;
|
||||||
|
inode->i_mode = mode;
|
||||||
|
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|
||||||
|
switch (mode & S_IFMT) {
|
||||||
|
case S_IFREG:
|
||||||
|
inode->i_fop = &pstore_file_operations;
|
||||||
|
break;
|
||||||
|
case S_IFDIR:
|
||||||
|
inode->i_op = &pstore_dir_inode_operations;
|
||||||
|
inode->i_fop = &simple_dir_operations;
|
||||||
|
inc_nlink(inode);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inode;
|
||||||
|
}
|
||||||
|
|
||||||
static const struct super_operations pstore_ops = {
|
static const struct super_operations pstore_ops = {
|
||||||
.statfs = simple_statfs,
|
.statfs = simple_statfs,
|
||||||
.drop_inode = generic_delete_inode,
|
.drop_inode = generic_delete_inode,
|
||||||
@ -70,37 +114,10 @@ static const struct super_operations pstore_ops = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static struct super_block *pstore_sb;
|
static struct super_block *pstore_sb;
|
||||||
static struct vfsmount *pstore_mnt;
|
|
||||||
|
|
||||||
int pstore_is_mounted(void)
|
int pstore_is_mounted(void)
|
||||||
{
|
{
|
||||||
return pstore_mnt != NULL;
|
return pstore_sb != NULL;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set up a file structure as if we had opened this file and
|
|
||||||
* write our data to it.
|
|
||||||
*/
|
|
||||||
static int pstore_writefile(struct inode *inode, struct dentry *dentry,
|
|
||||||
char *data, size_t size)
|
|
||||||
{
|
|
||||||
struct file f;
|
|
||||||
ssize_t n;
|
|
||||||
mm_segment_t old_fs = get_fs();
|
|
||||||
|
|
||||||
memset(&f, '0', sizeof f);
|
|
||||||
f.f_mapping = inode->i_mapping;
|
|
||||||
f.f_path.dentry = dentry;
|
|
||||||
f.f_path.mnt = pstore_mnt;
|
|
||||||
f.f_pos = 0;
|
|
||||||
f.f_op = inode->i_fop;
|
|
||||||
set_fs(KERNEL_DS);
|
|
||||||
n = do_sync_write(&f, data, size, &f.f_pos);
|
|
||||||
set_fs(old_fs);
|
|
||||||
|
|
||||||
fsnotify_modify(&f);
|
|
||||||
|
|
||||||
return n == size;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -123,8 +140,7 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id,
|
|||||||
inode = pstore_get_inode(pstore_sb, root->d_inode, S_IFREG | 0444, 0);
|
inode = pstore_get_inode(pstore_sb, root->d_inode, S_IFREG | 0444, 0);
|
||||||
if (!inode)
|
if (!inode)
|
||||||
goto fail;
|
goto fail;
|
||||||
inode->i_uid = inode->i_gid = 0;
|
private = kmalloc(sizeof *private + size, GFP_KERNEL);
|
||||||
private = kmalloc(sizeof *private, GFP_KERNEL);
|
|
||||||
if (!private)
|
if (!private)
|
||||||
goto fail_alloc;
|
goto fail_alloc;
|
||||||
private->id = id;
|
private->id = id;
|
||||||
@ -152,28 +168,19 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id,
|
|||||||
if (IS_ERR(dentry))
|
if (IS_ERR(dentry))
|
||||||
goto fail_lockedalloc;
|
goto fail_lockedalloc;
|
||||||
|
|
||||||
d_add(dentry, inode);
|
memcpy(private->data, data, size);
|
||||||
|
inode->i_size = private->size = size;
|
||||||
mutex_unlock(&root->d_inode->i_mutex);
|
|
||||||
|
|
||||||
if (!pstore_writefile(inode, dentry, data, size))
|
|
||||||
goto fail_write;
|
|
||||||
|
|
||||||
inode->i_private = private;
|
inode->i_private = private;
|
||||||
|
|
||||||
if (time.tv_sec)
|
if (time.tv_sec)
|
||||||
inode->i_mtime = inode->i_ctime = time;
|
inode->i_mtime = inode->i_ctime = time;
|
||||||
|
|
||||||
return 0;
|
d_add(dentry, inode);
|
||||||
|
|
||||||
fail_write:
|
|
||||||
kfree(private);
|
|
||||||
inode->i_nlink--;
|
|
||||||
mutex_lock(&root->d_inode->i_mutex);
|
|
||||||
d_delete(dentry);
|
|
||||||
dput(dentry);
|
|
||||||
mutex_unlock(&root->d_inode->i_mutex);
|
mutex_unlock(&root->d_inode->i_mutex);
|
||||||
goto fail;
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
fail_lockedalloc:
|
fail_lockedalloc:
|
||||||
mutex_unlock(&root->d_inode->i_mutex);
|
mutex_unlock(&root->d_inode->i_mutex);
|
||||||
@ -225,32 +232,21 @@ fail:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int pstore_get_sb(struct file_system_type *fs_type,
|
static struct dentry *pstore_mount(struct file_system_type *fs_type,
|
||||||
int flags, const char *dev_name, void *data, struct vfsmount *mnt)
|
int flags, const char *dev_name, void *data)
|
||||||
{
|
{
|
||||||
struct dentry *root;
|
return mount_single(fs_type, flags, data, pstore_fill_super);
|
||||||
|
|
||||||
root = mount_nodev(fs_type, flags, data, pstore_fill_super);
|
|
||||||
if (IS_ERR(root))
|
|
||||||
return -ENOMEM;
|
|
||||||
|
|
||||||
mnt->mnt_root = root;
|
|
||||||
mnt->mnt_sb = root->d_sb;
|
|
||||||
pstore_mnt = mnt;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pstore_kill_sb(struct super_block *sb)
|
static void pstore_kill_sb(struct super_block *sb)
|
||||||
{
|
{
|
||||||
kill_litter_super(sb);
|
kill_litter_super(sb);
|
||||||
pstore_sb = NULL;
|
pstore_sb = NULL;
|
||||||
pstore_mnt = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct file_system_type pstore_fs_type = {
|
static struct file_system_type pstore_fs_type = {
|
||||||
.name = "pstore",
|
.name = "pstore",
|
||||||
.get_sb = pstore_get_sb,
|
.mount = pstore_mount,
|
||||||
.kill_sb = pstore_kill_sb,
|
.kill_sb = pstore_kill_sb,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
96
fs/super.c
96
fs/super.c
@ -910,29 +910,18 @@ struct dentry *mount_single(struct file_system_type *fs_type,
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL(mount_single);
|
EXPORT_SYMBOL(mount_single);
|
||||||
|
|
||||||
struct vfsmount *
|
struct dentry *
|
||||||
vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data)
|
mount_fs(struct file_system_type *type, int flags, const char *name, void *data)
|
||||||
{
|
{
|
||||||
struct vfsmount *mnt;
|
|
||||||
struct dentry *root;
|
struct dentry *root;
|
||||||
|
struct super_block *sb;
|
||||||
char *secdata = NULL;
|
char *secdata = NULL;
|
||||||
int error;
|
int error = -ENOMEM;
|
||||||
|
|
||||||
if (!type)
|
|
||||||
return ERR_PTR(-ENODEV);
|
|
||||||
|
|
||||||
error = -ENOMEM;
|
|
||||||
mnt = alloc_vfsmnt(name);
|
|
||||||
if (!mnt)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (flags & MS_KERNMOUNT)
|
|
||||||
mnt->mnt_flags = MNT_INTERNAL;
|
|
||||||
|
|
||||||
if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
|
if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
|
||||||
secdata = alloc_secdata();
|
secdata = alloc_secdata();
|
||||||
if (!secdata)
|
if (!secdata)
|
||||||
goto out_mnt;
|
goto out;
|
||||||
|
|
||||||
error = security_sb_copy_data(data, secdata);
|
error = security_sb_copy_data(data, secdata);
|
||||||
if (error)
|
if (error)
|
||||||
@ -944,13 +933,12 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
|
|||||||
error = PTR_ERR(root);
|
error = PTR_ERR(root);
|
||||||
goto out_free_secdata;
|
goto out_free_secdata;
|
||||||
}
|
}
|
||||||
mnt->mnt_root = root;
|
sb = root->d_sb;
|
||||||
mnt->mnt_sb = root->d_sb;
|
BUG_ON(!sb);
|
||||||
BUG_ON(!mnt->mnt_sb);
|
WARN_ON(!sb->s_bdi);
|
||||||
WARN_ON(!mnt->mnt_sb->s_bdi);
|
sb->s_flags |= MS_BORN;
|
||||||
mnt->mnt_sb->s_flags |= MS_BORN;
|
|
||||||
|
|
||||||
error = security_sb_kern_mount(mnt->mnt_sb, flags, secdata);
|
error = security_sb_kern_mount(sb, flags, secdata);
|
||||||
if (error)
|
if (error)
|
||||||
goto out_sb;
|
goto out_sb;
|
||||||
|
|
||||||
@ -961,27 +949,21 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
|
|||||||
* violate this rule. This warning should be either removed or
|
* violate this rule. This warning should be either removed or
|
||||||
* converted to a BUG() in 2.6.34.
|
* converted to a BUG() in 2.6.34.
|
||||||
*/
|
*/
|
||||||
WARN((mnt->mnt_sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "
|
WARN((sb->s_maxbytes < 0), "%s set sb->s_maxbytes to "
|
||||||
"negative value (%lld)\n", type->name, mnt->mnt_sb->s_maxbytes);
|
"negative value (%lld)\n", type->name, sb->s_maxbytes);
|
||||||
|
|
||||||
mnt->mnt_mountpoint = mnt->mnt_root;
|
up_write(&sb->s_umount);
|
||||||
mnt->mnt_parent = mnt;
|
|
||||||
up_write(&mnt->mnt_sb->s_umount);
|
|
||||||
free_secdata(secdata);
|
free_secdata(secdata);
|
||||||
return mnt;
|
return root;
|
||||||
out_sb:
|
out_sb:
|
||||||
dput(mnt->mnt_root);
|
dput(root);
|
||||||
deactivate_locked_super(mnt->mnt_sb);
|
deactivate_locked_super(sb);
|
||||||
out_free_secdata:
|
out_free_secdata:
|
||||||
free_secdata(secdata);
|
free_secdata(secdata);
|
||||||
out_mnt:
|
|
||||||
free_vfsmnt(mnt);
|
|
||||||
out:
|
out:
|
||||||
return ERR_PTR(error);
|
return ERR_PTR(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(vfs_kern_mount);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* freeze_super - lock the filesystem and force it into a consistent state
|
* freeze_super - lock the filesystem and force it into a consistent state
|
||||||
* @sb: the super to lock
|
* @sb: the super to lock
|
||||||
@ -1071,49 +1053,3 @@ out:
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(thaw_super);
|
EXPORT_SYMBOL(thaw_super);
|
||||||
|
|
||||||
static struct vfsmount *fs_set_subtype(struct vfsmount *mnt, const char *fstype)
|
|
||||||
{
|
|
||||||
int err;
|
|
||||||
const char *subtype = strchr(fstype, '.');
|
|
||||||
if (subtype) {
|
|
||||||
subtype++;
|
|
||||||
err = -EINVAL;
|
|
||||||
if (!subtype[0])
|
|
||||||
goto err;
|
|
||||||
} else
|
|
||||||
subtype = "";
|
|
||||||
|
|
||||||
mnt->mnt_sb->s_subtype = kstrdup(subtype, GFP_KERNEL);
|
|
||||||
err = -ENOMEM;
|
|
||||||
if (!mnt->mnt_sb->s_subtype)
|
|
||||||
goto err;
|
|
||||||
return mnt;
|
|
||||||
|
|
||||||
err:
|
|
||||||
mntput(mnt);
|
|
||||||
return ERR_PTR(err);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct vfsmount *
|
|
||||||
do_kern_mount(const char *fstype, int flags, const char *name, void *data)
|
|
||||||
{
|
|
||||||
struct file_system_type *type = get_fs_type(fstype);
|
|
||||||
struct vfsmount *mnt;
|
|
||||||
if (!type)
|
|
||||||
return ERR_PTR(-ENODEV);
|
|
||||||
mnt = vfs_kern_mount(type, flags, name, data);
|
|
||||||
if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
|
|
||||||
!mnt->mnt_sb->s_subtype)
|
|
||||||
mnt = fs_set_subtype(mnt, fstype);
|
|
||||||
put_filesystem(type);
|
|
||||||
return mnt;
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(do_kern_mount);
|
|
||||||
|
|
||||||
struct vfsmount *kern_mount_data(struct file_system_type *type, void *data)
|
|
||||||
{
|
|
||||||
return vfs_kern_mount(type, MS_KERNMOUNT, type->name, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
EXPORT_SYMBOL_GPL(kern_mount_data);
|
|
||||||
|
@ -168,7 +168,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, bool);
|
int (*d_manage)(struct dentry *, bool);
|
||||||
} ____cacheline_aligned;
|
} ____cacheline_aligned;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1839,7 +1839,6 @@ extern struct dentry *mount_pseudo(struct file_system_type *, char *,
|
|||||||
const struct super_operations *ops,
|
const struct super_operations *ops,
|
||||||
const struct dentry_operations *dops,
|
const struct dentry_operations *dops,
|
||||||
unsigned long);
|
unsigned long);
|
||||||
extern void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb);
|
|
||||||
|
|
||||||
static inline void sb_mark_dirty(struct super_block *sb)
|
static inline void sb_mark_dirty(struct super_block *sb)
|
||||||
{
|
{
|
||||||
|
@ -85,7 +85,7 @@ extern struct file *lookup_instantiate_filp(struct nameidata *nd, struct dentry
|
|||||||
extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
|
extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
|
||||||
|
|
||||||
extern int follow_down_one(struct path *);
|
extern int follow_down_one(struct path *);
|
||||||
extern int follow_down(struct path *, bool);
|
extern int follow_down(struct path *);
|
||||||
extern int follow_up(struct path *);
|
extern int follow_up(struct path *);
|
||||||
|
|
||||||
extern struct dentry *lock_rename(struct dentry *, struct dentry *);
|
extern struct dentry *lock_rename(struct dentry *, struct dentry *);
|
||||||
|
Loading…
Reference in New Issue
Block a user