| /* |
| * In-kernel MOUNT protocol client |
| * |
| * Copyright (C) 1997, Olaf Kirch <okir@monad.swb.de> |
| */ |
| |
| #include <linux/types.h> |
| #include <linux/socket.h> |
| #include <linux/kernel.h> |
| #include <linux/errno.h> |
| #include <linux/uio.h> |
| #include <linux/net.h> |
| #include <linux/in.h> |
| #include <linux/sunrpc/clnt.h> |
| #include <linux/sunrpc/sched.h> |
| #include <linux/nfs_fs.h> |
| |
| #ifdef RPC_DEBUG |
| # define NFSDBG_FACILITY NFSDBG_MOUNT |
| #endif |
| |
| static struct rpc_program mnt_program; |
| |
| struct mnt_fhstatus { |
| u32 status; |
| struct nfs_fh *fh; |
| }; |
| |
| /** |
| * nfs_mount - Obtain an NFS file handle for the given host and path |
| * @addr: pointer to server's address |
| * @len: size of server's address |
| * @hostname: name of server host, or NULL |
| * @path: pointer to string containing export path to mount |
| * @version: mount version to use for this request |
| * @protocol: transport protocol to use for thie request |
| * @fh: pointer to location to place returned file handle |
| * |
| * Uses default timeout parameters specified by underlying transport. |
| */ |
| int nfs_mount(struct sockaddr *addr, size_t len, char *hostname, char *path, |
| int version, int protocol, struct nfs_fh *fh) |
| { |
| struct mnt_fhstatus result = { |
| .fh = fh |
| }; |
| struct rpc_message msg = { |
| .rpc_argp = path, |
| .rpc_resp = &result, |
| }; |
| struct rpc_create_args args = { |
| .protocol = protocol, |
| .address = addr, |
| .addrsize = len, |
| .servername = hostname, |
| .program = &mnt_program, |
| .version = version, |
| .authflavor = RPC_AUTH_UNIX, |
| .flags = 0, |
| }; |
| struct rpc_clnt *mnt_clnt; |
| int status; |
| |
| dprintk("NFS: sending MNT request for %s:%s\n", |
| (hostname ? hostname : "server"), path); |
| |
| mnt_clnt = rpc_create(&args); |
| if (IS_ERR(mnt_clnt)) |
| goto out_clnt_err; |
| |
| if (version == NFS_MNT3_VERSION) |
| msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; |
| else |
| msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT]; |
| |
| status = rpc_call_sync(mnt_clnt, &msg, 0); |
| rpc_shutdown_client(mnt_clnt); |
| |
| if (status < 0) |
| goto out_call_err; |
| if (result.status != 0) |
| goto out_mnt_err; |
| |
| dprintk("NFS: MNT request succeeded\n"); |
| status = 0; |
| |
| out: |
| return status; |
| |
| out_clnt_err: |
| status = PTR_ERR(mnt_clnt); |
| dprintk("NFS: failed to create RPC client, status=%d\n", status); |
| goto out; |
| |
| out_call_err: |
| dprintk("NFS: failed to start MNT request, status=%d\n", status); |
| goto out; |
| |
| out_mnt_err: |
| dprintk("NFS: MNT server returned result %d\n", result.status); |
| status = -EACCES; |
| goto out; |
| } |
| |
| /* |
| * XDR encode/decode functions for MOUNT |
| */ |
| static int xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, |
| const char *path) |
| { |
| p = xdr_encode_string(p, path); |
| |
| req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); |
| return 0; |
| } |
| |
| static int xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, |
| struct mnt_fhstatus *res) |
| { |
| struct nfs_fh *fh = res->fh; |
| |
| if ((res->status = ntohl(*p++)) == 0) { |
| fh->size = NFS2_FHSIZE; |
| memcpy(fh->data, p, NFS2_FHSIZE); |
| } |
| return 0; |
| } |
| |
| static int xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, |
| struct mnt_fhstatus *res) |
| { |
| struct nfs_fh *fh = res->fh; |
| unsigned size; |
| |
| if ((res->status = ntohl(*p++)) == 0) { |
| size = ntohl(*p++); |
| if (size <= NFS3_FHSIZE && size != 0) { |
| fh->size = size; |
| memcpy(fh->data, p, size); |
| } else |
| res->status = -EBADHANDLE; |
| } |
| return 0; |
| } |
| |
| #define MNT_dirpath_sz (1 + 256) |
| #define MNT_fhstatus_sz (1 + 8) |
| #define MNT_fhstatus3_sz (1 + 16) |
| |
| static struct rpc_procinfo mnt_procedures[] = { |
| [MNTPROC_MNT] = { |
| .p_proc = MNTPROC_MNT, |
| .p_encode = (kxdrproc_t) xdr_encode_dirpath, |
| .p_decode = (kxdrproc_t) xdr_decode_fhstatus, |
| .p_arglen = MNT_dirpath_sz, |
| .p_replen = MNT_fhstatus_sz, |
| .p_statidx = MNTPROC_MNT, |
| .p_name = "MOUNT", |
| }, |
| }; |
| |
| static struct rpc_procinfo mnt3_procedures[] = { |
| [MOUNTPROC3_MNT] = { |
| .p_proc = MOUNTPROC3_MNT, |
| .p_encode = (kxdrproc_t) xdr_encode_dirpath, |
| .p_decode = (kxdrproc_t) xdr_decode_fhstatus3, |
| .p_arglen = MNT_dirpath_sz, |
| .p_replen = MNT_fhstatus3_sz, |
| .p_statidx = MOUNTPROC3_MNT, |
| .p_name = "MOUNT", |
| }, |
| }; |
| |
| |
| static struct rpc_version mnt_version1 = { |
| .number = 1, |
| .nrprocs = 2, |
| .procs = mnt_procedures, |
| }; |
| |
| static struct rpc_version mnt_version3 = { |
| .number = 3, |
| .nrprocs = 2, |
| .procs = mnt3_procedures, |
| }; |
| |
| static struct rpc_version *mnt_version[] = { |
| NULL, |
| &mnt_version1, |
| NULL, |
| &mnt_version3, |
| }; |
| |
| static struct rpc_stat mnt_stats; |
| |
| static struct rpc_program mnt_program = { |
| .name = "mount", |
| .number = NFS_MNT_PROGRAM, |
| .nrvers = ARRAY_SIZE(mnt_version), |
| .version = mnt_version, |
| .stats = &mnt_stats, |
| }; |