diff options
| -rw-r--r-- | fs/nfs/internal.h | 29 | ||||
| -rw-r--r-- | fs/nfs/nfs4_fs.h | 2 | ||||
| -rw-r--r-- | fs/nfs/nfs4super.c | 328 | ||||
| -rw-r--r-- | fs/nfs/super.c | 395 |
4 files changed, 381 insertions, 373 deletions
diff --git a/fs/nfs/internal.h b/fs/nfs/internal.h index b4a35705246c..cfafd13b6fe9 100644 --- a/fs/nfs/internal.h +++ b/fs/nfs/internal.h | |||
| @@ -153,6 +153,14 @@ struct nfs_mount_request { | |||
| 153 | struct net *net; | 153 | struct net *net; |
| 154 | }; | 154 | }; |
| 155 | 155 | ||
| 156 | struct nfs_mount_info { | ||
| 157 | void (*fill_super)(struct super_block *, struct nfs_mount_info *); | ||
| 158 | int (*set_security)(struct super_block *, struct dentry *, struct nfs_mount_info *); | ||
| 159 | struct nfs_parsed_mount_data *parsed; | ||
| 160 | struct nfs_clone_mount *cloned; | ||
| 161 | struct nfs_fh *mntfh; | ||
| 162 | }; | ||
| 163 | |||
| 156 | extern int nfs_mount(struct nfs_mount_request *info); | 164 | extern int nfs_mount(struct nfs_mount_request *info); |
| 157 | extern void nfs_umount(const struct nfs_mount_request *info); | 165 | extern void nfs_umount(const struct nfs_mount_request *info); |
| 158 | 166 | ||
| @@ -318,6 +326,16 @@ extern struct file_system_type nfs_xdev_fs_type; | |||
| 318 | extern struct file_system_type nfs4_xdev_fs_type; | 326 | extern struct file_system_type nfs4_xdev_fs_type; |
| 319 | extern struct file_system_type nfs4_referral_fs_type; | 327 | extern struct file_system_type nfs4_referral_fs_type; |
| 320 | #endif | 328 | #endif |
| 329 | void nfs_initialise_sb(struct super_block *); | ||
| 330 | int nfs_set_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *); | ||
| 331 | int nfs_clone_sb_security(struct super_block *, struct dentry *, struct nfs_mount_info *); | ||
| 332 | struct dentry *nfs_fs_mount_common(struct file_system_type *, struct nfs_server *, | ||
| 333 | int, const char *, struct nfs_mount_info *); | ||
| 334 | struct dentry *nfs_fs_mount(struct file_system_type *, int, const char *, void *); | ||
| 335 | struct dentry * nfs_xdev_mount_common(struct file_system_type *, int, | ||
| 336 | const char *, struct nfs_mount_info *); | ||
| 337 | void nfs_kill_super(struct super_block *); | ||
| 338 | void nfs_fill_super(struct super_block *, struct nfs_mount_info *); | ||
| 321 | 339 | ||
| 322 | extern struct rpc_stat nfs_rpcstat; | 340 | extern struct rpc_stat nfs_rpcstat; |
| 323 | 341 | ||
| @@ -364,6 +382,17 @@ extern void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, | |||
| 364 | extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio); | 382 | extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio); |
| 365 | extern void nfs_readdata_release(struct nfs_read_data *rdata); | 383 | extern void nfs_readdata_release(struct nfs_read_data *rdata); |
| 366 | 384 | ||
| 385 | /* super.c */ | ||
| 386 | void nfs_clone_super(struct super_block *, struct nfs_mount_info *); | ||
| 387 | void nfs_umount_begin(struct super_block *); | ||
| 388 | int nfs_statfs(struct dentry *, struct kstatfs *); | ||
| 389 | int nfs_show_options(struct seq_file *, struct dentry *); | ||
| 390 | int nfs_show_devname(struct seq_file *, struct dentry *); | ||
| 391 | int nfs_show_path(struct seq_file *, struct dentry *); | ||
| 392 | int nfs_show_stats(struct seq_file *, struct dentry *); | ||
| 393 | void nfs_put_super(struct super_block *); | ||
| 394 | int nfs_remount(struct super_block *sb, int *flags, char *raw_data); | ||
| 395 | |||
| 367 | /* write.c */ | 396 | /* write.c */ |
| 368 | extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, | 397 | extern void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, |
| 369 | struct inode *inode, int ioflags, | 398 | struct inode *inode, int ioflags, |
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index b508fef1a32b..b1ecacd8784a 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h | |||
| @@ -365,6 +365,8 @@ extern void nfs4_free_lock_state(struct nfs_server *server, struct nfs4_lock_sta | |||
| 365 | extern const nfs4_stateid zero_stateid; | 365 | extern const nfs4_stateid zero_stateid; |
| 366 | 366 | ||
| 367 | /* nfs4super.c */ | 367 | /* nfs4super.c */ |
| 368 | struct nfs_mount_info; | ||
| 369 | struct dentry *nfs4_try_mount(int, const char *, struct nfs_mount_info *); | ||
| 368 | int init_nfs_v4(void); | 370 | int init_nfs_v4(void); |
| 369 | void exit_nfs_v4(void); | 371 | void exit_nfs_v4(void); |
| 370 | 372 | ||
diff --git a/fs/nfs/nfs4super.c b/fs/nfs/nfs4super.c index 70c394e75ca1..2af26913884f 100644 --- a/fs/nfs/nfs4super.c +++ b/fs/nfs/nfs4super.c | |||
| @@ -2,10 +2,331 @@ | |||
| 2 | * Copyright (c) 2012 Bryan Schumaker <bjschuma@netapp.com> | 2 | * Copyright (c) 2012 Bryan Schumaker <bjschuma@netapp.com> |
| 3 | */ | 3 | */ |
| 4 | #include <linux/init.h> | 4 | #include <linux/init.h> |
| 5 | #include <linux/module.h> | ||
| 5 | #include <linux/nfs_idmap.h> | 6 | #include <linux/nfs_idmap.h> |
| 7 | #include <linux/nfs4_mount.h> | ||
| 6 | #include <linux/nfs_fs.h> | 8 | #include <linux/nfs_fs.h> |
| 9 | #include "internal.h" | ||
| 7 | #include "nfs4_fs.h" | 10 | #include "nfs4_fs.h" |
| 8 | 11 | ||
| 12 | #define NFSDBG_FACILITY NFSDBG_VFS | ||
| 13 | |||
| 14 | static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type, | ||
| 15 | int flags, const char *dev_name, void *raw_data); | ||
| 16 | static struct dentry *nfs4_xdev_mount(struct file_system_type *fs_type, | ||
| 17 | int flags, const char *dev_name, void *raw_data); | ||
| 18 | static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | ||
| 19 | int flags, const char *dev_name, void *raw_data); | ||
| 20 | static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type, | ||
| 21 | int flags, const char *dev_name, void *raw_data); | ||
| 22 | |||
| 23 | static struct file_system_type nfs4_fs_type = { | ||
| 24 | .owner = THIS_MODULE, | ||
| 25 | .name = "nfs4", | ||
| 26 | .mount = nfs_fs_mount, | ||
| 27 | .kill_sb = nfs_kill_super, | ||
| 28 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
| 29 | }; | ||
| 30 | |||
| 31 | static struct file_system_type nfs4_remote_fs_type = { | ||
| 32 | .owner = THIS_MODULE, | ||
| 33 | .name = "nfs4", | ||
| 34 | .mount = nfs4_remote_mount, | ||
| 35 | .kill_sb = nfs_kill_super, | ||
| 36 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
| 37 | }; | ||
| 38 | |||
| 39 | struct file_system_type nfs4_xdev_fs_type = { | ||
| 40 | .owner = THIS_MODULE, | ||
| 41 | .name = "nfs4", | ||
| 42 | .mount = nfs4_xdev_mount, | ||
| 43 | .kill_sb = nfs_kill_super, | ||
| 44 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
| 45 | }; | ||
| 46 | |||
| 47 | static struct file_system_type nfs4_remote_referral_fs_type = { | ||
| 48 | .owner = THIS_MODULE, | ||
| 49 | .name = "nfs4", | ||
| 50 | .mount = nfs4_remote_referral_mount, | ||
| 51 | .kill_sb = nfs_kill_super, | ||
| 52 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
| 53 | }; | ||
| 54 | |||
| 55 | struct file_system_type nfs4_referral_fs_type = { | ||
| 56 | .owner = THIS_MODULE, | ||
| 57 | .name = "nfs4", | ||
| 58 | .mount = nfs4_referral_mount, | ||
| 59 | .kill_sb = nfs_kill_super, | ||
| 60 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
| 61 | }; | ||
| 62 | |||
| 63 | static const struct super_operations nfs4_sops = { | ||
| 64 | .alloc_inode = nfs_alloc_inode, | ||
| 65 | .destroy_inode = nfs_destroy_inode, | ||
| 66 | .write_inode = nfs4_write_inode, | ||
| 67 | .put_super = nfs_put_super, | ||
| 68 | .statfs = nfs_statfs, | ||
| 69 | .evict_inode = nfs4_evict_inode, | ||
| 70 | .umount_begin = nfs_umount_begin, | ||
| 71 | .show_options = nfs_show_options, | ||
| 72 | .show_devname = nfs_show_devname, | ||
| 73 | .show_path = nfs_show_path, | ||
| 74 | .show_stats = nfs_show_stats, | ||
| 75 | .remount_fs = nfs_remount, | ||
| 76 | }; | ||
| 77 | |||
| 78 | /* | ||
| 79 | * Set up an NFS4 superblock | ||
| 80 | */ | ||
| 81 | static void nfs4_fill_super(struct super_block *sb, | ||
| 82 | struct nfs_mount_info *mount_info) | ||
| 83 | { | ||
| 84 | sb->s_time_gran = 1; | ||
| 85 | sb->s_op = &nfs4_sops; | ||
| 86 | /* | ||
| 87 | * The VFS shouldn't apply the umask to mode bits. We will do | ||
| 88 | * so ourselves when necessary. | ||
| 89 | */ | ||
| 90 | sb->s_flags |= MS_POSIXACL; | ||
| 91 | sb->s_xattr = nfs4_xattr_handlers; | ||
| 92 | nfs_initialise_sb(sb); | ||
| 93 | } | ||
| 94 | |||
| 95 | /* | ||
| 96 | * Get the superblock for the NFS4 root partition | ||
| 97 | */ | ||
| 98 | static struct dentry * | ||
| 99 | nfs4_remote_mount(struct file_system_type *fs_type, int flags, | ||
| 100 | const char *dev_name, void *info) | ||
| 101 | { | ||
| 102 | struct nfs_mount_info *mount_info = info; | ||
| 103 | struct nfs_server *server; | ||
| 104 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | ||
| 105 | |||
| 106 | mount_info->fill_super = nfs4_fill_super; | ||
| 107 | mount_info->set_security = nfs_set_sb_security; | ||
| 108 | |||
| 109 | /* Get a volume representation */ | ||
| 110 | server = nfs4_create_server(mount_info->parsed, mount_info->mntfh); | ||
| 111 | if (IS_ERR(server)) { | ||
| 112 | mntroot = ERR_CAST(server); | ||
| 113 | goto out; | ||
| 114 | } | ||
| 115 | |||
| 116 | mntroot = nfs_fs_mount_common(fs_type, server, flags, dev_name, mount_info); | ||
| 117 | |||
| 118 | out: | ||
| 119 | return mntroot; | ||
| 120 | } | ||
| 121 | |||
| 122 | static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, | ||
| 123 | int flags, void *data, const char *hostname) | ||
| 124 | { | ||
| 125 | struct vfsmount *root_mnt; | ||
| 126 | char *root_devname; | ||
| 127 | size_t len; | ||
| 128 | |||
| 129 | len = strlen(hostname) + 5; | ||
| 130 | root_devname = kmalloc(len, GFP_KERNEL); | ||
| 131 | if (root_devname == NULL) | ||
| 132 | return ERR_PTR(-ENOMEM); | ||
| 133 | /* Does hostname needs to be enclosed in brackets? */ | ||
| 134 | if (strchr(hostname, ':')) | ||
| 135 | snprintf(root_devname, len, "[%s]:/", hostname); | ||
| 136 | else | ||
| 137 | snprintf(root_devname, len, "%s:/", hostname); | ||
| 138 | root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data); | ||
| 139 | kfree(root_devname); | ||
| 140 | return root_mnt; | ||
| 141 | } | ||
| 142 | |||
| 143 | struct nfs_referral_count { | ||
| 144 | struct list_head list; | ||
| 145 | const struct task_struct *task; | ||
| 146 | unsigned int referral_count; | ||
| 147 | }; | ||
| 148 | |||
| 149 | static LIST_HEAD(nfs_referral_count_list); | ||
| 150 | static DEFINE_SPINLOCK(nfs_referral_count_list_lock); | ||
| 151 | |||
| 152 | static struct nfs_referral_count *nfs_find_referral_count(void) | ||
| 153 | { | ||
| 154 | struct nfs_referral_count *p; | ||
| 155 | |||
| 156 | list_for_each_entry(p, &nfs_referral_count_list, list) { | ||
| 157 | if (p->task == current) | ||
| 158 | return p; | ||
| 159 | } | ||
| 160 | return NULL; | ||
| 161 | } | ||
| 162 | |||
| 163 | #define NFS_MAX_NESTED_REFERRALS 2 | ||
| 164 | |||
| 165 | static int nfs_referral_loop_protect(void) | ||
| 166 | { | ||
| 167 | struct nfs_referral_count *p, *new; | ||
| 168 | int ret = -ENOMEM; | ||
| 169 | |||
| 170 | new = kmalloc(sizeof(*new), GFP_KERNEL); | ||
| 171 | if (!new) | ||
| 172 | goto out; | ||
| 173 | new->task = current; | ||
| 174 | new->referral_count = 1; | ||
| 175 | |||
| 176 | ret = 0; | ||
| 177 | spin_lock(&nfs_referral_count_list_lock); | ||
| 178 | p = nfs_find_referral_count(); | ||
| 179 | if (p != NULL) { | ||
| 180 | if (p->referral_count >= NFS_MAX_NESTED_REFERRALS) | ||
| 181 | ret = -ELOOP; | ||
| 182 | else | ||
| 183 | p->referral_count++; | ||
| 184 | } else { | ||
| 185 | list_add(&new->list, &nfs_referral_count_list); | ||
| 186 | new = NULL; | ||
| 187 | } | ||
| 188 | spin_unlock(&nfs_referral_count_list_lock); | ||
| 189 | kfree(new); | ||
| 190 | out: | ||
| 191 | return ret; | ||
| 192 | } | ||
| 193 | |||
| 194 | static void nfs_referral_loop_unprotect(void) | ||
| 195 | { | ||
| 196 | struct nfs_referral_count *p; | ||
| 197 | |||
| 198 | spin_lock(&nfs_referral_count_list_lock); | ||
| 199 | p = nfs_find_referral_count(); | ||
| 200 | p->referral_count--; | ||
| 201 | if (p->referral_count == 0) | ||
| 202 | list_del(&p->list); | ||
| 203 | else | ||
| 204 | p = NULL; | ||
| 205 | spin_unlock(&nfs_referral_count_list_lock); | ||
| 206 | kfree(p); | ||
| 207 | } | ||
| 208 | |||
| 209 | static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, | ||
| 210 | const char *export_path) | ||
| 211 | { | ||
| 212 | struct dentry *dentry; | ||
| 213 | int err; | ||
| 214 | |||
| 215 | if (IS_ERR(root_mnt)) | ||
| 216 | return ERR_CAST(root_mnt); | ||
| 217 | |||
| 218 | err = nfs_referral_loop_protect(); | ||
| 219 | if (err) { | ||
| 220 | mntput(root_mnt); | ||
| 221 | return ERR_PTR(err); | ||
| 222 | } | ||
| 223 | |||
| 224 | dentry = mount_subtree(root_mnt, export_path); | ||
| 225 | nfs_referral_loop_unprotect(); | ||
| 226 | |||
| 227 | return dentry; | ||
| 228 | } | ||
| 229 | |||
| 230 | struct dentry *nfs4_try_mount(int flags, const char *dev_name, | ||
| 231 | struct nfs_mount_info *mount_info) | ||
| 232 | { | ||
| 233 | char *export_path; | ||
| 234 | struct vfsmount *root_mnt; | ||
| 235 | struct dentry *res; | ||
| 236 | struct nfs_parsed_mount_data *data = mount_info->parsed; | ||
| 237 | |||
| 238 | dfprintk(MOUNT, "--> nfs4_try_mount()\n"); | ||
| 239 | |||
| 240 | mount_info->fill_super = nfs4_fill_super; | ||
| 241 | |||
| 242 | export_path = data->nfs_server.export_path; | ||
| 243 | data->nfs_server.export_path = "/"; | ||
| 244 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info, | ||
| 245 | data->nfs_server.hostname); | ||
| 246 | data->nfs_server.export_path = export_path; | ||
| 247 | |||
| 248 | res = nfs_follow_remote_path(root_mnt, export_path); | ||
| 249 | |||
| 250 | dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s\n", | ||
| 251 | IS_ERR(res) ? PTR_ERR(res) : 0, | ||
| 252 | IS_ERR(res) ? " [error]" : ""); | ||
| 253 | return res; | ||
| 254 | } | ||
| 255 | |||
| 256 | /* | ||
| 257 | * Clone an NFS4 server record on xdev traversal (FSID-change) | ||
| 258 | */ | ||
| 259 | static struct dentry * | ||
| 260 | nfs4_xdev_mount(struct file_system_type *fs_type, int flags, | ||
| 261 | const char *dev_name, void *raw_data) | ||
| 262 | { | ||
| 263 | struct nfs_mount_info mount_info = { | ||
| 264 | .fill_super = nfs_clone_super, | ||
| 265 | .set_security = nfs_clone_sb_security, | ||
| 266 | .cloned = raw_data, | ||
| 267 | }; | ||
| 268 | return nfs_xdev_mount_common(&nfs4_fs_type, flags, dev_name, &mount_info); | ||
| 269 | } | ||
| 270 | |||
| 271 | static struct dentry * | ||
| 272 | nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags, | ||
| 273 | const char *dev_name, void *raw_data) | ||
| 274 | { | ||
| 275 | struct nfs_mount_info mount_info = { | ||
| 276 | .fill_super = nfs4_fill_super, | ||
| 277 | .set_security = nfs_clone_sb_security, | ||
| 278 | .cloned = raw_data, | ||
| 279 | }; | ||
| 280 | struct nfs_server *server; | ||
| 281 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | ||
| 282 | |||
| 283 | dprintk("--> nfs4_referral_get_sb()\n"); | ||
| 284 | |||
| 285 | mount_info.mntfh = nfs_alloc_fhandle(); | ||
| 286 | if (mount_info.cloned == NULL || mount_info.mntfh == NULL) | ||
| 287 | goto out; | ||
| 288 | |||
| 289 | /* create a new volume representation */ | ||
| 290 | server = nfs4_create_referral_server(mount_info.cloned, mount_info.mntfh); | ||
| 291 | if (IS_ERR(server)) { | ||
| 292 | mntroot = ERR_CAST(server); | ||
| 293 | goto out; | ||
| 294 | } | ||
| 295 | |||
| 296 | mntroot = nfs_fs_mount_common(&nfs4_fs_type, server, flags, dev_name, &mount_info); | ||
| 297 | out: | ||
| 298 | nfs_free_fhandle(mount_info.mntfh); | ||
| 299 | return mntroot; | ||
| 300 | } | ||
| 301 | |||
| 302 | /* | ||
| 303 | * Create an NFS4 server record on referral traversal | ||
| 304 | */ | ||
| 305 | static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | ||
| 306 | int flags, const char *dev_name, void *raw_data) | ||
| 307 | { | ||
| 308 | struct nfs_clone_mount *data = raw_data; | ||
| 309 | char *export_path; | ||
| 310 | struct vfsmount *root_mnt; | ||
| 311 | struct dentry *res; | ||
| 312 | |||
| 313 | dprintk("--> nfs4_referral_mount()\n"); | ||
| 314 | |||
| 315 | export_path = data->mnt_path; | ||
| 316 | data->mnt_path = "/"; | ||
| 317 | |||
| 318 | root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type, | ||
| 319 | flags, data, data->hostname); | ||
| 320 | data->mnt_path = export_path; | ||
| 321 | |||
| 322 | res = nfs_follow_remote_path(root_mnt, export_path); | ||
| 323 | dprintk("<-- nfs4_referral_mount() = %ld%s\n", | ||
| 324 | IS_ERR(res) ? PTR_ERR(res) : 0, | ||
| 325 | IS_ERR(res) ? " [error]" : ""); | ||
| 326 | return res; | ||
| 327 | } | ||
| 328 | |||
| 329 | |||
| 9 | int __init init_nfs_v4(void) | 330 | int __init init_nfs_v4(void) |
| 10 | { | 331 | { |
| 11 | int err; | 332 | int err; |
| @@ -18,7 +339,13 @@ int __init init_nfs_v4(void) | |||
| 18 | if (err) | 339 | if (err) |
| 19 | goto out1; | 340 | goto out1; |
| 20 | 341 | ||
| 342 | err = register_filesystem(&nfs4_fs_type); | ||
| 343 | if (err < 0) | ||
| 344 | goto out2; | ||
| 345 | |||
| 21 | return 0; | 346 | return 0; |
| 347 | out2: | ||
| 348 | nfs4_unregister_sysctl(); | ||
| 22 | out1: | 349 | out1: |
| 23 | nfs_idmap_quit(); | 350 | nfs_idmap_quit(); |
| 24 | out: | 351 | out: |
| @@ -27,6 +354,7 @@ out: | |||
| 27 | 354 | ||
| 28 | void __exit exit_nfs_v4(void) | 355 | void __exit exit_nfs_v4(void) |
| 29 | { | 356 | { |
| 357 | unregister_filesystem(&nfs4_fs_type); | ||
| 30 | nfs4_unregister_sysctl(); | 358 | nfs4_unregister_sysctl(); |
| 31 | nfs_idmap_quit(); | 359 | nfs_idmap_quit(); |
| 32 | } | 360 | } |
diff --git a/fs/nfs/super.c b/fs/nfs/super.c index ca3c0e8cf774..95866a8c21bb 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c | |||
| @@ -278,29 +278,8 @@ static match_table_t nfs_vers_tokens = { | |||
| 278 | { Opt_vers_err, NULL } | 278 | { Opt_vers_err, NULL } |
| 279 | }; | 279 | }; |
| 280 | 280 | ||
| 281 | struct nfs_mount_info { | ||
| 282 | void (*fill_super)(struct super_block *, struct nfs_mount_info *); | ||
| 283 | int (*set_security)(struct super_block *, struct dentry *, struct nfs_mount_info *); | ||
| 284 | struct nfs_parsed_mount_data *parsed; | ||
| 285 | struct nfs_clone_mount *cloned; | ||
| 286 | struct nfs_fh *mntfh; | ||
| 287 | }; | ||
| 288 | |||
| 289 | static void nfs_umount_begin(struct super_block *); | ||
| 290 | static int nfs_statfs(struct dentry *, struct kstatfs *); | ||
| 291 | static int nfs_show_options(struct seq_file *, struct dentry *); | ||
| 292 | static int nfs_show_devname(struct seq_file *, struct dentry *); | ||
| 293 | static int nfs_show_path(struct seq_file *, struct dentry *); | ||
| 294 | static int nfs_show_stats(struct seq_file *, struct dentry *); | ||
| 295 | static struct dentry *nfs_fs_mount_common(struct file_system_type *, | ||
| 296 | struct nfs_server *, int, const char *, struct nfs_mount_info *); | ||
| 297 | static struct dentry *nfs_fs_mount(struct file_system_type *, | ||
| 298 | int, const char *, void *); | ||
| 299 | static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type, | 281 | static struct dentry *nfs_xdev_mount(struct file_system_type *fs_type, |
| 300 | int flags, const char *dev_name, void *raw_data); | 282 | int flags, const char *dev_name, void *raw_data); |
| 301 | static void nfs_put_super(struct super_block *); | ||
| 302 | static void nfs_kill_super(struct super_block *); | ||
| 303 | static int nfs_remount(struct super_block *sb, int *flags, char *raw_data); | ||
| 304 | 283 | ||
| 305 | static struct file_system_type nfs_fs_type = { | 284 | static struct file_system_type nfs_fs_type = { |
| 306 | .owner = THIS_MODULE, | 285 | .owner = THIS_MODULE, |
| @@ -337,71 +316,6 @@ static const struct super_operations nfs_sops = { | |||
| 337 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *); | 316 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *); |
| 338 | static int nfs4_validate_mount_data(void *options, | 317 | static int nfs4_validate_mount_data(void *options, |
| 339 | struct nfs_parsed_mount_data *args, const char *dev_name); | 318 | struct nfs_parsed_mount_data *args, const char *dev_name); |
| 340 | static struct dentry *nfs4_try_mount(int flags, const char *dev_name, | ||
| 341 | struct nfs_mount_info *mount_info); | ||
| 342 | static struct dentry *nfs4_remote_mount(struct file_system_type *fs_type, | ||
| 343 | int flags, const char *dev_name, void *raw_data); | ||
| 344 | static struct dentry *nfs4_xdev_mount(struct file_system_type *fs_type, | ||
| 345 | int flags, const char *dev_name, void *raw_data); | ||
| 346 | static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | ||
| 347 | int flags, const char *dev_name, void *raw_data); | ||
| 348 | static struct dentry *nfs4_remote_referral_mount(struct file_system_type *fs_type, | ||
| 349 | int flags, const char *dev_name, void *raw_data); | ||
| 350 | |||
| 351 | static struct file_system_type nfs4_fs_type = { | ||
| 352 | .owner = THIS_MODULE, | ||
| 353 | .name = "nfs4", | ||
| 354 | .mount = nfs_fs_mount, | ||
| 355 | .kill_sb = nfs_kill_super, | ||
| 356 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
| 357 | }; | ||
| 358 | |||
| 359 | static struct file_system_type nfs4_remote_fs_type = { | ||
| 360 | .owner = THIS_MODULE, | ||
| 361 | .name = "nfs4", | ||
| 362 | .mount = nfs4_remote_mount, | ||
| 363 | .kill_sb = nfs_kill_super, | ||
| 364 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
| 365 | }; | ||
| 366 | |||
| 367 | struct file_system_type nfs4_xdev_fs_type = { | ||
| 368 | .owner = THIS_MODULE, | ||
| 369 | .name = "nfs4", | ||
| 370 | .mount = nfs4_xdev_mount, | ||
| 371 | .kill_sb = nfs_kill_super, | ||
| 372 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
| 373 | }; | ||
| 374 | |||
| 375 | static struct file_system_type nfs4_remote_referral_fs_type = { | ||
| 376 | .owner = THIS_MODULE, | ||
| 377 | .name = "nfs4", | ||
| 378 | .mount = nfs4_remote_referral_mount, | ||
| 379 | .kill_sb = nfs_kill_super, | ||
| 380 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
| 381 | }; | ||
| 382 | |||
| 383 | struct file_system_type nfs4_referral_fs_type = { | ||
| 384 | .owner = THIS_MODULE, | ||
| 385 | .name = "nfs4", | ||
| 386 | .mount = nfs4_referral_mount, | ||
| 387 | .kill_sb = nfs_kill_super, | ||
| 388 | .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, | ||
| 389 | }; | ||
| 390 | |||
| 391 | static const struct super_operations nfs4_sops = { | ||
| 392 | .alloc_inode = nfs_alloc_inode, | ||
| 393 | .destroy_inode = nfs_destroy_inode, | ||
| 394 | .write_inode = nfs4_write_inode, | ||
| 395 | .put_super = nfs_put_super, | ||
| 396 | .statfs = nfs_statfs, | ||
| 397 | .evict_inode = nfs4_evict_inode, | ||
| 398 | .umount_begin = nfs_umount_begin, | ||
| 399 | .show_options = nfs_show_options, | ||
| 400 | .show_devname = nfs_show_devname, | ||
| 401 | .show_path = nfs_show_path, | ||
| 402 | .show_stats = nfs_show_stats, | ||
| 403 | .remount_fs = nfs_remount, | ||
| 404 | }; | ||
| 405 | #endif | 319 | #endif |
| 406 | 320 | ||
| 407 | static struct shrinker acl_shrinker = { | 321 | static struct shrinker acl_shrinker = { |
| @@ -423,18 +337,9 @@ int __init register_nfs_fs(void) | |||
| 423 | ret = nfs_register_sysctl(); | 337 | ret = nfs_register_sysctl(); |
| 424 | if (ret < 0) | 338 | if (ret < 0) |
| 425 | goto error_1; | 339 | goto error_1; |
| 426 | #ifdef CONFIG_NFS_V4 | ||
| 427 | ret = register_filesystem(&nfs4_fs_type); | ||
| 428 | if (ret < 0) | ||
| 429 | goto error_2; | ||
| 430 | #endif | ||
| 431 | register_shrinker(&acl_shrinker); | 340 | register_shrinker(&acl_shrinker); |
| 432 | return 0; | 341 | return 0; |
| 433 | 342 | ||
| 434 | #ifdef CONFIG_NFS_V4 | ||
| 435 | error_2: | ||
| 436 | nfs_unregister_sysctl(); | ||
| 437 | #endif | ||
| 438 | error_1: | 343 | error_1: |
| 439 | unregister_filesystem(&nfs_fs_type); | 344 | unregister_filesystem(&nfs_fs_type); |
| 440 | error_0: | 345 | error_0: |
| @@ -447,9 +352,6 @@ error_0: | |||
| 447 | void __exit unregister_nfs_fs(void) | 352 | void __exit unregister_nfs_fs(void) |
| 448 | { | 353 | { |
| 449 | unregister_shrinker(&acl_shrinker); | 354 | unregister_shrinker(&acl_shrinker); |
| 450 | #ifdef CONFIG_NFS_V4 | ||
| 451 | unregister_filesystem(&nfs4_fs_type); | ||
| 452 | #endif | ||
| 453 | nfs_unregister_sysctl(); | 355 | nfs_unregister_sysctl(); |
| 454 | unregister_filesystem(&nfs_fs_type); | 356 | unregister_filesystem(&nfs_fs_type); |
| 455 | } | 357 | } |
| @@ -473,7 +375,7 @@ void nfs_sb_deactive(struct super_block *sb) | |||
| 473 | /* | 375 | /* |
| 474 | * Deliver file system statistics to userspace | 376 | * Deliver file system statistics to userspace |
| 475 | */ | 377 | */ |
| 476 | static int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) | 378 | int nfs_statfs(struct dentry *dentry, struct kstatfs *buf) |
| 477 | { | 379 | { |
| 478 | struct nfs_server *server = NFS_SB(dentry->d_sb); | 380 | struct nfs_server *server = NFS_SB(dentry->d_sb); |
| 479 | unsigned char blockbits; | 381 | unsigned char blockbits; |
| @@ -756,7 +658,7 @@ static void nfs_show_mount_options(struct seq_file *m, struct nfs_server *nfss, | |||
| 756 | /* | 658 | /* |
| 757 | * Describe the mount options on this VFS mountpoint | 659 | * Describe the mount options on this VFS mountpoint |
| 758 | */ | 660 | */ |
| 759 | static int nfs_show_options(struct seq_file *m, struct dentry *root) | 661 | int nfs_show_options(struct seq_file *m, struct dentry *root) |
| 760 | { | 662 | { |
| 761 | struct nfs_server *nfss = NFS_SB(root->d_sb); | 663 | struct nfs_server *nfss = NFS_SB(root->d_sb); |
| 762 | 664 | ||
| @@ -814,7 +716,7 @@ static void show_implementation_id(struct seq_file *m, struct nfs_server *nfss) | |||
| 814 | } | 716 | } |
| 815 | #endif | 717 | #endif |
| 816 | 718 | ||
| 817 | static int nfs_show_devname(struct seq_file *m, struct dentry *root) | 719 | int nfs_show_devname(struct seq_file *m, struct dentry *root) |
| 818 | { | 720 | { |
| 819 | char *page = (char *) __get_free_page(GFP_KERNEL); | 721 | char *page = (char *) __get_free_page(GFP_KERNEL); |
| 820 | char *devname, *dummy; | 722 | char *devname, *dummy; |
| @@ -830,7 +732,7 @@ static int nfs_show_devname(struct seq_file *m, struct dentry *root) | |||
| 830 | return err; | 732 | return err; |
| 831 | } | 733 | } |
| 832 | 734 | ||
| 833 | static int nfs_show_path(struct seq_file *m, struct dentry *dentry) | 735 | int nfs_show_path(struct seq_file *m, struct dentry *dentry) |
| 834 | { | 736 | { |
| 835 | seq_puts(m, "/"); | 737 | seq_puts(m, "/"); |
| 836 | return 0; | 738 | return 0; |
| @@ -839,7 +741,7 @@ static int nfs_show_path(struct seq_file *m, struct dentry *dentry) | |||
| 839 | /* | 741 | /* |
| 840 | * Present statistical information for this VFS mountpoint | 742 | * Present statistical information for this VFS mountpoint |
| 841 | */ | 743 | */ |
| 842 | static int nfs_show_stats(struct seq_file *m, struct dentry *root) | 744 | int nfs_show_stats(struct seq_file *m, struct dentry *root) |
| 843 | { | 745 | { |
| 844 | int i, cpu; | 746 | int i, cpu; |
| 845 | struct nfs_server *nfss = NFS_SB(root->d_sb); | 747 | struct nfs_server *nfss = NFS_SB(root->d_sb); |
| @@ -932,7 +834,7 @@ static int nfs_show_stats(struct seq_file *m, struct dentry *root) | |||
| 932 | * Begin unmount by attempting to remove all automounted mountpoints we added | 834 | * Begin unmount by attempting to remove all automounted mountpoints we added |
| 933 | * in response to xdev traversals and referrals | 835 | * in response to xdev traversals and referrals |
| 934 | */ | 836 | */ |
| 935 | static void nfs_umount_begin(struct super_block *sb) | 837 | void nfs_umount_begin(struct super_block *sb) |
| 936 | { | 838 | { |
| 937 | struct nfs_server *server; | 839 | struct nfs_server *server; |
| 938 | struct rpc_clnt *rpc; | 840 | struct rpc_clnt *rpc; |
| @@ -2107,7 +2009,7 @@ nfs_compare_remount_data(struct nfs_server *nfss, | |||
| 2107 | return 0; | 2009 | return 0; |
| 2108 | } | 2010 | } |
| 2109 | 2011 | ||
| 2110 | static int | 2012 | int |
| 2111 | nfs_remount(struct super_block *sb, int *flags, char *raw_data) | 2013 | nfs_remount(struct super_block *sb, int *flags, char *raw_data) |
| 2112 | { | 2014 | { |
| 2113 | int error; | 2015 | int error; |
| @@ -2172,7 +2074,7 @@ out: | |||
| 2172 | /* | 2074 | /* |
| 2173 | * Initialise the common bits of the superblock | 2075 | * Initialise the common bits of the superblock |
| 2174 | */ | 2076 | */ |
| 2175 | static inline void nfs_initialise_sb(struct super_block *sb) | 2077 | inline void nfs_initialise_sb(struct super_block *sb) |
| 2176 | { | 2078 | { |
| 2177 | struct nfs_server *server = NFS_SB(sb); | 2079 | struct nfs_server *server = NFS_SB(sb); |
| 2178 | 2080 | ||
| @@ -2194,8 +2096,7 @@ static inline void nfs_initialise_sb(struct super_block *sb) | |||
| 2194 | /* | 2096 | /* |
| 2195 | * Finish setting up an NFS2/3 superblock | 2097 | * Finish setting up an NFS2/3 superblock |
| 2196 | */ | 2098 | */ |
| 2197 | static void nfs_fill_super(struct super_block *sb, | 2099 | void nfs_fill_super(struct super_block *sb, struct nfs_mount_info *mount_info) |
| 2198 | struct nfs_mount_info *mount_info) | ||
| 2199 | { | 2100 | { |
| 2200 | struct nfs_parsed_mount_data *data = mount_info->parsed; | 2101 | struct nfs_parsed_mount_data *data = mount_info->parsed; |
| 2201 | struct nfs_server *server = NFS_SB(sb); | 2102 | struct nfs_server *server = NFS_SB(sb); |
| @@ -2220,8 +2121,7 @@ static void nfs_fill_super(struct super_block *sb, | |||
| 2220 | /* | 2121 | /* |
| 2221 | * Finish setting up a cloned NFS2/3/4 superblock | 2122 | * Finish setting up a cloned NFS2/3/4 superblock |
| 2222 | */ | 2123 | */ |
| 2223 | static void nfs_clone_super(struct super_block *sb, | 2124 | void nfs_clone_super(struct super_block *sb, struct nfs_mount_info *mount_info) |
| 2224 | struct nfs_mount_info *mount_info) | ||
| 2225 | { | 2125 | { |
| 2226 | const struct super_block *old_sb = mount_info->cloned->sb; | 2126 | const struct super_block *old_sb = mount_info->cloned->sb; |
| 2227 | struct nfs_server *server = NFS_SB(sb); | 2127 | struct nfs_server *server = NFS_SB(sb); |
| @@ -2381,14 +2281,14 @@ static int nfs_bdi_register(struct nfs_server *server) | |||
| 2381 | return bdi_register_dev(&server->backing_dev_info, server->s_dev); | 2281 | return bdi_register_dev(&server->backing_dev_info, server->s_dev); |
| 2382 | } | 2282 | } |
| 2383 | 2283 | ||
| 2384 | static int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot, | 2284 | int nfs_set_sb_security(struct super_block *s, struct dentry *mntroot, |
| 2385 | struct nfs_mount_info *mount_info) | 2285 | struct nfs_mount_info *mount_info) |
| 2386 | { | 2286 | { |
| 2387 | return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts); | 2287 | return security_sb_set_mnt_opts(s, &mount_info->parsed->lsm_opts); |
| 2388 | } | 2288 | } |
| 2389 | 2289 | ||
| 2390 | static int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, | 2290 | int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, |
| 2391 | struct nfs_mount_info *mount_info) | 2291 | struct nfs_mount_info *mount_info) |
| 2392 | { | 2292 | { |
| 2393 | /* clone any lsm security options from the parent to the new sb */ | 2293 | /* clone any lsm security options from the parent to the new sb */ |
| 2394 | security_sb_clone_mnt_opts(mount_info->cloned->sb, s); | 2294 | security_sb_clone_mnt_opts(mount_info->cloned->sb, s); |
| @@ -2397,10 +2297,10 @@ static int nfs_clone_sb_security(struct super_block *s, struct dentry *mntroot, | |||
| 2397 | return 0; | 2297 | return 0; |
| 2398 | } | 2298 | } |
| 2399 | 2299 | ||
| 2400 | static struct dentry *nfs_fs_mount_common(struct file_system_type *fs_type, | 2300 | struct dentry *nfs_fs_mount_common(struct file_system_type *fs_type, |
| 2401 | struct nfs_server *server, | 2301 | struct nfs_server *server, |
| 2402 | int flags, const char *dev_name, | 2302 | int flags, const char *dev_name, |
| 2403 | struct nfs_mount_info *mount_info) | 2303 | struct nfs_mount_info *mount_info) |
| 2404 | { | 2304 | { |
| 2405 | struct super_block *s; | 2305 | struct super_block *s; |
| 2406 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | 2306 | struct dentry *mntroot = ERR_PTR(-ENOMEM); |
| @@ -2470,7 +2370,7 @@ error_splat_bdi: | |||
| 2470 | goto out; | 2370 | goto out; |
| 2471 | } | 2371 | } |
| 2472 | 2372 | ||
| 2473 | static struct dentry *nfs_fs_mount(struct file_system_type *fs_type, | 2373 | struct dentry *nfs_fs_mount(struct file_system_type *fs_type, |
| 2474 | int flags, const char *dev_name, void *raw_data) | 2374 | int flags, const char *dev_name, void *raw_data) |
| 2475 | { | 2375 | { |
| 2476 | struct nfs_mount_info mount_info = { | 2376 | struct nfs_mount_info mount_info = { |
| @@ -2511,7 +2411,7 @@ out: | |||
| 2511 | * Ensure that we unregister the bdi before kill_anon_super | 2411 | * Ensure that we unregister the bdi before kill_anon_super |
| 2512 | * releases the device name | 2412 | * releases the device name |
| 2513 | */ | 2413 | */ |
| 2514 | static void nfs_put_super(struct super_block *s) | 2414 | void nfs_put_super(struct super_block *s) |
| 2515 | { | 2415 | { |
| 2516 | struct nfs_server *server = NFS_SB(s); | 2416 | struct nfs_server *server = NFS_SB(s); |
| 2517 | 2417 | ||
| @@ -2521,7 +2421,7 @@ static void nfs_put_super(struct super_block *s) | |||
| 2521 | /* | 2421 | /* |
| 2522 | * Destroy an NFS2/3 superblock | 2422 | * Destroy an NFS2/3 superblock |
| 2523 | */ | 2423 | */ |
| 2524 | static void nfs_kill_super(struct super_block *s) | 2424 | void nfs_kill_super(struct super_block *s) |
| 2525 | { | 2425 | { |
| 2526 | struct nfs_server *server = NFS_SB(s); | 2426 | struct nfs_server *server = NFS_SB(s); |
| 2527 | 2427 | ||
| @@ -2533,7 +2433,7 @@ static void nfs_kill_super(struct super_block *s) | |||
| 2533 | /* | 2433 | /* |
| 2534 | * Clone an NFS2/3/4 server record on xdev traversal (FSID-change) | 2434 | * Clone an NFS2/3/4 server record on xdev traversal (FSID-change) |
| 2535 | */ | 2435 | */ |
| 2536 | static struct dentry * | 2436 | struct dentry * |
| 2537 | nfs_xdev_mount_common(struct file_system_type *fs_type, int flags, | 2437 | nfs_xdev_mount_common(struct file_system_type *fs_type, int flags, |
| 2538 | const char *dev_name, struct nfs_mount_info *mount_info) | 2438 | const char *dev_name, struct nfs_mount_info *mount_info) |
| 2539 | { | 2439 | { |
| @@ -2580,23 +2480,6 @@ nfs_xdev_mount(struct file_system_type *fs_type, int flags, | |||
| 2580 | 2480 | ||
| 2581 | #ifdef CONFIG_NFS_V4 | 2481 | #ifdef CONFIG_NFS_V4 |
| 2582 | 2482 | ||
| 2583 | /* | ||
| 2584 | * Set up an NFS4 superblock | ||
| 2585 | */ | ||
| 2586 | static void nfs4_fill_super(struct super_block *sb, | ||
| 2587 | struct nfs_mount_info *mount_info) | ||
| 2588 | { | ||
| 2589 | sb->s_time_gran = 1; | ||
| 2590 | sb->s_op = &nfs4_sops; | ||
| 2591 | /* | ||
| 2592 | * The VFS shouldn't apply the umask to mode bits. We will do | ||
| 2593 | * so ourselves when necessary. | ||
| 2594 | */ | ||
| 2595 | sb->s_flags |= MS_POSIXACL; | ||
| 2596 | sb->s_xattr = nfs4_xattr_handlers; | ||
| 2597 | nfs_initialise_sb(sb); | ||
| 2598 | } | ||
| 2599 | |||
| 2600 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) | 2483 | static void nfs4_validate_mount_flags(struct nfs_parsed_mount_data *args) |
| 2601 | { | 2484 | { |
| 2602 | args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3| | 2485 | args->flags &= ~(NFS_MOUNT_NONLM|NFS_MOUNT_NOACL|NFS_MOUNT_VER3| |
| @@ -2694,238 +2577,4 @@ out_no_address: | |||
| 2694 | return -EINVAL; | 2577 | return -EINVAL; |
| 2695 | } | 2578 | } |
| 2696 | 2579 | ||
| 2697 | /* | ||
| 2698 | * Get the superblock for the NFS4 root partition | ||
| 2699 | */ | ||
| 2700 | static struct dentry * | ||
| 2701 | nfs4_remote_mount(struct file_system_type *fs_type, int flags, | ||
| 2702 | const char *dev_name, void *info) | ||
| 2703 | { | ||
| 2704 | struct nfs_mount_info *mount_info = info; | ||
| 2705 | struct nfs_server *server; | ||
| 2706 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | ||
| 2707 | |||
| 2708 | mount_info->fill_super = nfs4_fill_super; | ||
| 2709 | mount_info->set_security = nfs_set_sb_security; | ||
| 2710 | |||
| 2711 | /* Get a volume representation */ | ||
| 2712 | server = nfs4_create_server(mount_info->parsed, mount_info->mntfh); | ||
| 2713 | if (IS_ERR(server)) { | ||
| 2714 | mntroot = ERR_CAST(server); | ||
| 2715 | goto out; | ||
| 2716 | } | ||
| 2717 | |||
| 2718 | mntroot = nfs_fs_mount_common(fs_type, server, flags, dev_name, mount_info); | ||
| 2719 | |||
| 2720 | out: | ||
| 2721 | return mntroot; | ||
| 2722 | } | ||
| 2723 | |||
| 2724 | static struct vfsmount *nfs_do_root_mount(struct file_system_type *fs_type, | ||
| 2725 | int flags, void *data, const char *hostname) | ||
| 2726 | { | ||
| 2727 | struct vfsmount *root_mnt; | ||
| 2728 | char *root_devname; | ||
| 2729 | size_t len; | ||
| 2730 | |||
| 2731 | len = strlen(hostname) + 5; | ||
| 2732 | root_devname = kmalloc(len, GFP_KERNEL); | ||
| 2733 | if (root_devname == NULL) | ||
| 2734 | return ERR_PTR(-ENOMEM); | ||
| 2735 | /* Does hostname needs to be enclosed in brackets? */ | ||
| 2736 | if (strchr(hostname, ':')) | ||
| 2737 | snprintf(root_devname, len, "[%s]:/", hostname); | ||
| 2738 | else | ||
| 2739 | snprintf(root_devname, len, "%s:/", hostname); | ||
| 2740 | root_mnt = vfs_kern_mount(fs_type, flags, root_devname, data); | ||
| 2741 | kfree(root_devname); | ||
| 2742 | return root_mnt; | ||
| 2743 | } | ||
| 2744 | |||
| 2745 | struct nfs_referral_count { | ||
| 2746 | struct list_head list; | ||
| 2747 | const struct task_struct *task; | ||
| 2748 | unsigned int referral_count; | ||
| 2749 | }; | ||
| 2750 | |||
| 2751 | static LIST_HEAD(nfs_referral_count_list); | ||
| 2752 | static DEFINE_SPINLOCK(nfs_referral_count_list_lock); | ||
| 2753 | |||
| 2754 | static struct nfs_referral_count *nfs_find_referral_count(void) | ||
| 2755 | { | ||
| 2756 | struct nfs_referral_count *p; | ||
| 2757 | |||
| 2758 | list_for_each_entry(p, &nfs_referral_count_list, list) { | ||
| 2759 | if (p->task == current) | ||
| 2760 | return p; | ||
| 2761 | } | ||
| 2762 | return NULL; | ||
| 2763 | } | ||
| 2764 | |||
| 2765 | #define NFS_MAX_NESTED_REFERRALS 2 | ||
| 2766 | |||
| 2767 | static int nfs_referral_loop_protect(void) | ||
| 2768 | { | ||
| 2769 | struct nfs_referral_count *p, *new; | ||
| 2770 | int ret = -ENOMEM; | ||
| 2771 | |||
| 2772 | new = kmalloc(sizeof(*new), GFP_KERNEL); | ||
| 2773 | if (!new) | ||
| 2774 | goto out; | ||
| 2775 | new->task = current; | ||
| 2776 | new->referral_count = 1; | ||
| 2777 | |||
| 2778 | ret = 0; | ||
| 2779 | spin_lock(&nfs_referral_count_list_lock); | ||
| 2780 | p = nfs_find_referral_count(); | ||
| 2781 | if (p != NULL) { | ||
| 2782 | if (p->referral_count >= NFS_MAX_NESTED_REFERRALS) | ||
| 2783 | ret = -ELOOP; | ||
| 2784 | else | ||
| 2785 | p->referral_count++; | ||
| 2786 | } else { | ||
| 2787 | list_add(&new->list, &nfs_referral_count_list); | ||
| 2788 | new = NULL; | ||
| 2789 | } | ||
| 2790 | spin_unlock(&nfs_referral_count_list_lock); | ||
| 2791 | kfree(new); | ||
| 2792 | out: | ||
| 2793 | return ret; | ||
| 2794 | } | ||
| 2795 | |||
| 2796 | static void nfs_referral_loop_unprotect(void) | ||
| 2797 | { | ||
| 2798 | struct nfs_referral_count *p; | ||
| 2799 | |||
| 2800 | spin_lock(&nfs_referral_count_list_lock); | ||
| 2801 | p = nfs_find_referral_count(); | ||
| 2802 | p->referral_count--; | ||
| 2803 | if (p->referral_count == 0) | ||
| 2804 | list_del(&p->list); | ||
| 2805 | else | ||
| 2806 | p = NULL; | ||
| 2807 | spin_unlock(&nfs_referral_count_list_lock); | ||
| 2808 | kfree(p); | ||
| 2809 | } | ||
| 2810 | |||
| 2811 | static struct dentry *nfs_follow_remote_path(struct vfsmount *root_mnt, | ||
| 2812 | const char *export_path) | ||
| 2813 | { | ||
| 2814 | struct dentry *dentry; | ||
| 2815 | int err; | ||
| 2816 | |||
| 2817 | if (IS_ERR(root_mnt)) | ||
| 2818 | return ERR_CAST(root_mnt); | ||
| 2819 | |||
| 2820 | err = nfs_referral_loop_protect(); | ||
| 2821 | if (err) { | ||
| 2822 | mntput(root_mnt); | ||
| 2823 | return ERR_PTR(err); | ||
| 2824 | } | ||
| 2825 | |||
| 2826 | dentry = mount_subtree(root_mnt, export_path); | ||
| 2827 | nfs_referral_loop_unprotect(); | ||
| 2828 | |||
| 2829 | return dentry; | ||
| 2830 | } | ||
| 2831 | |||
| 2832 | static struct dentry *nfs4_try_mount(int flags, const char *dev_name, | ||
| 2833 | struct nfs_mount_info *mount_info) | ||
| 2834 | { | ||
| 2835 | char *export_path; | ||
| 2836 | struct vfsmount *root_mnt; | ||
| 2837 | struct dentry *res; | ||
| 2838 | struct nfs_parsed_mount_data *data = mount_info->parsed; | ||
| 2839 | |||
| 2840 | dfprintk(MOUNT, "--> nfs4_try_mount()\n"); | ||
| 2841 | |||
| 2842 | mount_info->fill_super = nfs4_fill_super; | ||
| 2843 | |||
| 2844 | export_path = data->nfs_server.export_path; | ||
| 2845 | data->nfs_server.export_path = "/"; | ||
| 2846 | root_mnt = nfs_do_root_mount(&nfs4_remote_fs_type, flags, mount_info, | ||
| 2847 | data->nfs_server.hostname); | ||
| 2848 | data->nfs_server.export_path = export_path; | ||
| 2849 | |||
| 2850 | res = nfs_follow_remote_path(root_mnt, export_path); | ||
| 2851 | |||
| 2852 | dfprintk(MOUNT, "<-- nfs4_try_mount() = %ld%s\n", | ||
| 2853 | IS_ERR(res) ? PTR_ERR(res) : 0, | ||
| 2854 | IS_ERR(res) ? " [error]" : ""); | ||
| 2855 | return res; | ||
| 2856 | } | ||
| 2857 | |||
| 2858 | /* | ||
| 2859 | * Clone an NFS4 server record on xdev traversal (FSID-change) | ||
| 2860 | */ | ||
| 2861 | static struct dentry * | ||
| 2862 | nfs4_xdev_mount(struct file_system_type *fs_type, int flags, | ||
| 2863 | const char *dev_name, void *raw_data) | ||
| 2864 | { | ||
| 2865 | struct nfs_mount_info mount_info = { | ||
| 2866 | .fill_super = nfs_clone_super, | ||
| 2867 | .set_security = nfs_clone_sb_security, | ||
| 2868 | .cloned = raw_data, | ||
| 2869 | }; | ||
| 2870 | return nfs_xdev_mount_common(&nfs4_fs_type, flags, dev_name, &mount_info); | ||
| 2871 | } | ||
| 2872 | |||
| 2873 | static struct dentry * | ||
| 2874 | nfs4_remote_referral_mount(struct file_system_type *fs_type, int flags, | ||
| 2875 | const char *dev_name, void *raw_data) | ||
| 2876 | { | ||
| 2877 | struct nfs_mount_info mount_info = { | ||
| 2878 | .fill_super = nfs4_fill_super, | ||
| 2879 | .set_security = nfs_clone_sb_security, | ||
| 2880 | .cloned = raw_data, | ||
| 2881 | }; | ||
| 2882 | struct nfs_server *server; | ||
| 2883 | struct dentry *mntroot = ERR_PTR(-ENOMEM); | ||
| 2884 | |||
| 2885 | dprintk("--> nfs4_referral_get_sb()\n"); | ||
| 2886 | |||
| 2887 | mount_info.mntfh = nfs_alloc_fhandle(); | ||
| 2888 | if (mount_info.cloned == NULL || mount_info.mntfh == NULL) | ||
| 2889 | goto out; | ||
| 2890 | |||
| 2891 | /* create a new volume representation */ | ||
| 2892 | server = nfs4_create_referral_server(mount_info.cloned, mount_info.mntfh); | ||
| 2893 | if (IS_ERR(server)) { | ||
| 2894 | mntroot = ERR_CAST(server); | ||
| 2895 | goto out; | ||
| 2896 | } | ||
| 2897 | |||
| 2898 | mntroot = nfs_fs_mount_common(&nfs4_fs_type, server, flags, dev_name, &mount_info); | ||
| 2899 | out: | ||
| 2900 | nfs_free_fhandle(mount_info.mntfh); | ||
| 2901 | return mntroot; | ||
| 2902 | } | ||
| 2903 | |||
| 2904 | /* | ||
| 2905 | * Create an NFS4 server record on referral traversal | ||
| 2906 | */ | ||
| 2907 | static struct dentry *nfs4_referral_mount(struct file_system_type *fs_type, | ||
| 2908 | int flags, const char *dev_name, void *raw_data) | ||
| 2909 | { | ||
| 2910 | struct nfs_clone_mount *data = raw_data; | ||
| 2911 | char *export_path; | ||
| 2912 | struct vfsmount *root_mnt; | ||
| 2913 | struct dentry *res; | ||
| 2914 | |||
| 2915 | dprintk("--> nfs4_referral_mount()\n"); | ||
| 2916 | |||
| 2917 | export_path = data->mnt_path; | ||
| 2918 | data->mnt_path = "/"; | ||
| 2919 | |||
| 2920 | root_mnt = nfs_do_root_mount(&nfs4_remote_referral_fs_type, | ||
| 2921 | flags, data, data->hostname); | ||
| 2922 | data->mnt_path = export_path; | ||
| 2923 | |||
| 2924 | res = nfs_follow_remote_path(root_mnt, export_path); | ||
| 2925 | dprintk("<-- nfs4_referral_mount() = %ld%s\n", | ||
| 2926 | IS_ERR(res) ? PTR_ERR(res) : 0, | ||
| 2927 | IS_ERR(res) ? " [error]" : ""); | ||
| 2928 | return res; | ||
| 2929 | } | ||
| 2930 | |||
| 2931 | #endif /* CONFIG_NFS_V4 */ | 2580 | #endif /* CONFIG_NFS_V4 */ |
