lkml.org 
[lkml]   [2006]   [Mar]   [1]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subject[Fwd: [PATCH 1/5] NFS: Permit filesystem to override root dentry on mount [try #2]]
The attached patch extends the get_sb() filesystem operation to take an 
extra argument that permits the VFS to pass in the target vfsmount that
defines the mountpoint.

The filesystem is then required to manually set the superblock and root
dentry pointers. For most filesystems, this should be done with
simple_set_mnt() which will set the superblock pointer and then set the
root dentry to the superblock's s_root (as per the old default behaviour).

This patch permits a superblock to be implicitly shared amongst several
mount points, such as can be done with NFS to avoid potential inode
aliasing (see patch 5/5). In such a case, simple_set_mnt() would not be
called, and instead the mnt_root and mnt_sb would be set directly.

This patch also changes the superblock cleanup routine to make it use
shrink_dcache_sb() instead of shrink_dcache_parent() and
shrink_dcache_anon().
This required is because the superblock may now have multiple trees that
aren't actually bound to s_root, but that still need to be cleaned up.
The currently called functions assume that the whole tree is rooted at
s_root, and that anonymous dentries are not the roots of trees which
results in dentries being left unculled.

Signed-Off-By: David Howells <dhowells@redhat.com>
Acked-By: Sam Vilain <sam.vilain@catalyst.net.nz>
---
I find this one interesting, for the reason that it appears to be the
opposite of a bind mount. This is a "merge mount" :)

That is, with a bind mount, you are interested in getting a new vfsmnt
on a single mount structure, and having different options for that
vfsmnt. While I was looking through the vfs_rename function, it
occurred to me that this would make renames between bind mount areas
impossible, though it should be possible in principle as they are the
same underlying filesystem.

So, some positive feedback - not very useful I know - but perhaps it's
worth considering what happens in the above case; ie how does this play
with bind mounts, client side or server side?

Documentation/filesystems/porting | 2 -
fs/libfs.c | 12 +++--
fs/namespace.c | 9 ++++
fs/super.c | 87
++++++++++++++++++++-----------------
include/linux/fs.h | 25 ++++++-----
5 files changed, 77 insertions(+), 58 deletions(-)

diff --git a/Documentation/filesystems/porting
b/Documentation/filesystems/porting
index 2f38846..2de7a23 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -51,7 +51,7 @@ success and negative number in case of e
informative error value to report). Call it foo_fill_super(). Now
declare

