diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 22:09:57 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-03-16 22:09:57 -0400 |
| commit | 054cfaacf88865bff1dd58d305443d5d6c068a08 (patch) | |
| tree | 39cd85f0f5966ed8c501740359b1d03d48f5ea41 | |
| parent | dc113c1f1d4b47af1b1ca701c5a39e24d296c2ac (diff) | |
| parent | 1a102ff92579edeff5e3d5d3c76ca49977898f00 (diff) | |
Merge branch 'mnt_devname' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'mnt_devname' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6:
vfs: bury ->get_sb()
nfs: switch NFS from ->get_sb() to ->mount()
nfs: stop mangling ->mnt_devname on NFS
vfs: new superblock methods to override /proc/*/mount{s,info}
nfs: nfs_do_{ref,sub}mount() superblock argument is redundant
nfs: make nfs_path() work without vfsmount
nfs: store devname at disconnected NFS roots
nfs: propagate devname to nfs{,4}_get_root()
| -rw-r--r-- | Documentation/filesystems/Locking | 6 | ||||
| -rw-r--r-- | Documentation/filesystems/porting | 7 | ||||
| -rw-r--r-- | Documentation/filesystems/vfs.txt | 56 | ||||
| -rw-r--r-- | fs/namespace.c | 39 | ||||
| -rw-r--r-- | fs/nfs/dir.c | 13 | ||||
| -rw-r--r-- | fs/nfs/getroot.c | 42 | ||||
| -rw-r--r-- | fs/nfs/internal.h | 21 | ||||
| -rw-r--r-- | fs/nfs/namespace.c | 66 | ||||
| -rw-r--r-- | fs/nfs/nfs4namespace.c | 41 | ||||
| -rw-r--r-- | fs/nfs/super.c | 194 | ||||
| -rw-r--r-- | fs/nfs/unlink.c | 20 | ||||
| -rw-r--r-- | fs/super.c | 67 | ||||
| -rw-r--r-- | include/linux/fs.h | 16 |
13 files changed, 316 insertions, 272 deletions
diff --git a/Documentation/filesystems/Locking b/Documentation/filesystems/Locking index 4471a416c274..2e994efe12cb 100644 --- a/Documentation/filesystems/Locking +++ b/Documentation/filesystems/Locking | |||
| @@ -166,13 +166,11 @@ prototypes: | |||
| 166 | void (*kill_sb) (struct super_block *); | 166 | void (*kill_sb) (struct super_block *); |
| 167 | locking rules: | 167 | locking rules: |
| 168 | may block | 168 | may block |
| 169 | get_sb yes | ||
| 170 | mount yes | 169 | mount yes |
| 171 | kill_sb yes | 170 | kill_sb yes |
| 172 | 171 | ||
| 173 | ->get_sb() returns error or 0 with locked superblock attached to the vfsmount | 172 | ->mount() returns ERR_PTR or the root dentry; its superblock should be locked |
| 174 | (exclusive on ->s_umount). | 173 | on return. |
| 175 | ->mount() returns ERR_PTR or the root dentry. | ||
| 176 | ->kill_sb() takes a write-locked superblock, does all shutdown work on it, | 174 | ->kill_sb() takes a write-locked superblock, does all shutdown work on it, |
| 177 | unlocks and drops the reference. | 175 | unlocks and drops the reference. |
| 178 | 176 | ||
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index dfbcd1b00b0a..0c986c9e8519 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting | |||
| @@ -394,3 +394,10 @@ file) you must return -EOPNOTSUPP if FALLOC_FL_PUNCH_HOLE is set in mode. | |||
| 394 | Currently you can only have FALLOC_FL_PUNCH_HOLE with FALLOC_FL_KEEP_SIZE set, | 394 | Currently you can only have FALLOC_FL_PUNCH_HOLE with FALLOC_FL_KEEP_SIZE set, |
| 395 | so the i_size should not change when hole punching, even when puching the end of | 395 | so the i_size should not change when hole punching, even when puching the end of |
| 396 | a file off. | 396 | a file off. |
| 397 | |||
| 398 | -- | ||
| 399 | [mandatory] | ||
| 400 | ->get_sb() is gone. Switch to use of ->mount(). Typically it's just | ||
| 401 | a matter of switching from calling get_sb_... to mount_... and changing the | ||
| 402 | function type. If you were doing it manually, just switch from setting ->mnt_root | ||
| 403 | to some pointer to returning that pointer. On errors return ERR_PTR(...). | ||
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt index 94cf97b901d7..ef0714aa8e40 100644 --- a/Documentation/filesystems/vfs.txt +++ b/Documentation/filesystems/vfs.txt | |||
| @@ -95,10 +95,11 @@ functions: | |||
| 95 | extern int unregister_filesystem(struct file_system_type *); | 95 | extern int unregister_filesystem(struct file_system_type *); |
| 96 | 96 | ||
| 97 | The passed struct file_system_type describes your filesystem. When a | 97 | The passed struct file_system_type describes your filesystem. When a |
| 98 | request is made to mount a device onto a directory in your filespace, | 98 | request is made to mount a filesystem onto a directory in your namespace, |
| 99 | the VFS will call the appropriate get_sb() method for the specific | 99 | the VFS will call the appropriate mount() method for the specific |
| 100 | filesystem. The dentry for the mount point will then be updated to | 100 | filesystem. New vfsmount refering to the tree returned by ->mount() |
| 101 | point to the root inode for the new filesystem. | 101 | will be attached to the mountpoint, so that when pathname resolution |
| 102 | reaches the mountpoint it will jump into the root of that vfsmount. | ||
| 102 | 103 | ||
| 103 | You can see all filesystems that are registered to the kernel in the | 104 | You can see all filesystems that are registered to the kernel in the |
| 104 | file /proc/filesystems. | 105 | file /proc/filesystems. |
| @@ -107,14 +108,14 @@ file /proc/filesystems. | |||
| 107 | struct file_system_type | 108 | struct file_system_type |
| 108 | ----------------------- | 109 | ----------------------- |
| 109 | 110 | ||
| 110 | This describes the filesystem. As of kernel 2.6.22, the following | 111 | This describes the filesystem. As of kernel 2.6.39, the following |
| 111 | members are defined: | 112 | members are defined: |
| 112 | 113 | ||
| 113 | struct file_system_type { | 114 | struct file_system_type { |
| 114 | const char *name; | 115 | const char *name; |
| 115 | int fs_flags; | 116 | int fs_flags; |
| 116 | int (*get_sb) (struct file_system_type *, int, | 117 | struct dentry (*mount) (struct file_system_type *, int, |
| 117 | const char *, void *, struct vfsmount *); | 118 | const char *, void *); |
| 118 | void (*kill_sb) (struct super_block *); | 119 | void (*kill_sb) (struct super_block *); |
| 119 | struct module *owner; | 120 | struct module *owner; |
| 120 | struct file_system_type * next; | 121 | struct file_system_type * next; |
| @@ -128,11 +129,11 @@ struct file_system_type { | |||
| 128 | 129 | ||
| 129 | fs_flags: various flags (i.e. FS_REQUIRES_DEV, FS_NO_DCACHE, etc.) | 130 | fs_flags: various flags (i.e. FS_REQUIRES_DEV, FS_NO_DCACHE, etc.) |
| 130 | 131 | ||
| 131 | get_sb: the method to call when a new instance of this | 132 | mount: the method to call when a new instance of this |
| 132 | filesystem should be mounted | 133 | filesystem should be mounted |
| 133 | 134 | ||
| 134 | kill_sb: the method to call when an instance of this filesystem | 135 | kill_sb: the method to call when an instance of this filesystem |
| 135 | should be unmounted | 136 | should be shut down |
| 136 | 137 | ||
| 137 | owner: for internal VFS use: you should initialize this to THIS_MODULE in | 138 | owner: for internal VFS use: you should initialize this to THIS_MODULE in |
| 138 | most cases. | 139 | most cases. |
| @@ -141,7 +142,7 @@ struct file_system_type { | |||
| 141 | 142 | ||
| 142 | s_lock_key, s_umount_key: lockdep-specific | 143 | s_lock_key, s_umount_key: lockdep-specific |
| 143 | 144 | ||
| 144 | The get_sb() method has the following arguments: | 145 | The mount() method has the following arguments: |
| 145 | 146 | ||
| 146 | struct file_system_type *fs_type: describes the filesystem, partly initialized | 147 | struct file_system_type *fs_type: describes the filesystem, partly initialized |
| 147 | by the specific filesystem code | 148 | by the specific filesystem code |
| @@ -153,32 +154,39 @@ The get_sb() method has the following arguments: | |||
| 153 | void *data: arbitrary mount options, usually comes as an ASCII | 154 | void *data: arbitrary mount options, usually comes as an ASCII |
| 154 | string (see "Mount Options" section) | 155 | string (see "Mount Options" section) |
| 155 | 156 | ||
| 156 | struct vfsmount *mnt: a vfs-internal representation of a mount point | 157 | The mount() method must return the root dentry of the tree requested by |
| 158 | caller. An active reference to its superblock must be grabbed and the | ||
| 159 | superblock must be locked. On failure it should return ERR_PTR(error). | ||
| 157 | 160 | ||
| 158 | The get_sb() method must determine if the block device specified | 161 | The arguments match those of mount(2) and their interpretation |
| 159 | in the dev_name and fs_type contains a filesystem of the type the method | 162 | depends on filesystem type. E.g. for block filesystems, dev_name is |
| 160 | supports. If it succeeds in opening the named block device, it initializes a | 163 | interpreted as block device name, that device is opened and if it |
| 161 | struct super_block descriptor for the filesystem contained by the block device. | 164 | contains a suitable filesystem image the method creates and initializes |
| 162 | On failure it returns an error. | 165 | struct super_block accordingly, returning its root dentry to caller. |
| 166 | |||
| 167 | ->mount() may choose to return a subtree of existing filesystem - it | ||
| 168 | doesn't have to create a new one. The main result from the caller's | ||
| 169 | point of view is a reference to dentry at the root of (sub)tree to | ||
| 170 | be attached; creation of new superblock is a common side effect. | ||
| 163 | 171 | ||
| 164 | The most interesting member of the superblock structure that the | 172 | The most interesting member of the superblock structure that the |
| 165 | get_sb() method fills in is the "s_op" field. This is a pointer to | 173 | mount() method fills in is the "s_op" field. This is a pointer to |
| 166 | a "struct super_operations" which describes the next level of the | 174 | a "struct super_operations" which describes the next level of the |
| 167 | filesystem implementation. | 175 | filesystem implementation. |
| 168 | 176 | ||
| 169 | Usually, a filesystem uses one of the generic get_sb() implementations | 177 | Usually, a filesystem uses one of the generic mount() implementations |
| 170 | and provides a fill_super() method instead. The generic methods are: | 178 | and provides a fill_super() callback instead. The generic variants are: |
| 171 | 179 | ||
| 172 | get_sb_bdev: mount a filesystem residing on a block device | 180 | mount_bdev: mount a filesystem residing on a block device |
| 173 | 181 | ||
| 174 | get_sb_nodev: mount a filesystem that is not backed by a device | 182 | mount_nodev: mount a filesystem that is not backed by a device |
| 175 | 183 | ||
| 176 | get_sb_single: mount a filesystem which shares the instance between | 184 | mount_single: mount a filesystem which shares the instance between |
| 177 | all mounts | 185 | all mounts |
| 178 | 186 | ||
| 179 | A fill_super() method implementation has the following arguments: | 187 | A fill_super() callback implementation has the following arguments: |
| 180 | 188 | ||
| 181 | struct super_block *sb: the superblock structure. The method fill_super() | 189 | struct super_block *sb: the superblock structure. The callback |
| 182 | must initialize this properly. | 190 | must initialize this properly. |
| 183 | 191 | ||
| 184 | void *data: arbitrary mount options, usually comes as an ASCII | 192 | void *data: arbitrary mount options, usually comes as an ASCII |
diff --git a/fs/namespace.c b/fs/namespace.c index e96e03782def..d7513485c1f3 100644 --- a/fs/namespace.c +++ b/fs/namespace.c | |||
| @@ -978,7 +978,13 @@ static int show_vfsmnt(struct seq_file *m, void *v) | |||
| 978 | int err = 0; | 978 | int err = 0; |
| 979 | struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; | 979 | struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; |
| 980 | 980 | ||
| 981 | mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); | 981 | if (mnt->mnt_sb->s_op->show_devname) { |
| 982 | err = mnt->mnt_sb->s_op->show_devname(m, mnt); | ||
| 983 | if (err) | ||
| 984 | goto out; | ||
| 985 | } else { | ||
| 986 | mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); | ||
| 987 | } | ||
| 982 | seq_putc(m, ' '); | 988 | seq_putc(m, ' '); |
| 983 | seq_path(m, &mnt_path, " \t\n\\"); | 989 | seq_path(m, &mnt_path, " \t\n\\"); |
| 984 | seq_putc(m, ' '); | 990 | seq_putc(m, ' '); |
| @@ -1025,7 +1031,12 @@ static int show_mountinfo(struct seq_file *m, void *v) | |||
| 1025 | 1031 | ||
| 1026 | seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id, | 1032 | seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id, |
| 1027 | MAJOR(sb->s_dev), MINOR(sb->s_dev)); | 1033 | MAJOR(sb->s_dev), MINOR(sb->s_dev)); |
| 1028 | seq_dentry(m, mnt->mnt_root, " \t\n\\"); | 1034 | if (sb->s_op->show_path) |
| 1035 | err = sb->s_op->show_path(m, mnt); | ||
| 1036 | else | ||
| 1037 | seq_dentry(m, mnt->mnt_root, " \t\n\\"); | ||
| 1038 | if (err) | ||
| 1039 | goto out; | ||
| 1029 | seq_putc(m, ' '); | 1040 | seq_putc(m, ' '); |
| 1030 | seq_path_root(m, &mnt_path, &root, " \t\n\\"); | 1041 | seq_path_root(m, &mnt_path, &root, " \t\n\\"); |
| 1031 | if (root.mnt != p->root.mnt || root.dentry != p->root.dentry) { | 1042 | if (root.mnt != p->root.mnt || root.dentry != p->root.dentry) { |
| @@ -1060,7 +1071,12 @@ static int show_mountinfo(struct seq_file *m, void *v) | |||
| 1060 | seq_puts(m, " - "); | 1071 | seq_puts(m, " - "); |
| 1061 | show_type(m, sb); | 1072 | show_type(m, sb); |
| 1062 | seq_putc(m, ' '); | 1073 | seq_putc(m, ' '); |
| 1063 | mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); | 1074 | if (sb->s_op->show_devname) |
| 1075 | err = sb->s_op->show_devname(m, mnt); | ||
| 1076 | else | ||
| 1077 | mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); | ||
| 1078 | if (err) | ||
| 1079 | goto out; | ||
| 1064 | seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw"); | 1080 | seq_puts(m, sb->s_flags & MS_RDONLY ? " ro" : " rw"); |
| 1065 | err = show_sb_opts(m, sb); | 1081 | err = show_sb_opts(m, sb); |
| 1066 | if (err) | 1082 | if (err) |
| @@ -1086,11 +1102,15 @@ static int show_vfsstat(struct seq_file *m, void *v) | |||
| 1086 | int err = 0; | 1102 | int err = 0; |
| 1087 | 1103 | ||
| 1088 | /* device */ | 1104 | /* device */ |
| 1089 | if (mnt->mnt_devname) { | 1105 | if (mnt->mnt_sb->s_op->show_devname) { |
| 1090 | seq_puts(m, "device "); | 1106 | err = mnt->mnt_sb->s_op->show_devname(m, mnt); |
| 1091 | mangle(m, mnt->mnt_devname); | 1107 | } else { |
| 1092 | } else | 1108 | if (mnt->mnt_devname) { |
| 1093 | seq_puts(m, "no device"); | 1109 | seq_puts(m, "device "); |
| 1110 | mangle(m, mnt->mnt_devname); | ||
| 1111 | } else | ||
| 1112 | seq_puts(m, "no device"); | ||
| 1113 | } | ||
| 1094 | 1114 | ||
| 1095 | /* mount point */ | 1115 | /* mount point */ |
| 1096 | seq_puts(m, " mounted on "); | 1116 | seq_puts(m, " mounted on "); |
| @@ -1104,7 +1124,8 @@ static int show_vfsstat(struct seq_file *m, void *v) | |||
| 1104 | /* optional statistics */ | 1124 | /* optional statistics */ |
| 1105 | if (mnt->mnt_sb->s_op->show_stats) { | 1125 | if (mnt->mnt_sb->s_op->show_stats) { |
| 1106 | seq_putc(m, ' '); | 1126 | seq_putc(m, ' '); |
| 1107 | err = mnt->mnt_sb->s_op->show_stats(m, mnt); | 1127 | if (!err) |
| 1128 | err = mnt->mnt_sb->s_op->show_stats(m, mnt); | ||
| 1108 | } | 1129 | } |
| 1109 | 1130 | ||
| 1110 | seq_putc(m, '\n'); | 1131 | seq_putc(m, '\n'); |
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index 2c3eb33b904d..abdf38d5971d 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c | |||
| @@ -1169,11 +1169,23 @@ static void nfs_dentry_iput(struct dentry *dentry, struct inode *inode) | |||
| 1169 | iput(inode); | 1169 | iput(inode); |
| 1170 | } | 1170 | } |
| 1171 | 1171 | ||
| 1172 | static void nfs_d_release(struct dentry *dentry) | ||
| 1173 | { | ||
| 1174 | /* free cached devname value, if it survived that far */ | ||
| 1175 | if (unlikely(dentry->d_fsdata)) { | ||
| 1176 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) | ||
| 1177 | WARN_ON(1); | ||
| 1178 | else | ||
| 1179 | kfree(dentry->d_fsdata); | ||
| 1180 | } | ||
| 1181 | } | ||
| 1182 | |||
| 1172 | const struct dentry_operations nfs_dentry_operations = { | 1183 | const struct dentry_operations nfs_dentry_operations = { |
| 1173 | .d_revalidate = nfs_lookup_revalidate, | 1184 | .d_revalidate = nfs_lookup_revalidate, |
| 1174 | .d_delete = nfs_dentry_delete, | 1185 | .d_delete = nfs_dentry_delete, |
| 1175 | .d_iput = nfs_dentry_iput, | 1186 | .d_iput = nfs_dentry_iput, |
| 1176 | .d_automount = nfs_d_automount, | 1187 | .d_automount = nfs_d_automount, |
| 1188 | .d_release = nfs_d_release, | ||
| 1177 | }; | 1189 | }; |
| 1178 | 1190 | ||
| 1179 | static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) | 1191 | static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) |
| @@ -1248,6 +1260,7 @@ const struct dentry_operations nfs4_dentry_operations = { | |||
| 1248 | .d_delete = nfs_dentry_delete, | 1260 | .d_delete = nfs_dentry_delete, |
| 1249 | .d_iput = nfs_dentry_iput, | 1261 | .d_iput = nfs_dentry_iput, |
| 1250 | .d_automount = nfs_d_automount, | 1262 | .d_automount = nfs_d_automount, |
| 1263 | .d_release = nfs_d_release, | ||
| 1251 | }; | 1264 | }; |
| 1252 | 1265 | ||
| 1253 | /* | 1266 | /* |
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index b5ffe8fa291f..1084792bc0fe 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
| @@ -75,18 +75,25 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i | |||
| 75 | /* | 75 | /* |
| 76 | * get an NFS2/NFS3 root dentry from the root filehandle | 76 | * get an NFS2/NFS3 root dentry from the root filehandle |
| 77 | */ | 77 | */ |
| 78 | struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | 78 | struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh, |
| 79 | const char *devname) | ||
| 79 | { | 80 | { |
| 80 | struct nfs_server *server = NFS_SB(sb); | 81 | struct nfs_server *server = NFS_SB(sb); |
| 81 | struct nfs_fsinfo fsinfo; | 82 | struct nfs_fsinfo fsinfo; |
| 82 | struct dentry *ret; | 83 | struct dentry *ret; |
| 83 | struct inode *inode; | 84 | struct inode *inode; |
| 85 | void *name = kstrdup(devname, GFP_KERNEL); | ||
| 84 | int error; | 86 | int error; |
| 85 | 87 | ||
| 88 | if (!name) | ||
| 89 | return ERR_PTR(-ENOMEM); | ||
| 90 | |||
| 86 | /* get the actual root for this mount */ | 91 | /* get the actual root for this mount */ |
| 87 | fsinfo.fattr = nfs_alloc_fattr(); | 92 | fsinfo.fattr = nfs_alloc_fattr(); |
| 88 | if (fsinfo.fattr == NULL) | 93 | if (fsinfo.fattr == NULL) { |
| 94 | kfree(name); | ||
| 89 | return ERR_PTR(-ENOMEM); | 95 | return ERR_PTR(-ENOMEM); |
| 96 | } | ||
| 90 | 97 | ||
| 91 | error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); | 98 | error = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); |
| 92 | if (error < 0) { | 99 | if (error < 0) { |
| @@ -119,7 +126,15 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
| 119 | } | 126 | } |
| 120 | 127 | ||
| 121 | security_d_instantiate(ret, inode); | 128 | security_d_instantiate(ret, inode); |
| 129 | spin_lock(&ret->d_lock); | ||
| 130 | if (IS_ROOT(ret) && !(ret->d_flags & DCACHE_NFSFS_RENAMED)) { | ||
| 131 | ret->d_fsdata = name; | ||
| 132 | name = NULL; | ||
| 133 | } | ||
| 134 | spin_unlock(&ret->d_lock); | ||
| 122 | out: | 135 | out: |
| 136 | if (name) | ||
| 137 | kfree(name); | ||
| 123 | nfs_free_fattr(fsinfo.fattr); | 138 | nfs_free_fattr(fsinfo.fattr); |
| 124 | return ret; | 139 | return ret; |
| 125 | } | 140 | } |
| @@ -169,27 +184,35 @@ out: | |||
| 169 | /* | 184 | /* |
| 170 | * get an NFS4 root dentry from the root filehandle | 185 | * get an NFS4 root dentry from the root filehandle |
| 171 | */ | 186 | */ |
| 172 | struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | 187 | struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh, |
| 188 | const char *devname) | ||
| 173 | { | 189 | { |
| 174 | struct nfs_server *server = NFS_SB(sb); | 190 | struct nfs_server *server = NFS_SB(sb); |
| 175 | struct nfs_fattr *fattr = NULL; | 191 | struct nfs_fattr *fattr = NULL; |
| 176 | struct dentry *ret; | 192 | struct dentry *ret; |
| 177 | struct inode *inode; | 193 | struct inode *inode; |
| 194 | void *name = kstrdup(devname, GFP_KERNEL); | ||
| 178 | int error; | 195 | int error; |
| 179 | 196 | ||
| 180 | dprintk("--> nfs4_get_root()\n"); | 197 | dprintk("--> nfs4_get_root()\n"); |
| 181 | 198 | ||
| 199 | if (!name) | ||
| 200 | return ERR_PTR(-ENOMEM); | ||
| 201 | |||
| 182 | /* get the info about the server and filesystem */ | 202 | /* get the info about the server and filesystem */ |
| 183 | error = nfs4_server_capabilities(server, mntfh); | 203 | error = nfs4_server_capabilities(server, mntfh); |
| 184 | if (error < 0) { | 204 | if (error < 0) { |
| 185 | dprintk("nfs_get_root: getcaps error = %d\n", | 205 | dprintk("nfs_get_root: getcaps error = %d\n", |
| 186 | -error); | 206 | -error); |
| 207 | kfree(name); | ||
| 187 | return ERR_PTR(error); | 208 | return ERR_PTR(error); |
| 188 | } | 209 | } |
| 189 | 210 | ||
| 190 | fattr = nfs_alloc_fattr(); | 211 | fattr = nfs_alloc_fattr(); |
| 191 | if (fattr == NULL) | 212 | if (fattr == NULL) { |
| 192 | return ERR_PTR(-ENOMEM);; | 213 | kfree(name); |
| 214 | return ERR_PTR(-ENOMEM); | ||
| 215 | } | ||
| 193 | 216 | ||
| 194 | /* get the actual root for this mount */ | 217 | /* get the actual root for this mount */ |
| 195 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr); | 218 | error = server->nfs_client->rpc_ops->getattr(server, mntfh, fattr); |
| @@ -223,8 +246,15 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
| 223 | } | 246 | } |
| 224 | 247 | ||
| 225 | security_d_instantiate(ret, inode); | 248 | security_d_instantiate(ret, inode); |
| 226 | 249 | spin_lock(&ret->d_lock); | |
| 250 | if (IS_ROOT(ret) && !(ret->d_flags & DCACHE_NFSFS_RENAMED)) { | ||
| 251 | ret->d_fsdata = name; | ||
| 252 | name = NULL; | ||
| 253 | } | ||
| 254 | spin_unlock(&ret->d_lock); | ||
| 227 | out: | 255 | out: |
| 256 | if (name) | ||
| 257 | kfree(name); | ||
| 228 | nfs_free_fattr(fattr); | 258 | nfs_free_fattr(fattr); |
| 229 | dprintk("<-- nfs4_get_root()\n"); | 259 | dprintk("<-- nfs4_get_root()\n"); |
| 230 | return ret; | 260 | return ret; |
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index cf9fdbdabc67..e94ad22da5d2 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -163,10 +163,10 @@ static inline void nfs_fs_proc_exit(void) | |||
| 163 | 163 | ||
| 164 | /* nfs4namespace.c */ | 164 | /* nfs4namespace.c */ |
| 165 | #ifdef CONFIG_NFS_V4 | 165 | #ifdef CONFIG_NFS_V4 |
| 166 | extern struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry); | 166 | extern struct vfsmount *nfs_do_refmount(struct dentry *dentry); |
| 167 | #else | 167 | #else |
| 168 | static inline | 168 | static inline |
| 169 | struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) | 169 | struct vfsmount *nfs_do_refmount(struct dentry *dentry) |
| 170 | { | 170 | { |
| 171 | return ERR_PTR(-ENOENT); | 171 | return ERR_PTR(-ENOENT); |
| 172 | } | 172 | } |
| @@ -247,16 +247,16 @@ extern void nfs_sb_active(struct super_block *sb); | |||
| 247 | extern void nfs_sb_deactive(struct super_block *sb); | 247 | extern void nfs_sb_deactive(struct super_block *sb); |
| 248 | 248 | ||
| 249 | /* namespace.c */ | 249 | /* namespace.c */ |
| 250 | extern char *nfs_path(const char *base, | 250 | extern char *nfs_path(char **p, struct dentry *dentry, |
| 251 | const struct dentry *droot, | ||
| 252 | const struct dentry *dentry, | ||
| 253 | char *buffer, ssize_t buflen); | 251 | char *buffer, ssize_t buflen); |
| 254 | extern struct vfsmount *nfs_d_automount(struct path *path); | 252 | extern struct vfsmount *nfs_d_automount(struct path *path); |
| 255 | 253 | ||
| 256 | /* getroot.c */ | 254 | /* getroot.c */ |
| 257 | extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *); | 255 | extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *, |
| 256 | const char *); | ||
| 258 | #ifdef CONFIG_NFS_V4 | 257 | #ifdef CONFIG_NFS_V4 |
| 259 | extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *); | 258 | extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *, |
| 259 | const char *); | ||
| 260 | 260 | ||
| 261 | extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh); | 261 | extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh); |
| 262 | #endif | 262 | #endif |
| @@ -288,12 +288,11 @@ extern int _nfs4_call_sync_session(struct nfs_server *server, | |||
| 288 | /* | 288 | /* |
| 289 | * Determine the device name as a string | 289 | * Determine the device name as a string |
| 290 | */ | 290 | */ |
| 291 | static inline char *nfs_devname(const struct vfsmount *mnt_parent, | 291 | static inline char *nfs_devname(struct dentry *dentry, |
| 292 | const struct dentry *dentry, | ||
| 293 | char *buffer, ssize_t buflen) | 292 | char *buffer, ssize_t buflen) |
| 294 | { | 293 | { |
| 295 | return nfs_path(mnt_parent->mnt_devname, mnt_parent->mnt_root, | 294 | char *dummy; |
| 296 | dentry, buffer, buflen); | 295 | return nfs_path(&dummy, dentry, buffer, buflen); |
| 297 | } | 296 | } |
| 298 | 297 | ||
| 299 | /* | 298 | /* |
diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index f32b8603dca8..c0b8344db0c6 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c | |||
| @@ -25,33 +25,30 @@ static LIST_HEAD(nfs_automount_list); | |||
| 25 | static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts); | 25 | static DECLARE_DELAYED_WORK(nfs_automount_task, nfs_expire_automounts); |
| 26 | int nfs_mountpoint_expiry_timeout = 500 * HZ; | 26 | int nfs_mountpoint_expiry_timeout = 500 * HZ; |
| 27 | 27 | ||
| 28 | static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, | 28 | static struct vfsmount *nfs_do_submount(struct dentry *dentry, |
| 29 | const struct dentry *dentry, | ||
| 30 | struct nfs_fh *fh, | 29 | struct nfs_fh *fh, |
| 31 | struct nfs_fattr *fattr); | 30 | struct nfs_fattr *fattr); |
| 32 | 31 | ||
| 33 | /* | 32 | /* |
| 34 | * nfs_path - reconstruct the path given an arbitrary dentry | 33 | * nfs_path - reconstruct the path given an arbitrary dentry |
| 35 | * @base - arbitrary string to prepend to the path | 34 | * @base - used to return pointer to the end of devname part of path |
| 36 | * @droot - pointer to root dentry for mountpoint | ||
| 37 | * @dentry - pointer to dentry | 35 | * @dentry - pointer to dentry |
| 38 | * @buffer - result buffer | 36 | * @buffer - result buffer |
| 39 | * @buflen - length of buffer | 37 | * @buflen - length of buffer |
| 40 | * | 38 | * |
| 41 | * Helper function for constructing the path from the | 39 | * Helper function for constructing the server pathname |
| 42 | * root dentry to an arbitrary hashed dentry. | 40 | * by arbitrary hashed dentry. |
| 43 | * | 41 | * |
| 44 | * This is mainly for use in figuring out the path on the | 42 | * This is mainly for use in figuring out the path on the |
| 45 | * server side when automounting on top of an existing partition. | 43 | * server side when automounting on top of an existing partition |
| 44 | * and in generating /proc/mounts and friends. | ||
| 46 | */ | 45 | */ |
| 47 | char *nfs_path(const char *base, | 46 | char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen) |
| 48 | const struct dentry *droot, | ||
| 49 | const struct dentry *dentry, | ||
| 50 | char *buffer, ssize_t buflen) | ||
| 51 | { | 47 | { |
| 52 | char *end; | 48 | char *end; |
| 53 | int namelen; | 49 | int namelen; |
| 54 | unsigned seq; | 50 | unsigned seq; |
| 51 | const char *base; | ||
| 55 | 52 | ||
| 56 | rename_retry: | 53 | rename_retry: |
| 57 | end = buffer+buflen; | 54 | end = buffer+buflen; |
| @@ -60,7 +57,10 @@ rename_retry: | |||
| 60 | 57 | ||
| 61 | seq = read_seqbegin(&rename_lock); | 58 | seq = read_seqbegin(&rename_lock); |
| 62 | rcu_read_lock(); | 59 | rcu_read_lock(); |
| 63 | while (!IS_ROOT(dentry) && dentry != droot) { | 60 | while (1) { |
| 61 | spin_lock(&dentry->d_lock); | ||
| 62 | if (IS_ROOT(dentry)) | ||
| 63 | break; | ||
| 64 | namelen = dentry->d_name.len; | 64 | namelen = dentry->d_name.len; |
| 65 | buflen -= namelen + 1; | 65 | buflen -= namelen + 1; |
| 66 | if (buflen < 0) | 66 | if (buflen < 0) |
| @@ -68,27 +68,47 @@ rename_retry: | |||
| 68 | end -= namelen; | 68 | end -= namelen; |
| 69 | memcpy(end, dentry->d_name.name, namelen); | 69 | memcpy(end, dentry->d_name.name, namelen); |
| 70 | *--end = '/'; | 70 | *--end = '/'; |
| 71 | spin_unlock(&dentry->d_lock); | ||
| 71 | dentry = dentry->d_parent; | 72 | dentry = dentry->d_parent; |
| 72 | } | 73 | } |
| 73 | rcu_read_unlock(); | 74 | if (read_seqretry(&rename_lock, seq)) { |
| 74 | if (read_seqretry(&rename_lock, seq)) | 75 | spin_unlock(&dentry->d_lock); |
| 76 | rcu_read_unlock(); | ||
| 75 | goto rename_retry; | 77 | goto rename_retry; |
| 78 | } | ||
| 76 | if (*end != '/') { | 79 | if (*end != '/') { |
| 77 | if (--buflen < 0) | 80 | if (--buflen < 0) { |
| 81 | spin_unlock(&dentry->d_lock); | ||
| 82 | rcu_read_unlock(); | ||
| 78 | goto Elong; | 83 | goto Elong; |
| 84 | } | ||
| 79 | *--end = '/'; | 85 | *--end = '/'; |
| 80 | } | 86 | } |
| 87 | *p = end; | ||
| 88 | base = dentry->d_fsdata; | ||
| 89 | if (!base) { | ||
| 90 | spin_unlock(&dentry->d_lock); | ||
| 91 | rcu_read_unlock(); | ||
| 92 | WARN_ON(1); | ||
| 93 | return end; | ||
| 94 | } | ||
| 81 | namelen = strlen(base); | 95 | namelen = strlen(base); |
| 82 | /* Strip off excess slashes in base string */ | 96 | /* Strip off excess slashes in base string */ |
| 83 | while (namelen > 0 && base[namelen - 1] == '/') | 97 | while (namelen > 0 && base[namelen - 1] == '/') |
| 84 | namelen--; | 98 | namelen--; |
| 85 | buflen -= namelen; | 99 | buflen -= namelen; |
| 86 | if (buflen < 0) | 100 | if (buflen < 0) { |
| 101 | spin_lock(&dentry->d_lock); | ||
| 102 | rcu_read_unlock(); | ||
| 87 | goto Elong; | 103 | goto Elong; |
| 104 | } | ||
| 88 | end -= namelen; | 105 | end -= namelen; |
| 89 | memcpy(end, base, namelen); | 106 | memcpy(end, base, namelen); |
| 107 | spin_unlock(&dentry->d_lock); | ||
| 108 | rcu_read_unlock(); | ||
| 90 | return end; | 109 | return end; |
| 91 | Elong_unlock: | 110 | Elong_unlock: |
| 111 | spin_lock(&dentry->d_lock); | ||
| 92 | rcu_read_unlock(); | 112 | rcu_read_unlock(); |
| 93 | if (read_seqretry(&rename_lock, seq)) | 113 | if (read_seqretry(&rename_lock, seq)) |
| 94 | goto rename_retry; | 114 | goto rename_retry; |
| @@ -143,9 +163,9 @@ struct vfsmount *nfs_d_automount(struct path *path) | |||
| 143 | } | 163 | } |
| 144 | 164 | ||
| 145 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) | 165 | if (fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) |
| 146 | mnt = nfs_do_refmount(path->mnt, path->dentry); | 166 | mnt = nfs_do_refmount(path->dentry); |
| 147 | else | 167 | else |
| 148 | mnt = nfs_do_submount(path->mnt, path->dentry, fh, fattr); | 168 | mnt = nfs_do_submount(path->dentry, fh, fattr); |
| 149 | if (IS_ERR(mnt)) | 169 | if (IS_ERR(mnt)) |
| 150 | goto out; | 170 | goto out; |
| 151 | 171 | ||
| @@ -209,19 +229,17 @@ static struct vfsmount *nfs_do_clone_mount(struct nfs_server *server, | |||
| 209 | 229 | ||
| 210 | /** | 230 | /** |
| 211 | * nfs_do_submount - set up mountpoint when crossing a filesystem boundary | 231 | * nfs_do_submount - set up mountpoint when crossing a filesystem boundary |
| 212 | * @mnt_parent - mountpoint of parent directory | ||
| 213 | * @dentry - parent directory | 232 | * @dentry - parent directory |
| 214 | * @fh - filehandle for new root dentry | 233 | * @fh - filehandle for new root dentry |
| 215 | * @fattr - attributes for new root inode | 234 | * @fattr - attributes for new root inode |
| 216 | * | 235 | * |
| 217 | */ | 236 | */ |
| 218 | static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, | 237 | static struct vfsmount *nfs_do_submount(struct dentry *dentry, |
| 219 | const struct dentry *dentry, | ||
| 220 | struct nfs_fh *fh, | 238 | struct nfs_fh *fh, |
| 221 | struct nfs_fattr *fattr) | 239 | struct nfs_fattr *fattr) |
| 222 | { | 240 | { |
| 223 | struct nfs_clone_mount mountdata = { | 241 | struct nfs_clone_mount mountdata = { |
| 224 | .sb = mnt_parent->mnt_sb, | 242 | .sb = dentry->d_sb, |
| 225 | .dentry = dentry, | 243 | .dentry = dentry, |
| 226 | .fh = fh, | 244 | .fh = fh, |
| 227 | .fattr = fattr, | 245 | .fattr = fattr, |
| @@ -237,11 +255,11 @@ static struct vfsmount *nfs_do_submount(const struct vfsmount *mnt_parent, | |||
| 237 | dentry->d_name.name); | 255 | dentry->d_name.name); |
| 238 | if (page == NULL) | 256 | if (page == NULL) |
| 239 | goto out; | 257 | goto out; |
| 240 | devname = nfs_devname(mnt_parent, dentry, page, PAGE_SIZE); | 258 | devname = nfs_devname(dentry, page, PAGE_SIZE); |
| 241 | mnt = (struct vfsmount *)devname; | 259 | mnt = (struct vfsmount *)devname; |
| 242 | if (IS_ERR(devname)) | 260 | if (IS_ERR(devname)) |
| 243 | goto free_page; | 261 | goto free_page; |
| 244 | mnt = nfs_do_clone_mount(NFS_SB(mnt_parent->mnt_sb), devname, &mountdata); | 262 | mnt = nfs_do_clone_mount(NFS_SB(dentry->d_sb), devname, &mountdata); |
| 245 | free_page: | 263 | free_page: |
| 246 | free_page((unsigned long)page); | 264 | free_page((unsigned long)page); |
| 247 | out: | 265 | out: |
diff --git a/fs/nfs/nfs4namespace.c b/fs/nfs/nfs4namespace.c index 3c2a1724fbd2..bb80c49b6533 100644 --- a/fs/nfs/nfs4namespace.c +++ b/fs/nfs/nfs4namespace.c | |||
| @@ -54,33 +54,29 @@ Elong: | |||
| 54 | /* | 54 | /* |
| 55 | * Determine the mount path as a string | 55 | * Determine the mount path as a string |
| 56 | */ | 56 | */ |
| 57 | static char *nfs4_path(const struct vfsmount *mnt_parent, | 57 | static char *nfs4_path(struct dentry *dentry, char *buffer, ssize_t buflen) |
| 58 | const struct dentry *dentry, | ||
| 59 | char *buffer, ssize_t buflen) | ||
| 60 | { | 58 | { |
| 61 | const char *srvpath; | 59 | char *limit; |
| 62 | 60 | char *path = nfs_path(&limit, dentry, buffer, buflen); | |
| 63 | srvpath = strchr(mnt_parent->mnt_devname, ':'); | 61 | if (!IS_ERR(path)) { |
| 64 | if (srvpath) | 62 | char *colon = strchr(path, ':'); |
| 65 | srvpath++; | 63 | if (colon && colon < limit) |
| 66 | else | 64 | path = colon + 1; |
| 67 | srvpath = mnt_parent->mnt_devname; | 65 | } |
| 68 | 66 | return path; | |
| 69 | return nfs_path(srvpath, mnt_parent->mnt_root, dentry, buffer, buflen); | ||
| 70 | } | 67 | } |
| 71 | 68 | ||
| 72 | /* | 69 | /* |
| 73 | * Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we | 70 | * Check that fs_locations::fs_root [RFC3530 6.3] is a prefix for what we |
| 74 | * believe to be the server path to this dentry | 71 | * believe to be the server path to this dentry |
| 75 | */ | 72 | */ |
| 76 | static int nfs4_validate_fspath(const struct vfsmount *mnt_parent, | 73 | static int nfs4_validate_fspath(struct dentry *dentry, |
| 77 | const struct dentry *dentry, | ||
| 78 | const struct nfs4_fs_locations *locations, | 74 | const struct nfs4_fs_locations *locations, |
| 79 | char *page, char *page2) | 75 | char *page, char *page2) |
| 80 | { | 76 | { |
| 81 | const char *path, *fs_path; | 77 | const char *path, *fs_path; |
| 82 | 78 | ||
| 83 | path = nfs4_path(mnt_parent, dentry, page, PAGE_SIZE); | 79 | path = nfs4_path(dentry, page, PAGE_SIZE); |
| 84 | if (IS_ERR(path)) | 80 | if (IS_ERR(path)) |
| 85 | return PTR_ERR(path); | 81 | return PTR_ERR(path); |
| 86 | 82 | ||
| @@ -165,20 +161,18 @@ static struct vfsmount *try_location(struct nfs_clone_mount *mountdata, | |||
| 165 | 161 | ||
| 166 | /** | 162 | /** |
| 167 | * nfs_follow_referral - set up mountpoint when hitting a referral on moved error | 163 | * nfs_follow_referral - set up mountpoint when hitting a referral on moved error |
| 168 | * @mnt_parent - mountpoint of parent directory | ||
| 169 | * @dentry - parent directory | 164 | * @dentry - parent directory |
| 170 | * @locations - array of NFSv4 server location information | 165 | * @locations - array of NFSv4 server location information |
| 171 | * | 166 | * |
| 172 | */ | 167 | */ |
| 173 | static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | 168 | static struct vfsmount *nfs_follow_referral(struct dentry *dentry, |
| 174 | const struct dentry *dentry, | ||
| 175 | const struct nfs4_fs_locations *locations) | 169 | const struct nfs4_fs_locations *locations) |
| 176 | { | 170 | { |
| 177 | struct vfsmount *mnt = ERR_PTR(-ENOENT); | 171 | struct vfsmount *mnt = ERR_PTR(-ENOENT); |
| 178 | struct nfs_clone_mount mountdata = { | 172 | struct nfs_clone_mount mountdata = { |
| 179 | .sb = mnt_parent->mnt_sb, | 173 | .sb = dentry->d_sb, |
| 180 | .dentry = dentry, | 174 | .dentry = dentry, |
| 181 | .authflavor = NFS_SB(mnt_parent->mnt_sb)->client->cl_auth->au_flavor, | 175 | .authflavor = NFS_SB(dentry->d_sb)->client->cl_auth->au_flavor, |
| 182 | }; | 176 | }; |
| 183 | char *page = NULL, *page2 = NULL; | 177 | char *page = NULL, *page2 = NULL; |
| 184 | int loc, error; | 178 | int loc, error; |
| @@ -198,7 +192,7 @@ static struct vfsmount *nfs_follow_referral(const struct vfsmount *mnt_parent, | |||
| 198 | goto out; | 192 | goto out; |
| 199 | 193 | ||
| 200 | /* Ensure fs path is a prefix of current dentry path */ | 194 | /* Ensure fs path is a prefix of current dentry path */ |
| 201 | error = nfs4_validate_fspath(mnt_parent, dentry, locations, page, page2); | 195 | error = nfs4_validate_fspath(dentry, locations, page, page2); |
| 202 | if (error < 0) { | 196 | if (error < 0) { |
| 203 | mnt = ERR_PTR(error); | 197 | mnt = ERR_PTR(error); |
| 204 | goto out; | 198 | goto out; |
| @@ -225,11 +219,10 @@ out: | |||
| 225 | 219 | ||
| 226 | /* | 220 | /* |
| 227 | * nfs_do_refmount - handle crossing a referral on server | 221 | * nfs_do_refmount - handle crossing a referral on server |
| 228 | * @mnt_parent - mountpoint of referral | ||
| 229 | * @dentry - dentry of referral | 222 | * @dentry - dentry of referral |
| 230 | * | 223 | * |
| 231 | */ | 224 | */ |
| 232 | struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentry *dentry) | 225 | struct vfsmount *nfs_do_refmount(struct dentry *dentry) |
| 233 | { | 226 | { |
| 234 | struct vfsmount *mnt = ERR_PTR(-ENOMEM); | 227 | struct vfsmount *mnt = ERR_PTR(-ENOMEM); |
| 235 | struct dentry *parent; | 228 | struct dentry *parent; |
| @@ -262,7 +255,7 @@ struct vfsmount *nfs_do_refmount(const struct vfsmount *mnt_parent, struct dentr | |||
| 262 | fs_locations->fs_path.ncomponents <= 0) | 255 | fs_locations->fs_path.ncomponents <= 0) |
| 263 | goto out_free; | 256 | goto out_free; |
| 264 | 257 | ||
| 265 | mnt = nfs_follow_referral(mnt_parent, dentry, fs_locations); | 258 | mnt = nfs_follow_referral(dentry, fs_locations); |
| 266 | out_free: | 259 | out_free: |
| 267 | __free_page(page); | 260 | __free_page(page); |
| 268 | kfree(fs_locations); | 261 | kfree(fs_locations); |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index b68c8607770f..d3286583009a 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -263,8 +263,11 @@ static match_table_t nfs_local_lock_tokens = { | |||
| 263 | static void nfs_umount_begin(struct super_block *); | 263 | static void nfs_umount_begin(struct super_block *); |
| 264 | static int nfs_statfs(struct dentry *, struct kstatfs *); | 264 | static int nfs_statfs(struct dentry *, struct kstatfs *); |
| 265 | static int nfs_show_options(struct seq_file *, struct vfsmount *); | 265 | static int nfs_show_options(struct seq_file *, struct vfsmount *); |
| 266 | static int nfs_show_devname(struct seq_file *, struct vfsmount *); | ||
| 267 | static int nfs_show_path(struct seq_file *, struct vfsmount *); | ||
| 266 | static int nfs_show_stats(struct seq_file *, struct vfsmount *); | 268 | static int nfs_show_stats(struct seq_file *, struct vfsmount *); |
| 267 | static int nfs_get_sb(struct file_system_type *, int, const char *, void *, struct vfsmount *); | 269 | static struct dentry *nfs_fs_mount(struct file_system_type *, |
| 270 | int, const char *, void *); | ||
| 268 | static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type, | 271 | static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type, |
| 269 | int flags, const char *dev_name, void *raw_data); | 272 | int flags, const char *dev_name, void *raw_data); |
| 270 | static void nfs_put_super(struct super_block *); | 273 | static void nfs_put_super(struct super_block *); |
| @@ -274,7 +277,7 @@ static int nfs_remount(struct super_block *sb, int *flags, char *raw_data); | |||
| 274 | static struct file_system_type nfs_fs_type = { | 277 | static struct file_system_type nfs_fs_type = { |
| 275 | .owner = THIS_MODULE, | 278 | .owner = THIS_MODULE, |
| 276 | .name = "nfs", | 279 | .name = "nfs", |
| 277 | .get_sb = nfs_get_sb, | 280 | .mount = nfs_fs_mount, |
| 278 | .kill_sb = nfs_kill_super, | 281 | .kill_sb = nfs_kill_super, |
| 279 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 282 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
| 280 | }; | 283 | }; |
| @@ -296,6 +299,8 @@ static const struct super_operations nfs_sops = { | |||
| 296 | .evict_inode = nfs_evict_inode, | 299 | .evict_inode = nfs_evict_inode, |
| 297 | .umount_begin = nfs_umount_begin, | 300 | .umount_begin = nfs_umount_begin, |
| 298 | .show_options = nfs_show_options, | 301 | .show_options = nfs_show_options, |
| 302 | .show_devname = nfs_show_devname, | ||
| 303 | .show_path = nfs_show_path, | ||
| 299 | .show_stats = nfs_show_stats, | 304 | .show_stats = nfs_show_stats, |
| 300 | .remount_fs = nfs_remount, | 305 | .remount_fs = nfs_remount, |
| 301 | }; | 306 | }; |
| @@ -303,16 +308,16 @@ static const struct super_operations nfs_sops = { | |||
| 303 | #ifdef CONFIG_NFS_V4 | 308 | #ifdef CONFIG_NFS_V4 |
| 304 | static int nfs4_validate_text_mount_data(void *options, | 309 | static int nfs4_validate_text_mount_data(void *options, |
| 305 | struct nfs_parsed_mount_data *args, const char *dev_name); | 310 | struct nfs_parsed_mount_data *args, const char *dev_name); |
| 306 | static int nfs4_try_mount(int flags, const char *dev_name, | 311 | static struct dentry *nfs4_try_mount(int flags, const char *dev_name, |
| 307 | struct nfs_parsed_mount_data *data, struct vfsmount *mnt); | 312 | struct nfs_parsed_mount_data *data); |
| 308 | static int nfs4_get_sb(struct file_system_type *fs_type, | 313 | static struct dentry *nfs4_mount(struct file_system_type *fs_type, |
| 309 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 314 | int flags, const char *dev_name, void *raw_data); |
| 310 | static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type, | 315 | static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type, |
| 311 | int flags, const char *dev_name, void *raw_data); | 316 | int flags, const char *dev_name, void *raw_data); |
| 312 | static struct dentry *nfs4_xdev_mount(struct file_system_type *fs_type, | 317 | static struct dentry *nfs4_xdev_mount(struct file_system_type *fs_type, |
| 313 | int flags, const char *dev_name, void *raw_data); | 318 | int flags, const char *dev_name, void *raw_data); |
| 314 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, | 319 | static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, |
| 315 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt); | 320 | int flags, const char *dev_name, void *raw_data); |
| 316 | static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type, | 321 | static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type, |
| 317 | int flags, const char *dev_name, void *raw_data); | 322 | int flags, const char *dev_name, void *raw_data); |
| 318 | static void nfs4_kill_super(struct super_block *sb); | 323 | static void nfs4_kill_super(struct super_block *sb); |
| @@ -320,7 +325,7 @@ static void nfs4_kill_super(struct super_block *sb); | |||
| 320 | static struct file_system_type nfs4_fs_type = { | 325 | static struct file_system_type nfs4_fs_type = { |
| 321 | .owner = THIS_MODULE, | 326 | .owner = THIS_MODULE, |
| 322 | .name = "nfs4", | 327 | .name = "nfs4", |
| 323 | .get_sb = nfs4_get_sb, | 328 | .mount = nfs4_mount, |
| 324 | .kill_sb = nfs4_kill_super, | 329 | .kill_sb = nfs4_kill_super, |
| 325 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 330 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
| 326 | }; | 331 | }; |
| @@ -352,7 +357,7 @@ static struct file_system_type nfs4_remote_referral_fs_type = { | |||
| 352 | struct file_system_type nfs4_referral_fs_type = { | 357 | struct file_system_type nfs4_referral_fs_type = { |
| 353 | .owner = THIS_MODULE, | 358 | .owner = THIS_MODULE, |
| 354 | .name = "nfs4", | 359 | .name = "nfs4", |
| 355 | .get_sb = nfs4_referral_get_sb, | 360 | .mount = nfs4_referral_mount, |
| 356 | .kill_sb = nfs4_kill_super, | 361 | .kill_sb = nfs4_kill_super, |
| 357 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | 362 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, |
| 358 | }; | 363 | }; |
| @@ -366,6 +371,8 @@ static const struct super_operations nfs4_sops = { | |||
| 366 | .evict_inode = nfs4_evict_inode, | 371 | .evict_inode = nfs4_evict_inode, |
| 367 | .umount_begin = nfs_umount_begin, | 372 | .umount_begin = nfs_umount_begin, |
| 368 | .show_options = nfs_show_options, | 373 | .show_options = nfs_show_options, |
| 374 | .show_devname = nfs_show_devname, | ||
| 375 | .show_path = nfs_show_path, | ||
| 369 | .show_stats = nfs_show_stats, | 376 | .show_stats = nfs_show_stats, |
| 370 | .remount_fs = nfs_remount, | 377 | .remount_fs = nfs_remount, |
| 371 | }; | 378 | }; |
| @@ -726,6 +733,28 @@ static int nfs_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
| 726 | return 0; | 733 | return 0; |
| 727 | } | 734 | } |
| 728 | 735 | ||
| 736 | static int nfs_show_devname(struct seq_file *m, struct vfsmount *mnt) | ||
| 737 | { | ||
| 738 | char *page = (char *) __get_free_page(GFP_KERNEL); | ||
| 739 | char *devname, *dummy; | ||
| 740 | int err = 0; | ||
| 741 | if (!page) | ||
| 742 | return -ENOMEM; | ||
| 743 | devname = nfs_path(&dummy, mnt->mnt_root, page, PAGE_SIZE); | ||
| 744 | if (IS_ERR(devname)) | ||
| 745 | err = PTR_ERR(devname); | ||
| 746 | else | ||
| 747 | seq_escape(m, devname, " \t\n\\"); | ||
| 748 | free_page((unsigned long)page); | ||
| 749 | return err; | ||
| 750 | } | ||
| 751 | |||
| 752 | static int nfs_show_path(struct seq_file *m, struct vfsmount *mnt) | ||
| 753 | { | ||
| 754 | seq_puts(m, "/"); | ||
| 755 | return 0; | ||
| 756 | } | ||
| 757 | |||
| 729 | /* | 758 | /* |
| 730 | * Present statistical information for this VFS mountpoint | 759 | * Present statistical information for this VFS mountpoint |
| 731 | */ | 760 | */ |
| @@ -2267,19 +2296,19 @@ static int nfs_bdi_register(struct nfs_server *server) | |||
| 2267 | return bdi_register_dev(&server->backing_dev_info, server->s_dev); | 2296 | return bdi_register_dev(&server->backing_dev_info, server->s_dev); |
| 2268 | } | 2297 | } |
| 2269 | 2298 | ||
| 2270 | static int nfs_get_sb(struct file_system_type *fs_type, | 2299 | static struct dentry *nfs_fs_mount(struct file_system_type *fs_type, |
| 2271 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 2300 | int flags, const char *dev_name, void *raw_data) |
| 2272 | { | 2301 | { |
| 2273 | struct nfs_server *server = NULL; | 2302 | struct nfs_server *server = NULL; |
| 2274 | struct super_block *s; | 2303 | struct super_block *s; |
| 2275 | struct nfs_parsed_mount_data *data; | 2304 | struct nfs_parsed_mount_data *data; |
| 2276 | struct nfs_fh *mntfh; | 2305 | struct nfs_fh *mntfh; |
| 2277 | struct dentry *mntroot; | 2306 | struct dentry *mntroot = ERR_PTR(-ENOMEM); |
| 2278 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; | 2307 | int (*compare_super)(struct super_block *, void *) = nfs_compare_super; |
| 2279 | struct nfs_sb_mountdata sb_mntdata = { | 2308 | struct nfs_sb_mountdata sb_mntdata = { |
| 2280 | .mntflags = flags, | 2309 | .mntflags = flags, |
| 2281 | }; | 2310 | }; |
| 2282 | int error = -ENOMEM; | 2311 | int error; |
| 2283 | 2312 | ||
| 2284 | data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION); | 2313 | data = nfs_alloc_parsed_mount_data(NFS_DEFAULT_VERSION); |
| 2285 | mntfh = nfs_alloc_fhandle(); | 2314 | mntfh = nfs_alloc_fhandle(); |
| @@ -2290,12 +2319,14 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
| 2290 | 2319 | ||
| 2291 | /* Validate the mount data */ | 2320 | /* Validate the mount data */ |
| 2292 | error = nfs_validate_mount_data(raw_data, data, mntfh, dev_name); | 2321 | error = nfs_validate_mount_data(raw_data, data, mntfh, dev_name); |
| 2293 | if (error < 0) | 2322 | if (error < 0) { |
| 2323 | mntroot = ERR_PTR(error); | ||
| 2294 | goto out; | 2324 | goto out; |
| 2325 | } | ||
| 2295 | 2326 | ||
| 2296 | #ifdef CONFIG_NFS_V4 | 2327 | #ifdef CONFIG_NFS_V4 |
| 2297 | if (data->version == 4) { | 2328 | if (data->version == 4) { |
| 2298 | error = nfs4_try_mount(flags, dev_name, data, mnt); | 2329 | mntroot = nfs4_try_mount(flags, dev_name, data); |
| 2299 | kfree(data->client_address); | 2330 | kfree(data->client_address); |
| 2300 | kfree(data->nfs_server.export_path); | 2331 | kfree(data->nfs_server.export_path); |
| 2301 | goto out; | 2332 | goto out; |
| @@ -2305,7 +2336,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
| 2305 | /* Get a volume representation */ | 2336 | /* Get a volume representation */ |
| 2306 | server = nfs_create_server(data, mntfh); | 2337 | server = nfs_create_server(data, mntfh); |
| 2307 | if (IS_ERR(server)) { | 2338 | if (IS_ERR(server)) { |
| 2308 | error = PTR_ERR(server); | 2339 | mntroot = ERR_CAST(server); |
| 2309 | goto out; | 2340 | goto out; |
| 2310 | } | 2341 | } |
| 2311 | sb_mntdata.server = server; | 2342 | sb_mntdata.server = server; |
| @@ -2316,7 +2347,7 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
| 2316 | /* Get a superblock - note that we may end up sharing one that already exists */ | 2347 | /* Get a superblock - note that we may end up sharing one that already exists */ |
| 2317 | s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata); | 2348 | s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata); |
| 2318 | if (IS_ERR(s)) { | 2349 | if (IS_ERR(s)) { |
| 2319 | error = PTR_ERR(s); | 2350 | mntroot = ERR_CAST(s); |
| 2320 | goto out_err_nosb; | 2351 | goto out_err_nosb; |
| 2321 | } | 2352 | } |
| 2322 | 2353 | ||
| @@ -2325,8 +2356,10 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
| 2325 | server = NULL; | 2356 | server = NULL; |
| 2326 | } else { | 2357 | } else { |
| 2327 | error = nfs_bdi_register(server); | 2358 | error = nfs_bdi_register(server); |
| 2328 | if (error) | 2359 | if (error) { |
| 2360 | mntroot = ERR_PTR(error); | ||
| 2329 | goto error_splat_bdi; | 2361 | goto error_splat_bdi; |
| 2362 | } | ||
| 2330 | } | 2363 | } |
| 2331 | 2364 | ||
| 2332 | if (!s->s_root) { | 2365 | if (!s->s_root) { |
| @@ -2336,20 +2369,15 @@ static int nfs_get_sb(struct file_system_type *fs_type, | |||
| 2336 | s, data ? data->fscache_uniq : NULL, NULL); | 2369 | s, data ? data->fscache_uniq : NULL, NULL); |
| 2337 | } | 2370 | } |
| 2338 | 2371 | ||
| 2339 | mntroot = nfs_get_root(s, mntfh); | 2372 | mntroot = nfs_get_root(s, mntfh, dev_name); |
| 2340 | if (IS_ERR(mntroot)) { | 2373 | if (IS_ERR(mntroot)) |
| 2341 | error = PTR_ERR(mntroot); | ||
| 2342 | goto error_splat_super; | 2374 | goto error_splat_super; |
| 2343 | } | ||
| 2344 | 2375 | ||
| 2345 | error = security_sb_set_mnt_opts(s, &data->lsm_opts); | 2376 | error = security_sb_set_mnt_opts(s, &data->lsm_opts); |
| 2346 | if (error) | 2377 | if (error) |
| 2347 | goto error_splat_root; | 2378 | goto error_splat_root; |
| 2348 | 2379 | ||
| 2349 | s->s_flags |= MS_ACTIVE; | 2380 | s->s_flags |= MS_ACTIVE; |
| 2350 | mnt->mnt_sb = s; | ||
| 2351 | mnt->mnt_root = mntroot; | ||
| 2352 | error = 0; | ||
| 2353 | 2381 | ||
| 2354 | out: | 2382 | out: |
| 2355 | kfree(data->nfs_server.hostname); | 2383 | kfree(data->nfs_server.hostname); |
| @@ -2359,7 +2387,7 @@ out: | |||
| 2359 | out_free_fh: | 2387 | out_free_fh: |
| 2360 | nfs_free_fhandle(mntfh); | 2388 | nfs_free_fhandle(mntfh); |
| 2361 | kfree(data); | 2389 | kfree(data); |
| 2362 | return error; | 2390 | return mntroot; |
| 2363 | 2391 | ||
| 2364 | out_err_nosb: | 2392 | out_err_nosb: |
| 2365 | nfs_free_server(server); | 2393 | nfs_free_server(server); |
| @@ -2367,6 +2395,7 @@ out_err_nosb: | |||
| 2367 | 2395 | ||
| 2368 | error_splat_root: | 2396 | error_splat_root: |
| 2369 | dput(mntroot); | 2397 | dput(mntroot); |
| 2398 | mntroot = ERR_PTR(error); | ||
| 2370 | error_splat_super: | 2399 | error_splat_super: |
| 2371 | if (server && !s->s_root) | 2400 | if (server && !s->s_root) |
| 2372 | bdi_unregister(&server->backing_dev_info); | 2401 | bdi_unregister(&server->backing_dev_info); |
| @@ -2450,7 +2479,7 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags, | |||
| 2450 | nfs_fscache_get_super_cookie(s, NULL, data); | 2479 | nfs_fscache_get_super_cookie(s, NULL, data); |
| 2451 | } | 2480 | } |
| 2452 | 2481 | ||
| 2453 | mntroot = nfs_get_root(s, data->fh); | 2482 | mntroot = nfs_get_root(s, data->fh, dev_name); |
| 2454 | if (IS_ERR(mntroot)) { | 2483 | if (IS_ERR(mntroot)) { |
| 2455 | error = PTR_ERR(mntroot); | 2484 | error = PTR_ERR(mntroot); |
| 2456 | goto error_splat_super; | 2485 | goto error_splat_super; |
| @@ -2718,7 +2747,7 @@ nfs4_remote_mount(struct file_system_type *fs_type, int flags, | |||
| 2718 | s, data ? data->fscache_uniq : NULL, NULL); | 2747 | s, data ? data->fscache_uniq : NULL, NULL); |
| 2719 | } | 2748 | } |
| 2720 | 2749 | ||
| 2721 | mntroot = nfs4_get_root(s, mntfh); | 2750 | mntroot = nfs4_get_root(s, mntfh, dev_name); |
| 2722 | if (IS_ERR(mntroot)) { | 2751 | if (IS_ERR(mntroot)) { |
| 2723 | error = PTR_ERR(mntroot); | 2752 | error = PTR_ERR(mntroot); |
| 2724 | goto error_splat_super; | 2753 | goto error_splat_super; |
| @@ -2771,27 +2800,6 @@ static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, | |||
| 2771 | return root_mnt; | 2800 | return root_mnt; |
| 2772 | } | 2801 | } |
| 2773 | 2802 | ||
| 2774 | static void nfs_fix_devname(const struct path *path, struct vfsmount *mnt) | ||
| 2775 | { | ||
| 2776 | char *page = (char *) __get_free_page(GFP_KERNEL); | ||
| 2777 | char *devname, *tmp; | ||
| 2778 | |||
| 2779 | if (page == NULL) | ||
| 2780 | return; | ||
| 2781 | devname = nfs_path(path->mnt->mnt_devname, | ||
| 2782 | path->mnt->mnt_root, path->dentry, | ||
| 2783 | page, PAGE_SIZE); | ||
| 2784 | if (IS_ERR(devname)) | ||
| 2785 | goto out_freepage; | ||
| 2786 | tmp = kstrdup(devname, GFP_KERNEL); | ||
| 2787 | if (tmp == NULL) | ||
| 2788 | goto out_freepage; | ||
| 2789 | kfree(mnt->mnt_devname); | ||
| 2790 | mnt->mnt_devname = tmp; | ||
| 2791 | out_freepage: | ||
| 2792 | free_page((unsigned long)page); | ||
| 2793 | } | ||
| 2794 | |||
| 2795 | struct nfs_referral_count { | 2803 | struct nfs_referral_count { |
| 2796 | struct list_head list; | 2804 | struct list_head list; |
| 2797 | const struct task_struct *task; | 2805 | const struct task_struct *task; |
| @@ -2858,17 +2866,18 @@ static void nfs_referral_loop_unprotect(void) | |||
| 2858 | kfree(p); | 2866 | kfree(p); |
| 2859 | } | 2867 | } |
| 2860 | 2868 | ||
| 2861 | static int nfs_follow_remote_path(struct vfsmount *root_mnt, | 2869 | static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, |
| 2862 | const char *export_path, struct vfsmount *mnt_target) | 2870 | const char *export_path) |
| 2863 | { | 2871 | { |
| 2864 | struct nameidata *nd = NULL; | 2872 | struct nameidata *nd = NULL; |
| 2865 | struct mnt_namespace *ns_private; | 2873 | struct mnt_namespace *ns_private; |
| 2866 | struct super_block *s; | 2874 | struct super_block *s; |
| 2875 | struct dentry *dentry; | ||
| 2867 | int ret; | 2876 | int ret; |
| 2868 | 2877 | ||
| 2869 | nd = kmalloc(sizeof(*nd), GFP_KERNEL); | 2878 | nd = kmalloc(sizeof(*nd), GFP_KERNEL); |
| 2870 | if (nd == NULL) | 2879 | if (nd == NULL) |
| 2871 | return -ENOMEM; | 2880 | return ERR_PTR(-ENOMEM); |
| 2872 | 2881 | ||
| 2873 | ns_private = create_mnt_ns(root_mnt); | 2882 | ns_private = create_mnt_ns(root_mnt); |
| 2874 | ret = PTR_ERR(ns_private); | 2883 | ret = PTR_ERR(ns_private); |
| @@ -2890,32 +2899,27 @@ static int nfs_follow_remote_path(struct vfsmount *root_mnt, | |||
| 2890 | 2899 | ||
| 2891 | s = nd->path.mnt->mnt_sb; | 2900 | s = nd->path.mnt->mnt_sb; |
| 2892 | atomic_inc(&s->s_active); | 2901 | atomic_inc(&s->s_active); |
| 2893 | mnt_target->mnt_sb = s; | 2902 | dentry = dget(nd->path.dentry); |
| 2894 | mnt_target->mnt_root = dget(nd->path.dentry); | ||
| 2895 | |||
| 2896 | /* Correct the device pathname */ | ||
| 2897 | nfs_fix_devname(&nd->path, mnt_target); | ||
| 2898 | 2903 | ||
| 2899 | path_put(&nd->path); | 2904 | path_put(&nd->path); |
| 2900 | kfree(nd); | 2905 | kfree(nd); |
| 2901 | down_write(&s->s_umount); | 2906 | down_write(&s->s_umount); |
| 2902 | return 0; | 2907 | return dentry; |
| 2903 | out_put_mnt_ns: | 2908 | out_put_mnt_ns: |
| 2904 | put_mnt_ns(ns_private); | 2909 | put_mnt_ns(ns_private); |
| 2905 | out_mntput: | 2910 | out_mntput: |
| 2906 | mntput(root_mnt); | 2911 | mntput(root_mnt); |
| 2907 | out_err: | 2912 | out_err: |
| 2908 | kfree(nd); | 2913 | kfree(nd); |
| 2909 | return ret; | 2914 | return ERR_PTR(ret); |
| 2910 | } | 2915 | } |
| 2911 | 2916 | ||
| 2912 | static int nfs4_try_mount(int flags, const char *dev_name, | 2917 | static struct dentry *nfs4_try_mount(int flags, const char *dev_name, |
| 2913 | struct nfs_parsed_mount_data *data, | 2918 | struct nfs_parsed_mount_data *data) |
| 2914 | struct vfsmount *mnt) | ||
| 2915 | { | 2919 | { |
| 2916 | char *export_path; | 2920 | char *export_path; |
| 2917 | struct vfsmount *root_mnt; | 2921 | struct vfsmount *root_mnt; |
| 2918 | int error; | 2922 | struct dentry *res; |
| 2919 | 2923 | ||
| 2920 | dfprintk(MOUNT, "--> nfs4_try_mount()\n"); | 2924 | dfprintk(MOUNT, "--> nfs4_try_mount()\n"); |
| 2921 | 2925 | ||
| @@ -2925,26 +2929,25 @@ static int nfs4_try_mount(int flags, const char *dev_name, | |||
| 2925 | data->nfs_server.hostname); | 2929 | data->nfs_server.hostname); |
| 2926 | data->nfs_server.export_path = export_path; | 2930 | data->nfs_server.export_path = export_path; |
| 2927 | 2931 | ||
| 2928 | error = PTR_ERR(root_mnt); | 2932 | res = ERR_CAST(root_mnt); |
| 2929 | if (IS_ERR(root_mnt)) | 2933 | if (!IS_ERR(root_mnt)) |
| 2930 | goto out; | 2934 | res = nfs_follow_remote_path(root_mnt, export_path); |
| 2931 | 2935 | ||
| 2932 | error = nfs_follow_remote_path(root_mnt, export_path, mnt); | 2936 | dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s\n", |
| 2933 | 2937 | IS_ERR(res) ? PTR_ERR(res) : 0, | |
| 2934 | out: | 2938 | IS_ERR(res) ? " [error]" : ""); |
| 2935 | dfprintk(MOUNT, "<-- nfs4_try_mount() = %d%s\n", error, | 2939 | return res; |
| 2936 | error != 0 ? " [error]" : ""); | ||
| 2937 | return error; | ||
| 2938 | } | 2940 | } |
| 2939 | 2941 | ||
| 2940 | /* | 2942 | /* |
| 2941 | * Get the superblock for an NFS4 mountpoint | 2943 | * Get the superblock for an NFS4 mountpoint |
| 2942 | */ | 2944 | */ |
| 2943 | static int nfs4_get_sb(struct file_system_type *fs_type, | 2945 | static struct dentry *nfs4_mount(struct file_system_type *fs_type, |
| 2944 | int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt) | 2946 | int flags, const char *dev_name, void *raw_data) |
| 2945 | { | 2947 | { |
| 2946 | struct nfs_parsed_mount_data *data; | 2948 | struct nfs_parsed_mount_data *data; |
| 2947 | int error = -ENOMEM; | 2949 | int error = -ENOMEM; |
| 2950 | struct dentry *res = ERR_PTR(-ENOMEM); | ||
| 2948 | 2951 | ||
| 2949 | data = nfs_alloc_parsed_mount_data(4); | 2952 | data = nfs_alloc_parsed_mount_data(4); |
| 2950 | if (data == NULL) | 2953 | if (data == NULL) |
| @@ -2952,10 +2955,14 @@ static int nfs4_get_sb(struct file_system_type *fs_type, | |||
| 2952 | 2955 | ||
| 2953 | /* Validate the mount data */ | 2956 | /* Validate the mount data */ |
| 2954 | error = nfs4_validate_mount_data(raw_data, data, dev_name); | 2957 | error = nfs4_validate_mount_data(raw_data, data, dev_name); |
| 2955 | if (error < 0) | 2958 | if (error < 0) { |
| 2959 | res = ERR_PTR(error); | ||
| 2956 | goto out; | 2960 | goto out; |
| 2961 | } | ||
| 2957 | 2962 | ||
| 2958 | error = nfs4_try_mount(flags, dev_name, data, mnt); | 2963 | res = nfs4_try_mount(flags, dev_name, data); |
| 2964 | if (IS_ERR(res)) | ||
| 2965 | error = PTR_ERR(res); | ||
| 2959 | 2966 | ||
| 2960 | out: | 2967 | out: |
| 2961 | kfree(data->client_address); | 2968 | kfree(data->client_address); |
| @@ -2964,9 +2971,9 @@ out: | |||
| 2964 | kfree(data->fscache_uniq); | 2971 | kfree(data->fscache_uniq); |
| 2965 | out_free_data: | 2972 | out_free_data: |
| 2966 | kfree(data); | 2973 | kfree(data); |
| 2967 | dprintk("<-- nfs4_get_sb() = %d%s\n", error, | 2974 | dprintk("<-- nfs4_mount() = %d%s\n", error, |
| 2968 | error != 0 ? " [error]" : ""); | 2975 | error != 0 ? " [error]" : ""); |
| 2969 | return error; | 2976 | return res; |
| 2970 | } | 2977 | } |
| 2971 | 2978 | ||
| 2972 | static void nfs4_kill_super(struct super_block *sb) | 2979 | static void nfs4_kill_super(struct super_block *sb) |
| @@ -3033,7 +3040,7 @@ nfs4_xdev_mount(struct file_system_type *fs_type, int flags, | |||
| 3033 | nfs_fscache_get_super_cookie(s, NULL, data); | 3040 | nfs_fscache_get_super_cookie(s, NULL, data); |
| 3034 | } | 3041 | } |
| 3035 | 3042 | ||
| 3036 | mntroot = nfs4_get_root(s, data->fh); | 3043 | mntroot = nfs4_get_root(s, data->fh, dev_name); |
| 3037 | if (IS_ERR(mntroot)) { | 3044 | if (IS_ERR(mntroot)) { |
| 3038 | error = PTR_ERR(mntroot); | 3045 | error = PTR_ERR(mntroot); |
| 3039 | goto error_splat_super; | 3046 | goto error_splat_super; |
| @@ -3120,7 +3127,7 @@ nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags, | |||
| 3120 | nfs_fscache_get_super_cookie(s, NULL, data); | 3127 | nfs_fscache_get_super_cookie(s, NULL, data); |
| 3121 | } | 3128 | } |
| 3122 | 3129 | ||
| 3123 | mntroot = nfs4_get_root(s, mntfh); | 3130 | mntroot = nfs4_get_root(s, mntfh, dev_name); |
| 3124 | if (IS_ERR(mntroot)) { | 3131 | if (IS_ERR(mntroot)) { |
| 3125 | error = PTR_ERR(mntroot); | 3132 | error = PTR_ERR(mntroot); |
| 3126 | goto error_splat_super; | 3133 | goto error_splat_super; |
| @@ -3160,16 +3167,15 @@ error_splat_bdi: | |||
| 3160 | /* | 3167 | /* |
| 3161 | * Create an NFS4 server record on referral traversal | 3168 | * Create an NFS4 server record on referral traversal |
| 3162 | */ | 3169 | */ |
| 3163 | static int nfs4_referral_get_sb(struct file_system_type *fs_type, | 3170 | static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, |
| 3164 | int flags, const char *dev_name, void *raw_data, | 3171 | int flags, const char *dev_name, void *raw_data) |
| 3165 | struct vfsmount *mnt) | ||
| 3166 | { | 3172 | { |
| 3167 | struct nfs_clone_mount *data = raw_data; | 3173 | struct nfs_clone_mount *data = raw_data; |
| 3168 | char *export_path; | 3174 | char *export_path; |
| 3169 | struct vfsmount *root_mnt; | 3175 | struct vfsmount *root_mnt; |
| 3170 | int error; | 3176 | struct dentry *res; |
| 3171 | 3177 | ||
| 3172 | dprintk("--> nfs4_referral_get_sb()\n"); | 3178 | dprintk("--> nfs4_referral_mount()\n"); |
| 3173 | 3179 | ||
| 3174 | export_path = data->mnt_path; | 3180 | export_path = data->mnt_path; |
| 3175 | data->mnt_path = "/"; | 3181 | data->mnt_path = "/"; |
| @@ -3178,15 +3184,13 @@ static int nfs4_referral_get_sb(struct file_system_type *fs_type, | |||
| 3178 | flags, data, data->hostname); | 3184 | flags, data, data->hostname); |
| 3179 | data->mnt_path = export_path; | 3185 | data->mnt_path = export_path; |
| 3180 | 3186 | ||
| 3181 | error = PTR_ERR(root_mnt); | 3187 | res = ERR_CAST(root_mnt); |
| 3182 | if (IS_ERR(root_mnt)) | 3188 | if (!IS_ERR(root_mnt)) |
| 3183 | goto out; | 3189 | res = nfs_follow_remote_path(root_mnt, export_path); |
| 3184 | 3190 | dprintk("<-- nfs4_referral_mount() = %ld%s\n", | |
| 3185 | error = nfs_follow_remote_path(root_mnt, export_path, mnt); | 3191 | IS_ERR(res) ? PTR_ERR(res) : 0, |
| 3186 | out: | 3192 | IS_ERR(res) ? " [error]" : ""); |
| 3187 | dprintk("<-- nfs4_referral_get_sb() = %d%s\n", error, | 3193 | return res; |
| 3188 | error != 0 ? " [error]" : ""); | ||
| 3189 | return error; | ||
| 3190 | } | 3194 | } |
| 3191 | 3195 | ||
| 3192 | #endif /* CONFIG_NFS_V4 */ | 3196 | #endif /* CONFIG_NFS_V4 */ |
diff --git a/fs/nfs/unlink.c b/fs/nfs/unlink.c index 6481d537d69d..8d6864c2a5fa 100644 --- a/fs/nfs/unlink.c +++ b/fs/nfs/unlink.c | |||
| @@ -148,6 +148,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n | |||
| 148 | alias = d_lookup(parent, &data->args.name); | 148 | alias = d_lookup(parent, &data->args.name); |
| 149 | if (alias != NULL) { | 149 | if (alias != NULL) { |
| 150 | int ret = 0; | 150 | int ret = 0; |
| 151 | void *devname_garbage = NULL; | ||
| 151 | 152 | ||
| 152 | /* | 153 | /* |
| 153 | * Hey, we raced with lookup... See if we need to transfer | 154 | * Hey, we raced with lookup... See if we need to transfer |
| @@ -157,6 +158,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n | |||
| 157 | spin_lock(&alias->d_lock); | 158 | spin_lock(&alias->d_lock); |
| 158 | if (alias->d_inode != NULL && | 159 | if (alias->d_inode != NULL && |
| 159 | !(alias->d_flags & DCACHE_NFSFS_RENAMED)) { | 160 | !(alias->d_flags & DCACHE_NFSFS_RENAMED)) { |
| 161 | devname_garbage = alias->d_fsdata; | ||
| 160 | alias->d_fsdata = data; | 162 | alias->d_fsdata = data; |
| 161 | alias->d_flags |= DCACHE_NFSFS_RENAMED; | 163 | alias->d_flags |= DCACHE_NFSFS_RENAMED; |
| 162 | ret = 1; | 164 | ret = 1; |
| @@ -164,6 +166,13 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n | |||
| 164 | spin_unlock(&alias->d_lock); | 166 | spin_unlock(&alias->d_lock); |
| 165 | nfs_dec_sillycount(dir); | 167 | nfs_dec_sillycount(dir); |
| 166 | dput(alias); | 168 | dput(alias); |
| 169 | /* | ||
| 170 | * If we'd displaced old cached devname, free it. At that | ||
| 171 | * point dentry is definitely not a root, so we won't need | ||
| 172 | * that anymore. | ||
| 173 | */ | ||
| 174 | if (devname_garbage) | ||
| 175 | kfree(devname_garbage); | ||
| 167 | return ret; | 176 | return ret; |
| 168 | } | 177 | } |
| 169 | data->dir = igrab(dir); | 178 | data->dir = igrab(dir); |
| @@ -252,6 +261,7 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry) | |||
| 252 | { | 261 | { |
| 253 | struct nfs_unlinkdata *data; | 262 | struct nfs_unlinkdata *data; |
| 254 | int status = -ENOMEM; | 263 | int status = -ENOMEM; |
| 264 | void *devname_garbage = NULL; | ||
| 255 | 265 | ||
| 256 | data = kzalloc(sizeof(*data), GFP_KERNEL); | 266 | data = kzalloc(sizeof(*data), GFP_KERNEL); |
| 257 | if (data == NULL) | 267 | if (data == NULL) |
| @@ -269,8 +279,16 @@ nfs_async_unlink(struct inode *dir, struct dentry *dentry) | |||
| 269 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) | 279 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) |
| 270 | goto out_unlock; | 280 | goto out_unlock; |
| 271 | dentry->d_flags |= DCACHE_NFSFS_RENAMED; | 281 | dentry->d_flags |= DCACHE_NFSFS_RENAMED; |
| 282 | devname_garbage = dentry->d_fsdata; | ||
| 272 | dentry->d_fsdata = data; | 283 | dentry->d_fsdata = data; |
| 273 | spin_unlock(&dentry->d_lock); | 284 | spin_unlock(&dentry->d_lock); |
| 285 | /* | ||
| 286 | * If we'd displaced old cached devname, free it. At that | ||
| 287 | * point dentry is definitely not a root, so we won't need | ||
| 288 | * that anymore. | ||
| 289 | */ | ||
| 290 | if (devname_garbage) | ||
| 291 | kfree(devname_garbage); | ||
| 274 | return 0; | 292 | return 0; |
| 275 | out_unlock: | 293 | out_unlock: |
| 276 | spin_unlock(&dentry->d_lock); | 294 | spin_unlock(&dentry->d_lock); |
| @@ -299,6 +317,7 @@ nfs_complete_unlink(struct dentry *dentry, struct inode *inode) | |||
| 299 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { | 317 | if (dentry->d_flags & DCACHE_NFSFS_RENAMED) { |
| 300 | dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; | 318 | dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; |
| 301 | data = dentry->d_fsdata; | 319 | data = dentry->d_fsdata; |
| 320 | dentry->d_fsdata = NULL; | ||
| 302 | } | 321 | } |
| 303 | spin_unlock(&dentry->d_lock); | 322 | spin_unlock(&dentry->d_lock); |
| 304 | 323 | ||
| @@ -315,6 +334,7 @@ nfs_cancel_async_unlink(struct dentry *dentry) | |||
| 315 | struct nfs_unlinkdata *data = dentry->d_fsdata; | 334 | struct nfs_unlinkdata *data = dentry->d_fsdata; |
| 316 | 335 | ||
| 317 | dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; | 336 | dentry->d_flags &= ~DCACHE_NFSFS_RENAMED; |
| 337 | dentry->d_fsdata = NULL; | ||
| 318 | spin_unlock(&dentry->d_lock); | 338 | spin_unlock(&dentry->d_lock); |
| 319 | nfs_free_unlinkdata(data); | 339 | nfs_free_unlinkdata(data); |
| 320 | return; | 340 | return; |
diff --git a/fs/super.c b/fs/super.c index 7e9dd4cc2c01..4bae0ef6110e 100644 --- a/fs/super.c +++ b/fs/super.c | |||
| @@ -843,23 +843,6 @@ error: | |||
| 843 | } | 843 | } |
| 844 | EXPORT_SYMBOL(mount_bdev); | 844 | EXPORT_SYMBOL(mount_bdev); |
| 845 | 845 | ||
| 846 | int get_sb_bdev(struct file_system_type *fs_type, | ||
| 847 | int flags, const char *dev_name, void *data, | ||
| 848 | int (*fill_super)(struct super_block *, void *, int), | ||
| 849 | struct vfsmount *mnt) | ||
| 850 | { | ||
| 851 | struct dentry *root; | ||
| 852 | |||
| 853 | root = mount_bdev(fs_type, flags, dev_name, data, fill_super); | ||
| 854 | if (IS_ERR(root)) | ||
| 855 | return PTR_ERR(root); | ||
| 856 | mnt->mnt_root = root; | ||
| 857 | mnt->mnt_sb = root->d_sb; | ||
| 858 | return 0; | ||
| 859 | } | ||
| 860 | |||
| 861 | EXPORT_SYMBOL(get_sb_bdev); | ||
| 862 | |||
| 863 | void kill_block_super(struct super_block *sb) | 846 | void kill_block_super(struct super_block *sb) |
| 864 | { | 847 | { |
| 865 | struct block_device *bdev = sb->s_bdev; | 848 | struct block_device *bdev = sb->s_bdev; |
| @@ -897,22 +880,6 @@ struct dentry *mount_nodev(struct file_system_type *fs_type, | |||
| 897 | } | 880 | } |
| 898 | EXPORT_SYMBOL(mount_nodev); | 881 | EXPORT_SYMBOL(mount_nodev); |
| 899 | 882 | ||
| 900 | int get_sb_nodev(struct file_system_type *fs_type, | ||
| 901 | int flags, void *data, | ||
| 902 | int (*fill_super)(struct super_block *, void *, int), | ||
| 903 | struct vfsmount *mnt) | ||
| 904 | { | ||
| 905 | struct dentry *root; | ||
| 906 | |||
| 907 | root = mount_nodev(fs_type, flags, data, fill_super); | ||
| 908 | if (IS_ERR(root)) | ||
| 909 | return PTR_ERR(root); | ||
| 910 | mnt->mnt_root = root; | ||
| 911 | mnt->mnt_sb = root->d_sb; | ||
| 912 | return 0; | ||
| 913 | } | ||
| 914 | EXPORT_SYMBOL(get_sb_nodev); | ||
| 915 | |||
| 916 | static int compare_single(struct super_block *s, void *p) | 883 | static int compare_single(struct super_block *s, void *p) |
| 917 | { | 884 | { |
| 918 | return 1; | 885 | return 1; |
| @@ -943,22 +910,6 @@ struct dentry *mount_single(struct file_system_type *fs_type, | |||
| 943 | } | 910 | } |
| 944 | EXPORT_SYMBOL(mount_single); | 911 | EXPORT_SYMBOL(mount_single); |
| 945 | 912 | ||
| 946 | int get_sb_single(struct file_system_type *fs_type, | ||
| 947 | int flags, void *data, | ||
| 948 | int (*fill_super)(struct super_block *, void *, int), | ||
| 949 | struct vfsmount *mnt) | ||
| 950 | { | ||
| 951 | struct dentry *root; | ||
| 952 | root = mount_single(fs_type, flags, data, fill_super); | ||
| 953 | if (IS_ERR(root)) | ||
| 954 | return PTR_ERR(root); | ||
| 955 | mnt->mnt_root = root; | ||
| 956 | mnt->mnt_sb = root->d_sb; | ||
| 957 | return 0; | ||
| 958 | } | ||
| 959 | |||
| 960 | EXPORT_SYMBOL(get_sb_single); | ||
| 961 | |||
| 962 | struct vfsmount * | 913 | struct vfsmount * |
| 963 | vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) | 914 | vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) |
| 964 | { | 915 | { |
| @@ -988,19 +939,13 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void | |||
| 988 | goto out_free_secdata; | 939 | goto out_free_secdata; |
| 989 | } | 940 | } |
| 990 | 941 | ||
| 991 | if (type->mount) { | 942 | root = type->mount(type, flags, name, data); |
| 992 | root = type->mount(type, flags, name, data); | 943 | if (IS_ERR(root)) { |
| 993 | if (IS_ERR(root)) { | 944 | error = PTR_ERR(root); |
| 994 | error = PTR_ERR(root); | 945 | goto out_free_secdata; |
| 995 | goto out_free_secdata; | ||
| 996 | } | ||
| 997 | mnt->mnt_root = root; | ||
| 998 | mnt->mnt_sb = root->d_sb; | ||
| 999 | } else { | ||
| 1000 | error = type->get_sb(type, flags, name, data, mnt); | ||
| 1001 | if (error < 0) | ||
| 1002 | goto out_free_secdata; | ||
| 1003 | } | 946 | } |
| 947 | mnt->mnt_root = root; | ||
| 948 | mnt->mnt_sb = root->d_sb; | ||
| 1004 | BUG_ON(!mnt->mnt_sb); | 949 | BUG_ON(!mnt->mnt_sb); |
| 1005 | WARN_ON(!mnt->mnt_sb->s_bdi); | 950 | WARN_ON(!mnt->mnt_sb->s_bdi); |
| 1006 | mnt->mnt_sb->s_flags |= MS_BORN; | 951 | mnt->mnt_sb->s_flags |= MS_BORN; |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 2f5a71d6d766..92f7e04aea11 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -1631,6 +1631,8 @@ struct super_operations { | |||
| 1631 | void (*umount_begin) (struct super_block *); | 1631 | void (*umount_begin) (struct super_block *); |
| 1632 | 1632 | ||
| 1633 | int (*show_options)(struct seq_file *, struct vfsmount *); | 1633 | int (*show_options)(struct seq_file *, struct vfsmount *); |
| 1634 | int (*show_devname)(struct seq_file *, struct vfsmount *); | ||
| 1635 | int (*show_path)(struct seq_file *, struct vfsmount *); | ||
| 1634 | int (*show_stats)(struct seq_file *, struct vfsmount *); | 1636 | int (*show_stats)(struct seq_file *, struct vfsmount *); |
| 1635 | #ifdef CONFIG_QUOTA | 1637 | #ifdef CONFIG_QUOTA |
| 1636 | ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); | 1638 | ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t); |
| @@ -1794,8 +1796,6 @@ int sync_inode_metadata(struct inode *inode, int wait); | |||
| 1794 | struct file_system_type { | 1796 | struct file_system_type { |
| 1795 | const char *name; | 1797 | const char *name; |
| 1796 | int fs_flags; | 1798 | int fs_flags; |
| 1797 | int (*get_sb) (struct file_system_type *, int, | ||
| 1798 | const char *, void *, struct vfsmount *); | ||
| 1799 | struct dentry *(*mount) (struct file_system_type *, int, | 1799 | struct dentry *(*mount) (struct file_system_type *, int, |
| 1800 | const char *, void *); | 1800 | const char *, void *); |
| 1801 | void (*kill_sb) (struct super_block *); | 1801 | void (*kill_sb) (struct super_block *); |
| @@ -1818,24 +1818,12 @@ extern struct dentry *mount_ns(struct file_system_type *fs_type, int flags, | |||
| 1818 | extern struct dentry *mount_bdev(struct file_system_type *fs_type, | 1818 | extern struct dentry *mount_bdev(struct file_system_type *fs_type, |
| 1819 | int flags, const char *dev_name, void *data, | 1819 | int flags, const char *dev_name, void *data, |
| 1820 | int (*fill_super)(struct super_block *, void *, int)); | 1820 | int (*fill_super)(struct super_block *, void *, int)); |
| 1821 | extern int get_sb_bdev(struct file_system_type *fs_type, | ||
| 1822 | int flags, const char *dev_name, void *data, | ||
| 1823 | int (*fill_super)(struct super_block *, void *, int), | ||
| 1824 | struct vfsmount *mnt); | ||
| 1825 | extern struct dentry *mount_single(struct file_system_type *fs_type, | 1821 | extern struct dentry *mount_single(struct file_system_type *fs_type, |
| 1826 | int flags, void *data, | 1822 | int flags, void *data, |
| 1827 | int (*fill_super)(struct super_block *, void *, int)); | 1823 | int (*fill_super)(struct super_block *, void *, int)); |
| 1828 | extern int get_sb_single(struct file_system_type *fs_type, | ||
| 1829 | int flags, void *data, | ||
| 1830 | int (*fill_super)(struct super_block *, void *, int), | ||
| 1831 | struct vfsmount *mnt); | ||
| 1832 | extern struct dentry *mount_nodev(struct file_system_type *fs_type, | 1824 | extern struct dentry *mount_nodev(struct file_system_type *fs_type, |
| 1833 | int flags, void *data, | 1825 | int flags, void *data, |
| 1834 | int (*fill_super)(struct super_block *, void *, int)); | 1826 | int (*fill_super)(struct super_block *, void *, int)); |
| 1835 | extern int get_sb_nodev(struct file_system_type *fs_type, | ||
| 1836 | int flags, void *data, | ||
| 1837 | int (*fill_super)(struct super_block *, void *, int), | ||
| 1838 | struct vfsmount *mnt); | ||
| 1839 | void generic_shutdown_super(struct super_block *sb); | 1827 | void generic_shutdown_super(struct super_block *sb); |
| 1840 | void kill_block_super(struct super_block *sb); | 1828 | void kill_block_super(struct super_block *sb); |
| 1841 | void kill_anon_super(struct super_block *sb); | 1829 | void kill_anon_super(struct super_block *sb); |
