⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 super.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
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 + -