Commit f539abec authored by Linus Torvalds's avatar Linus Torvalds

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()
parents 3f6f7e6d 24ff6663
...@@ -873,7 +873,7 @@ struct dentry_operations { ...@@ -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 { ...@@ -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); ...@@ -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 @@ static struct vfsmount *autofs4_d_automount(struct path *path) ...@@ -446,7 +446,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
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) ...@@ -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) ...@@ -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 @@ ...@@ -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 *); ...@@ -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); ...@@ -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) ...@@ -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, ...@@ -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 @@ static int follow_dotdot_rcu(struct nameidata *nd) ...@@ -1065,7 +1064,7 @@ static int follow_dotdot_rcu(struct nameidata *nd)
* 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) ...@@ -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;
} }
......
This diff is collapsed.
...@@ -87,7 +87,7 @@ nfsd_cross_mnt(struct svc_rqst *rqstp, struct dentry **dpp, ...@@ -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 @@ ...@@ -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 = { ...@@ -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 = { ...@@ -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, ...@@ -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, ...@@ -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 @@ int pstore_fill_super(struct super_block *sb, void *data, int silent) ...@@ -225,32 +232,21 @@ int pstore_fill_super(struct super_block *sb, void *data, int silent)
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,
}; };
......
...@@ -910,29 +910,18 @@ struct dentry *mount_single(struct file_system_type *fs_type, ...@@ -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 ...@@ -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 ...@@ -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 @@ int thaw_super(struct super_block *sb) ...@@ -1071,49 +1053,3 @@ int thaw_super(struct super_block *sb)
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 { ...@@ -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 *, ...@@ -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 ...@@ -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 *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment