📄 super.c
字号:
out_unrec_xprt: printk(KERN_INFO "NFS: unrecognized transport protocol\n"); return 0;out_unrec_sec: printk(KERN_INFO "NFS: unrecognized security flavor\n"); return 0;out_unknown: printk(KERN_INFO "NFS: unknown mount option: %s\n", p); return 0;}/* * Use the remote server's MOUNT service to request the NFS file handle * corresponding to the provided path. */static int nfs_try_mount(struct nfs_parsed_mount_data *args, struct nfs_fh *root_fh){ struct sockaddr_in sin; int status; if (args->mount_server.version == 0) { if (args->flags & NFS_MOUNT_VER3) args->mount_server.version = NFS_MNT3_VERSION; else args->mount_server.version = NFS_MNT_VERSION; } /* * Construct the mount server's address. */ if (args->mount_server.address.sin_addr.s_addr != INADDR_ANY) sin = args->mount_server.address; else sin = args->nfs_server.address; /* * autobind will be used if mount_server.port == 0 */ sin.sin_port = htons(args->mount_server.port); /* * Now ask the mount server to map our export path * to a file handle. */ status = nfs_mount((struct sockaddr *) &sin, sizeof(sin), args->nfs_server.hostname, args->nfs_server.export_path, args->mount_server.version, args->mount_server.protocol, root_fh); if (status == 0) return 0; dfprintk(MOUNT, "NFS: unable to mount server " NIPQUAD_FMT ", error %d\n", NIPQUAD(sin.sin_addr.s_addr), status); return status;}/* * Validate the NFS2/NFS3 mount data * - fills in the mount root filehandle * * For option strings, user space handles the following behaviors: * * + DNS: mapping server host name to IP address ("addr=" option) * * + failure mode: how to behave if a mount request can't be handled * immediately ("fg/bg" option) * * + retry: how often to retry a mount request ("retry=" option) * * + breaking back: trying proto=udp after proto=tcp, v2 after v3, * mountproto=tcp after mountproto=udp, and so on * * XXX: as far as I can tell, changing the NFS program number is not * supported in the NFS client. */static int nfs_validate_mount_data(void *options, struct nfs_parsed_mount_data *args, struct nfs_fh *mntfh, const char *dev_name){ struct nfs_mount_data *data = (struct nfs_mount_data *)options; memset(args, 0, sizeof(*args)); if (data == NULL) goto out_no_data; args->flags = (NFS_MOUNT_VER3 | NFS_MOUNT_TCP); args->rsize = NFS_MAX_FILE_IO_SIZE; args->wsize = NFS_MAX_FILE_IO_SIZE; args->timeo = 600; args->retrans = 2; args->acregmin = 3; args->acregmax = 60; args->acdirmin = 30; args->acdirmax = 60; args->mount_server.protocol = XPRT_TRANSPORT_UDP; args->mount_server.program = NFS_MNT_PROGRAM; args->nfs_server.protocol = XPRT_TRANSPORT_TCP; args->nfs_server.program = NFS_PROGRAM; switch (data->version) { case 1: data->namlen = 0; case 2: data->bsize = 0; case 3: if (data->flags & NFS_MOUNT_VER3) goto out_no_v3; data->root.size = NFS2_FHSIZE; memcpy(data->root.data, data->old_root.data, NFS2_FHSIZE); case 4: if (data->flags & NFS_MOUNT_SECFLAVOUR) goto out_no_sec; case 5: memset(data->context, 0, sizeof(data->context)); case 6: if (data->flags & NFS_MOUNT_VER3) mntfh->size = data->root.size; else mntfh->size = NFS2_FHSIZE; if (mntfh->size > sizeof(mntfh->data)) goto out_invalid_fh; memcpy(mntfh->data, data->root.data, mntfh->size); if (mntfh->size < sizeof(mntfh->data)) memset(mntfh->data + mntfh->size, 0, sizeof(mntfh->data) - mntfh->size); if (!nfs_verify_server_address((struct sockaddr *) &data->addr)) goto out_no_address; /* * Translate to nfs_parsed_mount_data, which nfs_fill_super * can deal with. */ args->flags = data->flags; args->rsize = data->rsize; args->wsize = data->wsize; args->flags = data->flags; args->timeo = data->timeo; args->retrans = data->retrans; args->acregmin = data->acregmin; args->acregmax = data->acregmax; args->acdirmin = data->acdirmin; args->acdirmax = data->acdirmax; args->nfs_server.address = data->addr; if (!(data->flags & NFS_MOUNT_TCP)) args->nfs_server.protocol = XPRT_TRANSPORT_UDP; /* N.B. caller will free nfs_server.hostname in all cases */ args->nfs_server.hostname = kstrdup(data->hostname, GFP_KERNEL); args->namlen = data->namlen; args->bsize = data->bsize; args->auth_flavors[0] = data->pseudoflavor; break; default: { unsigned int len; char *c; int status; if (nfs_parse_mount_options((char *)options, args) == 0) return -EINVAL; if (!nfs_verify_server_address((struct sockaddr *) &args->nfs_server.address)) goto out_no_address; c = strchr(dev_name, ':'); if (c == NULL) return -EINVAL; len = c - dev_name; /* N.B. caller will free nfs_server.hostname in all cases */ args->nfs_server.hostname = kstrndup(dev_name, len, GFP_KERNEL); c++; if (strlen(c) > NFS_MAXPATHLEN) return -ENAMETOOLONG; args->nfs_server.export_path = c; status = nfs_try_mount(args, mntfh); if (status) return status; break; } } if (!(args->flags & NFS_MOUNT_SECFLAVOUR)) args->auth_flavors[0] = RPC_AUTH_UNIX;#ifndef CONFIG_NFS_V3 if (args->flags & NFS_MOUNT_VER3) goto out_v3_not_compiled;#endif /* !CONFIG_NFS_V3 */ return 0;out_no_data: dfprintk(MOUNT, "NFS: mount program didn't pass any mount data\n"); return -EINVAL;out_no_v3: dfprintk(MOUNT, "NFS: nfs_mount_data version %d does not support v3\n", data->version); return -EINVAL;out_no_sec: dfprintk(MOUNT, "NFS: nfs_mount_data version supports only AUTH_SYS\n"); return -EINVAL;#ifndef CONFIG_NFS_V3out_v3_not_compiled: dfprintk(MOUNT, "NFS: NFSv3 is not compiled into kernel\n"); return -EPROTONOSUPPORT;#endif /* !CONFIG_NFS_V3 */out_no_address: dfprintk(MOUNT, "NFS: mount program didn't pass remote address\n"); return -EINVAL;out_invalid_fh: dfprintk(MOUNT, "NFS: invalid root filehandle\n"); return -EINVAL;}/* * Initialise the common bits of the superblock */static inline void nfs_initialise_sb(struct super_block *sb){ struct nfs_server *server = NFS_SB(sb); sb->s_magic = NFS_SUPER_MAGIC; /* We probably want something more informative here */ snprintf(sb->s_id, sizeof(sb->s_id), "%x:%x", MAJOR(sb->s_dev), MINOR(sb->s_dev)); if (sb->s_blocksize == 0) sb->s_blocksize = nfs_block_bits(server->wsize, &sb->s_blocksize_bits); if (server->flags & NFS_MOUNT_NOAC) sb->s_flags |= MS_SYNCHRONOUS; nfs_super_set_maxbytes(sb, server->maxfilesize);}/* * Finish setting up an NFS2/3 superblock */static void nfs_fill_super(struct super_block *sb, struct nfs_parsed_mount_data *data){ struct nfs_server *server = NFS_SB(sb); sb->s_blocksize_bits = 0; sb->s_blocksize = 0; if (data->bsize) sb->s_blocksize = nfs_block_size(data->bsize, &sb->s_blocksize_bits); if (server->flags & NFS_MOUNT_VER3) { /* The VFS shouldn't apply the umask to mode bits. We will do * so ourselves when necessary. */ sb->s_flags |= MS_POSIXACL; sb->s_time_gran = 1; } sb->s_op = &nfs_sops; nfs_initialise_sb(sb);}/* * Finish setting up a cloned NFS2/3 superblock */static void nfs_clone_super(struct super_block *sb, const struct super_block *old_sb){ struct nfs_server *server = NFS_SB(sb); sb->s_blocksize_bits = old_sb->s_blocksize_bits; sb->s_blocksize = old_sb->s_blocksize; sb->s_maxbytes = old_sb->s_maxbytes; if (server->flags & NFS_MOUNT_VER3) { /* The VFS shouldn't apply the umask to mode bits. We will do * so ourselves when necessary. */ sb->s_flags |= MS_POSIXACL; sb->s_time_gran = 1; } sb->s_op = old_sb->s_op; nfs_initialise_sb(sb);}#define NFS_MS_MASK (MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|MS_SYNCHRONOUS)static int nfs_compare_mount_options(const struct super_block *s, const struct nfs_server *b, int flags){ const struct nfs_server *a = s->s_fs_info; const struct rpc_clnt *clnt_a = a->client; const struct rpc_clnt *clnt_b = b->client; if ((s->s_flags & NFS_MS_MASK) != (flags & NFS_MS_MASK)) goto Ebusy; if (a->nfs_client != b->nfs_client) goto Ebusy; if (a->flags != b->flags) goto Ebusy; if (a->wsize != b->wsize) goto Ebusy; if (a->rsize != b->rsize) goto Ebusy; if (a->acregmin != b->acregmin) goto Ebusy; if (a->acregmax != b->acregmax) goto Ebusy; if (a->acdirmin != b->acdirmin) goto Ebusy; if (a->acdirmax != b->acdirmax) goto Ebusy; if (clnt_a->cl_auth->au_flavor != clnt_b->cl_auth->au_flavor) goto Ebusy; return 1;Ebusy: return 0;}struct nfs_sb_mountdata { struct nfs_server *server; int mntflags;};static int nfs_set_super(struct super_block *s, void *data){ struct nfs_sb_mountdata *sb_mntdata = data; struct nfs_server *server = sb_mntdata->server; int ret; s->s_flags = sb_mntdata->mntflags; s->s_fs_info = server; ret = set_anon_super(s, server); if (ret == 0) server->s_dev = s->s_dev; return ret;}static int nfs_compare_super(struct super_block *sb, void *data){ struct nfs_sb_mountdata *sb_mntdata = data; struct nfs_server *server = sb_mntdata->server, *old = NFS_SB(sb); int mntflags = sb_mntdata->mntflags; if (memcmp(&old->nfs_client->cl_addr, &server->nfs_client->cl_addr, sizeof(old->nfs_client->cl_addr)) != 0) return 0; /* Note: NFS_MOUNT_UNSHARED == NFS4_MOUNT_UNSHARED */ if (old->flags & NFS_MOUNT_UNSHARED) return 0; if (memcmp(&old->fsid, &server->fsid, sizeof(old->fsid)) != 0) return 0; return nfs_compare_mount_options(sb, server, mntflags);}static int nfs_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt){ struct nfs_server *server = NULL; struct super_block *s; struct nfs_fh mntfh; struct nfs_parsed_mount_data data; struct dentry *mntroot; int (*compare_super)(struct super_block *, void *) = nfs_compare_super; struct nfs_sb_mountdata sb_mntdata = { .mntflags = flags, }; int error; /* Validate the mount data */ error = nfs_validate_mount_data(raw_data, &data, &mntfh, dev_name); if (error < 0) goto out; /* Get a volume representation */ server = nfs_create_server(&data, &mntfh); if (IS_ERR(server)) { error = PTR_ERR(server); goto out; } sb_mntdata.server = server; if (server->flags & NFS_MOUNT_UNSHARED) compare_super = NULL; /* Get a superblock - note that we may end up sharing one that already exists */ s = sget(fs_type, compare_super, nfs_set_super, &sb_mntdata); if (IS_ERR(s)) { error = PTR_ERR(s); goto out_err_nosb; } if (s->s_fs_info != server) { nfs_free_server(server); server = NULL; } if (!s->s_root) { /* initial superblock/root creation */ nfs_fill_super(s, &data); } mntroot = nfs_get_root(s, &mntfh); if (IS_ERR(mntroot)) { error = PTR_ERR(mntroot); goto error_splat_super; } s->s_flags |= MS_ACTIVE; mnt->mnt_sb = s; mnt->mnt_root = mntroot; error = 0;out: kfree(data.nfs_server.hostname); return error;out_err_nosb: nfs_free_server(server); goto out;error_splat_super: up_write(&s->s_umount); deactivate_super(s); goto out;}/* * Destroy an NFS2/3 superblock */static void nfs_kill_super(struct super_block *s){ struct nfs_server *server = NFS_SB(s); kill_anon_super(s); nfs_free_server(server);}/* * Clone an NFS2/3 server record on xdev traversal (FSID-change) */static int nfs_xdev_get_sb(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data, struct vfsmount *mnt){ struct nfs_clone_mount *data = raw_data; struct super_block *s; struct nfs_server *server; struct dentry *mntroot; int (*compare_super)(struct super_block *, void *) = nfs_compare_super; struct nfs_sb_mountdata sb_mntdata = { .mntflags = flags, }; int error; dprintk("--> nfs_xdev_get_sb()\n"); /* create a new volume representation */ server = nfs_clone_server(NFS_SB(data->sb), data->fh, data->fattr); if (IS_ERR(server)) { error = PTR_ERR(server); goto out_err_noserver; } sb_mntdata.server = server;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -