1 /* 2 * In-kernel MOUNT protocol client 3 * 4 * Copyright (C) 1997, Olaf Kirch <okir@monad.swb.de> 5 */ 6 7 #include <linux/types.h> 8 #include <linux/socket.h> 9 #include <linux/kernel.h> 10 #include <linux/errno.h> 11 #include <linux/uio.h> 12 #include <linux/net.h> 13 #include <linux/in.h> 14 #include <linux/sunrpc/clnt.h> 15 #include <linux/sunrpc/sched.h> 16 #include <linux/nfs_fs.h> 17 #include "internal.h" 18 19 #ifdef RPC_DEBUG 20 # define NFSDBG_FACILITY NFSDBG_MOUNT 21 #endif 22 23 static struct rpc_program mnt_program; 24 25 struct mnt_fhstatus { 26 u32 status; 27 struct nfs_fh *fh; 28 }; 29 30 /** 31 * nfs_mount - Obtain an NFS file handle for the given host and path 32 * @info: pointer to mount request arguments 33 * 34 * Uses default timeout parameters specified by underlying transport. 35 */ 36 int nfs_mount(struct nfs_mount_request *info) 37 { 38 struct mnt_fhstatus result = { 39 .fh = info->fh 40 }; 41 struct rpc_message msg = { 42 .rpc_argp = info->dirpath, 43 .rpc_resp = &result, 44 }; 45 struct rpc_create_args args = { 46 .protocol = info->protocol, 47 .address = info->sap, 48 .addrsize = info->salen, 49 .servername = info->hostname, 50 .program = &mnt_program, 51 .version = info->version, 52 .authflavor = RPC_AUTH_UNIX, 53 }; 54 struct rpc_clnt *mnt_clnt; 55 int status; 56 57 dprintk("NFS: sending MNT request for %s:%s\n", 58 (info->hostname ? info->hostname : "server"), 59 info->dirpath); 60 61 if (info->noresvport) 62 args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; 63 64 mnt_clnt = rpc_create(&args); 65 if (IS_ERR(mnt_clnt)) 66 goto out_clnt_err; 67 68 if (info->version == NFS_MNT3_VERSION) 69 msg.rpc_proc = &mnt_clnt->cl_procinfo[MOUNTPROC3_MNT]; 70 else 71 msg.rpc_proc = &mnt_clnt->cl_procinfo[MNTPROC_MNT]; 72 73 status = rpc_call_sync(mnt_clnt, &msg, 0); 74 rpc_shutdown_client(mnt_clnt); 75 76 if (status < 0) 77 goto out_call_err; 78 if (result.status != 0) 79 goto out_mnt_err; 80 81 dprintk("NFS: MNT request succeeded\n"); 82 status = 0; 83 84 out: 85 return status; 86 87 out_clnt_err: 88 status = PTR_ERR(mnt_clnt); 89 dprintk("NFS: failed to create RPC client, status=%d\n", status); 90 goto out; 91 92 out_call_err: 93 dprintk("NFS: failed to start MNT request, status=%d\n", status); 94 goto out; 95 96 out_mnt_err: 97 dprintk("NFS: MNT server returned result %d\n", result.status); 98 status = nfs_stat_to_errno(result.status); 99 goto out; 100 } 101 102 /* 103 * XDR encode/decode functions for MOUNT 104 */ 105 static int xdr_encode_dirpath(struct rpc_rqst *req, __be32 *p, 106 const char *path) 107 { 108 p = xdr_encode_string(p, path); 109 110 req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); 111 return 0; 112 } 113 114 static int xdr_decode_fhstatus(struct rpc_rqst *req, __be32 *p, 115 struct mnt_fhstatus *res) 116 { 117 struct nfs_fh *fh = res->fh; 118 119 if ((res->status = ntohl(*p++)) == 0) { 120 fh->size = NFS2_FHSIZE; 121 memcpy(fh->data, p, NFS2_FHSIZE); 122 } 123 return 0; 124 } 125 126 static int xdr_decode_fhstatus3(struct rpc_rqst *req, __be32 *p, 127 struct mnt_fhstatus *res) 128 { 129 struct nfs_fh *fh = res->fh; 130 unsigned size; 131 132 if ((res->status = ntohl(*p++)) == 0) { 133 size = ntohl(*p++); 134 if (size <= NFS3_FHSIZE && size != 0) { 135 fh->size = size; 136 memcpy(fh->data, p, size); 137 } else 138 res->status = -EBADHANDLE; 139 } 140 return 0; 141 } 142 143 #define MNT_dirpath_sz (1 + 256) 144 #define MNT_fhstatus_sz (1 + 8) 145 #define MNT_fhstatus3_sz (1 + 16) 146 147 static struct rpc_procinfo mnt_procedures[] = { 148 [MNTPROC_MNT] = { 149 .p_proc = MNTPROC_MNT, 150 .p_encode = (kxdrproc_t) xdr_encode_dirpath, 151 .p_decode = (kxdrproc_t) xdr_decode_fhstatus, 152 .p_arglen = MNT_dirpath_sz, 153 .p_replen = MNT_fhstatus_sz, 154 .p_statidx = MNTPROC_MNT, 155 .p_name = "MOUNT", 156 }, 157 }; 158 159 static struct rpc_procinfo mnt3_procedures[] = { 160 [MOUNTPROC3_MNT] = { 161 .p_proc = MOUNTPROC3_MNT, 162 .p_encode = (kxdrproc_t) xdr_encode_dirpath, 163 .p_decode = (kxdrproc_t) xdr_decode_fhstatus3, 164 .p_arglen = MNT_dirpath_sz, 165 .p_replen = MNT_fhstatus3_sz, 166 .p_statidx = MOUNTPROC3_MNT, 167 .p_name = "MOUNT", 168 }, 169 }; 170 171 172 static struct rpc_version mnt_version1 = { 173 .number = 1, 174 .nrprocs = 2, 175 .procs = mnt_procedures, 176 }; 177 178 static struct rpc_version mnt_version3 = { 179 .number = 3, 180 .nrprocs = 2, 181 .procs = mnt3_procedures, 182 }; 183 184 static struct rpc_version *mnt_version[] = { 185 NULL, 186 &mnt_version1, 187 NULL, 188 &mnt_version3, 189 }; 190 191 static struct rpc_stat mnt_stats; 192 193 static struct rpc_program mnt_program = { 194 .name = "mount", 195 .number = NFS_MNT_PROGRAM, 196 .nrvers = ARRAY_SIZE(mnt_version), 197 .version = mnt_version, 198 .stats = &mnt_stats, 199 }; 200