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