struct super_block foo_get_sb(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
+ int flags, const char *dev_name, void *data, struct dentry **_root)
{
return get_sb_bdev(fs_type, flags, dev_name, data, ext2_fill_super);
}
diff --git a/fs/libfs.c b/fs/libfs.c
index 71fd08f..7a60a20 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -194,9 +194,9 @@ struct inode_operations simple_dir_inode
* Common helper for pseudo-filesystems (sockfs, pipefs, bdev - stuff that
* will never be mountable)
*/
-struct super_block *
-get_sb_pseudo(struct file_system_type *fs_type, char *name,
- struct super_operations *ops, unsigned long magic)
+int get_sb_pseudo(struct file_system_type *fs_type, char *name,
+ struct super_operations *ops, unsigned long magic,
+ struct vfsmount *mnt)
{
struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);
static struct super_operations default_ops = {.statfs = simple_statfs};
@@ -205,7 +205,7 @@ get_sb_pseudo(struct file_system_type *f
struct qstr d_name = {.name = name, .len = strlen(name)};

if (IS_ERR(s))
- return s;
+ return PTR_ERR(s);

s->s_flags = MS_NOUSER;
s->s_maxbytes = ~0ULL;
@@ -230,12 +230,12 @@ get_sb_pseudo(struct file_system_type *f
d_instantiate(dentry, root);
s->s_root = dentry;
s->s_flags |= MS_ACTIVE;
- return s;
+ return simple_set_mnt(mnt, s);

Enomem:
up_write(&s->s_umount);
deactivate_super(s);
- return ERR_PTR(-ENOMEM);
+ return -ENOMEM;
}

int simple_link(struct dentry *old_dentry, struct inode *dir, struct
dentry *dentry)
diff --git a/fs/namespace.c b/fs/namespace.c
index 058a448..51d3ebc 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -86,6 +86,15 @@ struct vfsmount *alloc_vfsmnt(const char
return mnt;
}

+int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb)
+{
+ mnt->mnt_sb = sb;
+ mnt->mnt_root = dget(sb->s_root);
+ return 0;
+}
+
+EXPORT_SYMBOL(simple_set_mnt);
+
void free_vfsmnt(struct vfsmount *mnt)
{
kfree(mnt->mnt_devname);
diff --git a/fs/super.c b/fs/super.c
index e20b558..7353011 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -230,8 +230,7 @@ void generic_shutdown_super(struct super

if (root) {
sb->s_root = NULL;
- shrink_dcache_parent(root);
- shrink_dcache_anon(&sb->s_anon);
+ shrink_dcache_sb(sb);
dput(root);
fsync_super(sb);
lock_super(sb);
@@ -676,9 +675,10 @@ static void bdev_uevent(struct block_dev
}
}

-struct super_block *get_sb_bdev(struct file_system_type *fs_type,
+int get_sb_bdev(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data,
- int (*fill_super)(struct super_block *, void *, int))
+ int (*fill_super)(struct super_block *, void *, int),
+ struct vfsmount *mnt)
{
struct block_device *bdev;
struct super_block *s;
@@ -686,7 +686,7 @@ struct super_block *get_sb_bdev(struct f

bdev = open_bdev_excl(dev_name, flags, fs_type);
if (IS_ERR(bdev))
- return (struct super_block *)bdev;
+ return PTR_ERR(bdev);

/*
* once the super is inserted into the list by sget, s_umount
@@ -697,13 +697,13 @@ struct super_block *get_sb_bdev(struct f
s = sget(fs_type, test_bdev_super, set_bdev_super, bdev);
up(&bdev->bd_mount_sem);
if (IS_ERR(s))
- goto out;
+ goto out_s_error;

if (s->s_root) {
if ((flags ^ s->s_flags) & MS_RDONLY) {
up_write(&s->s_umount);
deactivate_super(s);
- s = ERR_PTR(-EBUSY);
+ error = -EBUSY;
}
goto out;
} else {
@@ -716,18 +716,21 @@ struct super_block *get_sb_bdev(struct f
if (error) {
up_write(&s->s_umount);
deactivate_super(s);
- s = ERR_PTR(error);
- } else {
- s->s_flags |= MS_ACTIVE;
- bdev_uevent(bdev, KOBJ_MOUNT);
+ goto error;
}
+
+ s->s_flags |= MS_ACTIVE;
+ bdev_uevent(bdev, KOBJ_MOUNT);
}

- return s;
+ return simple_set_mnt(mnt, s);

+out_s_error:
+ error = PTR_ERR(s);
out:
close_bdev_excl(bdev);
- return s;
+error:
+ return error;
}

EXPORT_SYMBOL(get_sb_bdev);
@@ -744,15 +747,16 @@ void kill_block_super(struct super_block

EXPORT_SYMBOL(kill_block_super);

-struct super_block *get_sb_nodev(struct file_system_type *fs_type,
+int get_sb_nodev(struct file_system_type *fs_type,
int flags, void *data,
- int (*fill_super)(struct super_block *, void *, int))
+ int (*fill_super)(struct super_block *, void *, int),
+ struct vfsmount *mnt)
{
int error;
struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL);

if (IS_ERR(s))
- return s;
+ return PTR_ERR(s);

s->s_flags = flags;

@@ -760,10 +764,10 @@ struct super_block *get_sb_nodev(struct
if (error) {
up_write(&s->s_umount);
deactivate_super(s);
- return ERR_PTR(error);
+ return error;
}
s->s_flags |= MS_ACTIVE;
- return s;
+ return simple_set_mnt(mnt, s);
}

EXPORT_SYMBOL(get_sb_nodev);
@@ -773,28 +777,29 @@ static int compare_single(struct super_b
return 1;
}

-struct super_block *get_sb_single(struct file_system_type *fs_type,
+int get_sb_single(struct file_system_type *fs_type,
int flags, void *data,
- int (*fill_super)(struct super_block *, void *, int))
+ int (*fill_super)(struct super_block *, void *, int),
+ struct vfsmount *mnt)
{
struct super_block *s;
int error;

s = sget(fs_type, compare_single, set_anon_super, NULL);
if (IS_ERR(s))
- return s;
+ return PTR_ERR(s);
if (!s->s_root) {
s->s_flags = flags;
error = fill_super(s, data, flags & MS_VERBOSE ? 1 : 0);
if (error) {
up_write(&s->s_umount);
deactivate_super(s);
- return ERR_PTR(error);
+ return error;
}
s->s_flags |= MS_ACTIVE;
}
do_remount_sb(s, flags, data, 0);
- return s;
+ return simple_set_mnt(mnt, s);
}

EXPORT_SYMBOL(get_sb_single);
@@ -803,7 +808,6 @@ 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 super_block *sb = ERR_PTR(-ENOMEM);
struct vfsmount *mnt;
int error;
char *secdata = NULL;
@@ -811,49 +815,50 @@ do_kern_mount(const char *fstype, int fl
if (!type)
return ERR_PTR(-ENODEV);

+ error = -ENOMEM;
mnt = alloc_vfsmnt(name);
if (!mnt)
goto out;

if (data) {
secdata = alloc_secdata();
- if (!secdata) {
- sb = ERR_PTR(-ENOMEM);
+ if (!secdata)
goto out_mnt;
- }

error = security_sb_copy_data(type, data, secdata);
- if (error) {
- sb = ERR_PTR(error);
+ if (error)
goto out_free_secdata;
- }
}

- sb = type->get_sb(type, flags, name, data);
- if (IS_ERR(sb))
+ error = type->get_sb(type, flags, name, data, mnt);
+ if (error < 0)
goto out_free_secdata;
- error = security_sb_kern_mount(sb, secdata);
+
+ BUG_ON(!mnt->mnt_sb);
+ BUG_ON(!mnt->mnt_sb->s_root);
+ BUG_ON(!mnt->mnt_root);
+
+ error = security_sb_kern_mount(mnt->mnt_sb, secdata);
if (error)
goto out_sb;
- mnt->mnt_sb = sb;
- mnt->mnt_root = dget(sb->s_root);
- mnt->mnt_mountpoint = sb->s_root;
+
+ mnt->mnt_mountpoint = mnt->mnt_root;
mnt->mnt_parent = mnt;
- up_write(&sb->s_umount);
+ up_write(&mnt->mnt_sb->s_umount);
free_secdata(secdata);
put_filesystem(type);
return mnt;
out_sb:
- up_write(&sb->s_umount);
- deactivate_super(sb);
- sb = ERR_PTR(error);
+ dput(mnt->mnt_root);
+ up_write(&mnt->mnt_sb->s_umount);
+ deactivate_super(mnt->mnt_sb);
out_free_secdata:
free_secdata(secdata);
out_mnt:
free_vfsmnt(mnt);
out:
put_filesystem(type);
- return (struct vfsmount *)sb;
+ return ERR_PTR(error);
}

EXPORT_SYMBOL_GPL(do_kern_mount);
diff --git a/include/linux/fs.h b/include/linux/fs.h
index e059da9..4f5327a 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1239,23 +1239,26 @@ find_exported_dentry(struct super_block
struct file_system_type {
const char *name;
int fs_flags;
- struct super_block *(*get_sb) (struct file_system_type *, int,
- const char *, void *);
+ int (*get_sb) (struct file_system_type *, int,
+ const char *, void *, struct vfsmount *);
void (*kill_sb) (struct super_block *);
struct module *owner;
struct file_system_type * next;
struct list_head fs_supers;
};

-struct super_block *get_sb_bdev(struct file_system_type *fs_type,
+extern int get_sb_bdev(struct file_system_type *fs_type,
int flags, const char *dev_name, void *data,
- int (*fill_super)(struct super_block *, void *, int));
-struct super_block *get_sb_single(struct file_system_type *fs_type,
+ int (*fill_super)(struct super_block *, void *, int),
+ struct vfsmount *mnt);
+extern int get_sb_single(struct file_system_type *fs_type,
int flags, void *data,
- int (*fill_super)(struct super_block *, void *, int));
-struct super_block *get_sb_nodev(struct file_system_type *fs_type,
+ int (*fill_super)(struct super_block *, void *, int),
+ struct vfsmount *mnt);
+extern int get_sb_nodev(struct file_system_type *fs_type,
int flags, void *data,
- int (*fill_super)(struct super_block *, void *, int));
+ int (*fill_super)(struct super_block *, void *, int),
+ struct vfsmount *mnt);
void generic_shutdown_super(struct super_block *sb);
void kill_block_super(struct super_block *sb);
void kill_anon_super(struct super_block *sb);
@@ -1266,8 +1269,10 @@ struct super_block *sget(struct file_sys
int (*test)(struct super_block *,void *),
int (*set)(struct super_block *,void *),
void *data);
-struct super_block *get_sb_pseudo(struct file_system_type *, char *,
- struct super_operations *ops, unsigned long);
+extern int get_sb_pseudo(struct file_system_type *, char *,
+ struct super_operations *ops, unsigned long,
+ struct vfsmount *mnt);
+extern int simple_set_mnt(struct vfsmount *mnt, struct super_block *sb);
int __put_super(struct super_block *sb);
int __put_super_and_need_restart(struct super_block *sb);
void unnamed_dev_init(void);
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/

\
 
 \ /
  Last update: 2006-03-01 22:52    [W:1.062 / U:0.064 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site