1e97ad33aSDoug Rabson /*-
2e97ad33aSDoug Rabson * Copyright (c) 2017 Juniper Networks, Inc.
3e97ad33aSDoug Rabson * All rights reserved.
4e97ad33aSDoug Rabson *
5e97ad33aSDoug Rabson * Redistribution and use in source and binary forms, with or without
6e97ad33aSDoug Rabson * modification, are permitted provided that the following conditions
7e97ad33aSDoug Rabson * are met:
8e97ad33aSDoug Rabson * 1. Redistributions of source code must retain the above copyright
9e97ad33aSDoug Rabson * notice, this list of conditions and the following disclaimer.
10e97ad33aSDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright
11e97ad33aSDoug Rabson * notice, this list of conditions and the following disclaimer in the
12e97ad33aSDoug Rabson * documentation and/or other materials provided with the distribution.
13e97ad33aSDoug Rabson *
14e97ad33aSDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15e97ad33aSDoug Rabson * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16e97ad33aSDoug Rabson * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17e97ad33aSDoug Rabson * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18e97ad33aSDoug Rabson * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19e97ad33aSDoug Rabson * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20e97ad33aSDoug Rabson * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21e97ad33aSDoug Rabson * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22e97ad33aSDoug Rabson * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23e97ad33aSDoug Rabson * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24e97ad33aSDoug Rabson *
25e97ad33aSDoug Rabson */
26e97ad33aSDoug Rabson
27e97ad33aSDoug Rabson /*
28e97ad33aSDoug Rabson * This file contains 9P client functions which prepares message to be sent to
29e97ad33aSDoug Rabson * the server. Every fileop typically has a function defined here to interact
30e97ad33aSDoug Rabson * with the host.
31e97ad33aSDoug Rabson */
32e97ad33aSDoug Rabson
33e97ad33aSDoug Rabson #include <vm/uma.h>
34e97ad33aSDoug Rabson #include <sys/systm.h>
35e97ad33aSDoug Rabson #include <sys/dirent.h>
36e97ad33aSDoug Rabson #include <sys/fcntl.h>
37e97ad33aSDoug Rabson #include <sys/param.h>
38e97ad33aSDoug Rabson #include <sys/malloc.h>
39e97ad33aSDoug Rabson #include <sys/mount.h>
40e97ad33aSDoug Rabson #include <sys/sysctl.h>
41e97ad33aSDoug Rabson
42e97ad33aSDoug Rabson #include <fs/p9fs/p9_client.h>
43e97ad33aSDoug Rabson #include <fs/p9fs/p9_debug.h>
44e97ad33aSDoug Rabson #include <fs/p9fs/p9_transport.h>
45e97ad33aSDoug Rabson
46e97ad33aSDoug Rabson #define QEMU_HEADER 7
47e97ad33aSDoug Rabson #define P9FS_MAX_FID_CNT (1024 * 1024 * 1024)
48e97ad33aSDoug Rabson #define P9FS_ROOT_FID_NO 2
49e97ad33aSDoug Rabson #define P9FS_MIN_TAG 1
50e97ad33aSDoug Rabson #define P9FS_MAX_TAG 65535
51e97ad33aSDoug Rabson #define WSTAT_SIZE 47
52e97ad33aSDoug Rabson #define WSTAT_EXTENSION_SIZE 14
53e97ad33aSDoug Rabson
54e97ad33aSDoug Rabson static MALLOC_DEFINE(M_P9CLNT, "p9_client", "p9fs client structure");
55e97ad33aSDoug Rabson static uma_zone_t p9fs_fid_zone;
56e97ad33aSDoug Rabson static uma_zone_t p9fs_req_zone;
57e97ad33aSDoug Rabson static uma_zone_t p9fs_buf_zone;
58e97ad33aSDoug Rabson
59e97ad33aSDoug Rabson SYSCTL_DECL(_vfs_p9fs);
60e97ad33aSDoug Rabson int p9_debug_level = 0;
61e97ad33aSDoug Rabson SYSCTL_INT(_vfs_p9fs, OID_AUTO, debug_level, CTLFLAG_RW,
62e97ad33aSDoug Rabson &p9_debug_level, 0, "p9fs debug logging");
63e97ad33aSDoug Rabson
64e97ad33aSDoug Rabson static struct p9_req_t *p9_get_request(struct p9_client *c, int *error);
65e97ad33aSDoug Rabson static struct p9_req_t *p9_client_request(
66e97ad33aSDoug Rabson struct p9_client *c, int8_t type, int *error, const char *fmt, ...);
67e97ad33aSDoug Rabson
68e97ad33aSDoug Rabson inline int
p9_is_proto_dotl(struct p9_client * clnt)69e97ad33aSDoug Rabson p9_is_proto_dotl(struct p9_client *clnt)
70e97ad33aSDoug Rabson {
71e97ad33aSDoug Rabson
72e97ad33aSDoug Rabson return (clnt->proto_version == p9_proto_2000L);
73e97ad33aSDoug Rabson }
74e97ad33aSDoug Rabson
75e97ad33aSDoug Rabson inline int
p9_is_proto_dotu(struct p9_client * clnt)76e97ad33aSDoug Rabson p9_is_proto_dotu(struct p9_client *clnt)
77e97ad33aSDoug Rabson {
78e97ad33aSDoug Rabson
79e97ad33aSDoug Rabson return (clnt->proto_version == p9_proto_2000u);
80e97ad33aSDoug Rabson }
81e97ad33aSDoug Rabson
82e97ad33aSDoug Rabson /* Parse mount options into client structure */
83e97ad33aSDoug Rabson static int
p9_parse_opts(struct mount * mp,struct p9_client * clnt)84e97ad33aSDoug Rabson p9_parse_opts(struct mount *mp, struct p9_client *clnt)
85e97ad33aSDoug Rabson {
86e97ad33aSDoug Rabson int error, len;
87e97ad33aSDoug Rabson char *trans;
88e97ad33aSDoug Rabson
89e97ad33aSDoug Rabson /*
90e97ad33aSDoug Rabson * Default to virtio since thats the only transport we have for now.
91e97ad33aSDoug Rabson */
92e97ad33aSDoug Rabson error = vfs_getopt(mp->mnt_optnew, "trans", (void **)&trans, &len);
93e97ad33aSDoug Rabson if (error == ENOENT)
94e97ad33aSDoug Rabson trans = "virtio";
95e97ad33aSDoug Rabson
96e97ad33aSDoug Rabson /* These are defaults for now */
97e97ad33aSDoug Rabson clnt->proto_version = p9_proto_2000L;
98e97ad33aSDoug Rabson clnt->msize = 8192;
99e97ad33aSDoug Rabson
100e97ad33aSDoug Rabson /* Get the default trans callback */
101e97ad33aSDoug Rabson clnt->ops = p9_get_trans_by_name(trans);
102e97ad33aSDoug Rabson
103e97ad33aSDoug Rabson return (0);
104e97ad33aSDoug Rabson }
105e97ad33aSDoug Rabson
106e97ad33aSDoug Rabson /* Allocate buffer for sending request and getting responses */
107e97ad33aSDoug Rabson static struct p9_buffer *
p9_buffer_alloc(int alloc_msize)108e97ad33aSDoug Rabson p9_buffer_alloc(int alloc_msize)
109e97ad33aSDoug Rabson {
110e97ad33aSDoug Rabson struct p9_buffer *fc;
111e97ad33aSDoug Rabson
112e97ad33aSDoug Rabson fc = uma_zalloc(p9fs_buf_zone, M_WAITOK | M_ZERO);
113e97ad33aSDoug Rabson fc->capacity = alloc_msize;
114e97ad33aSDoug Rabson fc->offset = 0;
115e97ad33aSDoug Rabson fc->size = 0;
116e97ad33aSDoug Rabson fc->sdata = (char *)fc + sizeof(struct p9_buffer);
117e97ad33aSDoug Rabson
118e97ad33aSDoug Rabson return (fc);
119e97ad33aSDoug Rabson }
120e97ad33aSDoug Rabson
121e97ad33aSDoug Rabson /* Free memory used by request and response buffers */
122e97ad33aSDoug Rabson static void
p9_buffer_free(struct p9_buffer ** buf)123e97ad33aSDoug Rabson p9_buffer_free(struct p9_buffer **buf)
124e97ad33aSDoug Rabson {
125e97ad33aSDoug Rabson
126e97ad33aSDoug Rabson /* Free the sdata buffers first, then the whole structure*/
127e97ad33aSDoug Rabson uma_zfree(p9fs_buf_zone, *buf);
128e97ad33aSDoug Rabson *buf = NULL;
129e97ad33aSDoug Rabson }
130e97ad33aSDoug Rabson
131e97ad33aSDoug Rabson /* Free the request */
132e97ad33aSDoug Rabson static void
p9_free_req(struct p9_client * clnt,struct p9_req_t * req)133e97ad33aSDoug Rabson p9_free_req(struct p9_client *clnt, struct p9_req_t *req)
134e97ad33aSDoug Rabson {
135e97ad33aSDoug Rabson
136e97ad33aSDoug Rabson if (req->tc != NULL) {
137e97ad33aSDoug Rabson if (req->tc->tag != P9_NOTAG)
138e97ad33aSDoug Rabson p9_tag_destroy(clnt, req->tc->tag);
139e97ad33aSDoug Rabson p9_buffer_free(&req->tc);
140e97ad33aSDoug Rabson }
141e97ad33aSDoug Rabson
142e97ad33aSDoug Rabson if (req->rc != NULL)
143e97ad33aSDoug Rabson p9_buffer_free(&req->rc);
144e97ad33aSDoug Rabson
145e97ad33aSDoug Rabson uma_zfree(p9fs_req_zone, req);
146e97ad33aSDoug Rabson }
147e97ad33aSDoug Rabson
148e97ad33aSDoug Rabson /* Allocate a request by tag */
149e97ad33aSDoug Rabson static struct p9_req_t *
p9_get_request(struct p9_client * clnt,int * error)150e97ad33aSDoug Rabson p9_get_request(struct p9_client *clnt, int *error)
151e97ad33aSDoug Rabson {
152e97ad33aSDoug Rabson struct p9_req_t *req;
153e97ad33aSDoug Rabson int alloc_msize;
154e97ad33aSDoug Rabson uint16_t tag;
155e97ad33aSDoug Rabson
156e97ad33aSDoug Rabson alloc_msize = P9FS_MTU;
157e97ad33aSDoug Rabson
158e97ad33aSDoug Rabson req = uma_zalloc(p9fs_req_zone, M_WAITOK | M_ZERO);
159e97ad33aSDoug Rabson req->tc = p9_buffer_alloc(alloc_msize);
160e97ad33aSDoug Rabson req->rc = p9_buffer_alloc(alloc_msize);
161e97ad33aSDoug Rabson
162e97ad33aSDoug Rabson tag = p9_tag_create(clnt);
163e97ad33aSDoug Rabson if (tag == P9_NOTAG) {
164e97ad33aSDoug Rabson *error = EAGAIN;
165e97ad33aSDoug Rabson req->tc->tag = P9_NOTAG;
166e97ad33aSDoug Rabson p9_free_req(clnt, req);
167e97ad33aSDoug Rabson return (NULL);
168e97ad33aSDoug Rabson }
169e97ad33aSDoug Rabson req->tc->tag = tag;
170e97ad33aSDoug Rabson return (req);
171e97ad33aSDoug Rabson }
172e97ad33aSDoug Rabson
173e97ad33aSDoug Rabson /* Parse header arguments of the response buffer */
174e97ad33aSDoug Rabson static int
p9_parse_receive(struct p9_buffer * buf,struct p9_client * clnt)175e97ad33aSDoug Rabson p9_parse_receive(struct p9_buffer *buf, struct p9_client *clnt)
176e97ad33aSDoug Rabson {
177e97ad33aSDoug Rabson int8_t type;
178e97ad33aSDoug Rabson int16_t tag;
179e97ad33aSDoug Rabson int32_t size;
180e97ad33aSDoug Rabson int error;
181e97ad33aSDoug Rabson
182e97ad33aSDoug Rabson buf->offset = 0;
183e97ad33aSDoug Rabson
184e97ad33aSDoug Rabson /* This value is set by QEMU for the header.*/
185e97ad33aSDoug Rabson if (buf->size == 0)
186e97ad33aSDoug Rabson buf->size = QEMU_HEADER;
187e97ad33aSDoug Rabson
188e97ad33aSDoug Rabson /* This is the initial header. Parse size, type, and tag .*/
189e97ad33aSDoug Rabson error = p9_buf_readf(buf, 0, "dbw", &size, &type, &tag);
190e97ad33aSDoug Rabson if (error != 0)
191e97ad33aSDoug Rabson goto out;
192e97ad33aSDoug Rabson
193e97ad33aSDoug Rabson buf->size = size;
194e97ad33aSDoug Rabson buf->id = type;
195e97ad33aSDoug Rabson buf->tag = tag;
196e97ad33aSDoug Rabson P9_DEBUG(TRANS, "%s: size=%d type: %d tag: %d\n",
197e97ad33aSDoug Rabson __func__, buf->size, buf->id, buf->tag);
198e97ad33aSDoug Rabson out:
199e97ad33aSDoug Rabson return (error);
200e97ad33aSDoug Rabson }
201e97ad33aSDoug Rabson
202e97ad33aSDoug Rabson /* Check 9P response for any errors returned and process it */
203e97ad33aSDoug Rabson static int
p9_client_check_return(struct p9_client * c,struct p9_req_t * req)204e97ad33aSDoug Rabson p9_client_check_return(struct p9_client *c, struct p9_req_t *req)
205e97ad33aSDoug Rabson {
206e97ad33aSDoug Rabson int error;
207e97ad33aSDoug Rabson int ecode;
208e97ad33aSDoug Rabson char *ename;
209e97ad33aSDoug Rabson
210e97ad33aSDoug Rabson /* Check what we have in the receive bufer .*/
211e97ad33aSDoug Rabson error = p9_parse_receive(req->rc, c);
212e97ad33aSDoug Rabson if (error != 0)
213e97ad33aSDoug Rabson goto out;
214e97ad33aSDoug Rabson
215e97ad33aSDoug Rabson /*
216e97ad33aSDoug Rabson * No error, We are done with the preprocessing. Return to the caller
217e97ad33aSDoug Rabson * and process the actual data.
218e97ad33aSDoug Rabson */
219e97ad33aSDoug Rabson if (req->rc->id != P9PROTO_RERROR && req->rc->id != P9PROTO_RLERROR)
220e97ad33aSDoug Rabson return (0);
221e97ad33aSDoug Rabson
222e97ad33aSDoug Rabson /*
223e97ad33aSDoug Rabson * Interpreting the error is done in different ways for Linux and
224e97ad33aSDoug Rabson * Unix version. Make sure you interpret it right.
225e97ad33aSDoug Rabson */
226e97ad33aSDoug Rabson if (req->rc->id == P9PROTO_RERROR) {
227e97ad33aSDoug Rabson error = p9_buf_readf(req->rc, c->proto_version, "s?d", &ename, &ecode);
228e97ad33aSDoug Rabson } else if (req->rc->id == P9PROTO_RLERROR) {
229e97ad33aSDoug Rabson error = p9_buf_readf(req->rc, c->proto_version, "d", &ecode);
230e97ad33aSDoug Rabson } else {
231e97ad33aSDoug Rabson goto out;
232e97ad33aSDoug Rabson }
233e97ad33aSDoug Rabson if (error != 0)
234e97ad33aSDoug Rabson goto out;
235e97ad33aSDoug Rabson
236e97ad33aSDoug Rabson /* if there was an ecode error make this the err now */
237e97ad33aSDoug Rabson error = ecode;
238e97ad33aSDoug Rabson
239e97ad33aSDoug Rabson /*
240e97ad33aSDoug Rabson * Note this is still not completely an error, as lookups for files
241e97ad33aSDoug Rabson * not present can hit this and return. Hence it is made a debug print.
242e97ad33aSDoug Rabson */
243e97ad33aSDoug Rabson if (error != 0) {
244e97ad33aSDoug Rabson if (req->rc->id == P9PROTO_RERROR) {
245e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RERROR error %d ename %s\n",
246e97ad33aSDoug Rabson error, ename);
247e97ad33aSDoug Rabson } else if (req->rc->id == P9PROTO_RLERROR) {
248e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RLERROR error %d\n", error);
249e97ad33aSDoug Rabson }
250e97ad33aSDoug Rabson }
251e97ad33aSDoug Rabson
252e97ad33aSDoug Rabson if (req->rc->id == P9PROTO_RERROR) {
253e97ad33aSDoug Rabson free(ename, M_TEMP);
254e97ad33aSDoug Rabson }
255e97ad33aSDoug Rabson return (error);
256e97ad33aSDoug Rabson
257e97ad33aSDoug Rabson out:
258e97ad33aSDoug Rabson P9_DEBUG(ERROR, "couldn't parse receive buffer error%d\n", error);
259e97ad33aSDoug Rabson return (error);
260e97ad33aSDoug Rabson }
261e97ad33aSDoug Rabson
262e97ad33aSDoug Rabson /* State machine changing helpers */
p9_client_disconnect(struct p9_client * clnt)263e97ad33aSDoug Rabson void p9_client_disconnect(struct p9_client *clnt)
264e97ad33aSDoug Rabson {
265e97ad33aSDoug Rabson
266e97ad33aSDoug Rabson P9_DEBUG(TRANS, "%s: clnt %p\n", __func__, clnt);
267e97ad33aSDoug Rabson clnt->trans_status = P9FS_DISCONNECT;
268e97ad33aSDoug Rabson }
269e97ad33aSDoug Rabson
p9_client_begin_disconnect(struct p9_client * clnt)270e97ad33aSDoug Rabson void p9_client_begin_disconnect(struct p9_client *clnt)
271e97ad33aSDoug Rabson {
272e97ad33aSDoug Rabson
273e97ad33aSDoug Rabson P9_DEBUG(TRANS, "%s: clnt %p\n", __func__, clnt);
274e97ad33aSDoug Rabson clnt->trans_status = P9FS_BEGIN_DISCONNECT;
275e97ad33aSDoug Rabson }
276e97ad33aSDoug Rabson
277e97ad33aSDoug Rabson static struct p9_req_t *
p9_client_prepare_req(struct p9_client * c,int8_t type,int req_size,int * error,const char * fmt,__va_list ap)278e97ad33aSDoug Rabson p9_client_prepare_req(struct p9_client *c, int8_t type,
279e97ad33aSDoug Rabson int req_size, int *error, const char *fmt, __va_list ap)
280e97ad33aSDoug Rabson {
281e97ad33aSDoug Rabson struct p9_req_t *req;
282e97ad33aSDoug Rabson
283e97ad33aSDoug Rabson P9_DEBUG(TRANS, "%s: client %p op %d\n", __func__, c, type);
284e97ad33aSDoug Rabson
285e97ad33aSDoug Rabson /*
286e97ad33aSDoug Rabson * Before we start with the request, check if its possible to finish
287e97ad33aSDoug Rabson * this request. We are allowed to submit the request only if there
288e97ad33aSDoug Rabson * are no close sessions happening or else there can be race. If the
289e97ad33aSDoug Rabson * status is Disconnected, we stop any requests coming in after that.
290e97ad33aSDoug Rabson */
291e97ad33aSDoug Rabson if (c->trans_status == P9FS_DISCONNECT) {
292e97ad33aSDoug Rabson *error = EIO;
293e97ad33aSDoug Rabson return (NULL);
294e97ad33aSDoug Rabson }
295e97ad33aSDoug Rabson
296e97ad33aSDoug Rabson /* Allow only cleanup clunk messages once teardown has started. */
297e97ad33aSDoug Rabson if ((c->trans_status == P9FS_BEGIN_DISCONNECT) &&
298e97ad33aSDoug Rabson (type != P9PROTO_TCLUNK)) {
299e97ad33aSDoug Rabson *error = EIO;
300e97ad33aSDoug Rabson return (NULL);
301e97ad33aSDoug Rabson }
302e97ad33aSDoug Rabson
303e97ad33aSDoug Rabson /* Allocate buffer for transferring and receiving data from host */
304e97ad33aSDoug Rabson req = p9_get_request(c, error);
305e97ad33aSDoug Rabson if (*error != 0) {
306e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: request allocation failed.\n", __func__);
307e97ad33aSDoug Rabson return (NULL);
308e97ad33aSDoug Rabson }
309e97ad33aSDoug Rabson
310e97ad33aSDoug Rabson /* Marshall the data according to QEMU standards */
311e97ad33aSDoug Rabson *error = p9_buf_prepare(req->tc, type);
312e97ad33aSDoug Rabson if (*error != 0) {
313e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: p9_buf_prepare failed: %d\n",
314e97ad33aSDoug Rabson __func__, *error);
315e97ad33aSDoug Rabson goto out;
316e97ad33aSDoug Rabson }
317e97ad33aSDoug Rabson
318e97ad33aSDoug Rabson *error = p9_buf_vwritef(req->tc, c->proto_version, fmt, ap);
319e97ad33aSDoug Rabson if (*error != 0) {
320e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: p9_buf_vwrite failed: %d\n",
321e97ad33aSDoug Rabson __func__, *error);
322e97ad33aSDoug Rabson goto out;
323e97ad33aSDoug Rabson }
324e97ad33aSDoug Rabson
325e97ad33aSDoug Rabson *error = p9_buf_finalize(c, req->tc);
326e97ad33aSDoug Rabson if (*error != 0) {
327e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: p9_buf_finalize failed: %d \n",
328e97ad33aSDoug Rabson __func__, *error);
329e97ad33aSDoug Rabson goto out;
330e97ad33aSDoug Rabson }
331e97ad33aSDoug Rabson
332e97ad33aSDoug Rabson return (req);
333e97ad33aSDoug Rabson out:
334e97ad33aSDoug Rabson p9_free_req(c, req);
335e97ad33aSDoug Rabson return (NULL);
336e97ad33aSDoug Rabson }
337e97ad33aSDoug Rabson
338e97ad33aSDoug Rabson /*
339e97ad33aSDoug Rabson * Issue a request and wait for response. The routine takes care of preparing
340e97ad33aSDoug Rabson * the 9P request header to be sent, parsing and checking for error conditions
341e97ad33aSDoug Rabson * in the received buffer. It returns the request structure.
342e97ad33aSDoug Rabson */
343e97ad33aSDoug Rabson static struct p9_req_t *
p9_client_request(struct p9_client * c,int8_t type,int * error,const char * fmt,...)344e97ad33aSDoug Rabson p9_client_request(struct p9_client *c, int8_t type, int *error,
345e97ad33aSDoug Rabson const char *fmt, ...)
346e97ad33aSDoug Rabson {
347e97ad33aSDoug Rabson va_list ap;
348e97ad33aSDoug Rabson struct p9_req_t *req;
349e97ad33aSDoug Rabson
350e97ad33aSDoug Rabson va_start(ap, fmt);
351e97ad33aSDoug Rabson req = p9_client_prepare_req(c, type, c->msize, error, fmt, ap);
352e97ad33aSDoug Rabson va_end(ap);
353e97ad33aSDoug Rabson
354e97ad33aSDoug Rabson /* Issue with allocation of request buffer */
355e97ad33aSDoug Rabson if (*error != 0)
356e97ad33aSDoug Rabson return (NULL);
357e97ad33aSDoug Rabson
358e97ad33aSDoug Rabson /* Call into the transport for submission. */
359e97ad33aSDoug Rabson *error = c->ops->request(c->handle, req);
360e97ad33aSDoug Rabson if (*error != 0) {
361e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: failed: %d\n", __func__, *error);
362e97ad33aSDoug Rabson goto out;
363e97ad33aSDoug Rabson }
364e97ad33aSDoug Rabson
365e97ad33aSDoug Rabson /*
366e97ad33aSDoug Rabson * Before we return, pre process the header and the rc buffer before
367e97ad33aSDoug Rabson * calling into the protocol infra to analyze the data in rc.
368e97ad33aSDoug Rabson */
369e97ad33aSDoug Rabson *error = p9_client_check_return(c, req);
370e97ad33aSDoug Rabson if (*error != 0)
371e97ad33aSDoug Rabson goto out;
372e97ad33aSDoug Rabson
373e97ad33aSDoug Rabson return (req);
374e97ad33aSDoug Rabson out:
375e97ad33aSDoug Rabson p9_free_req(c, req);
376e97ad33aSDoug Rabson return (NULL);
377e97ad33aSDoug Rabson }
378e97ad33aSDoug Rabson
379e97ad33aSDoug Rabson /* Setup tag contents and structure */
380e97ad33aSDoug Rabson uint16_t
p9_tag_create(struct p9_client * clnt)381e97ad33aSDoug Rabson p9_tag_create(struct p9_client *clnt)
382e97ad33aSDoug Rabson {
383e97ad33aSDoug Rabson int tag;
384e97ad33aSDoug Rabson
385e97ad33aSDoug Rabson tag = alloc_unr(&clnt->tagpool);
386e97ad33aSDoug Rabson P9_DEBUG(LPROTO, "%s: clnt %p: tag %d\n", __func__, clnt, tag);
387e97ad33aSDoug Rabson
388e97ad33aSDoug Rabson /* Alloc_unr returning -1 is an error for no units left */
389e97ad33aSDoug Rabson if (tag == -1) {
390e97ad33aSDoug Rabson return (P9_NOTAG);
391e97ad33aSDoug Rabson }
392e97ad33aSDoug Rabson return (tag);
393e97ad33aSDoug Rabson }
394e97ad33aSDoug Rabson
395e97ad33aSDoug Rabson /* Clean up tag structures */
396e97ad33aSDoug Rabson void
p9_tag_destroy(struct p9_client * clnt,uint16_t tag)397e97ad33aSDoug Rabson p9_tag_destroy(struct p9_client *clnt, uint16_t tag)
398e97ad33aSDoug Rabson {
399e97ad33aSDoug Rabson
400e97ad33aSDoug Rabson P9_DEBUG(LPROTO, "%s: clnt %p: tag %d\n", __func__, clnt, tag);
401e97ad33aSDoug Rabson
402e97ad33aSDoug Rabson /* Release to the pool */
403e97ad33aSDoug Rabson free_unr(&clnt->tagpool, tag);
404e97ad33aSDoug Rabson }
405e97ad33aSDoug Rabson
406e97ad33aSDoug Rabson /* Allocate a new fid from the fidpool */
407e97ad33aSDoug Rabson struct p9_fid *
p9_fid_create(struct p9_client * clnt)408e97ad33aSDoug Rabson p9_fid_create(struct p9_client *clnt)
409e97ad33aSDoug Rabson {
410e97ad33aSDoug Rabson struct p9_fid *fid;
411e97ad33aSDoug Rabson
412e97ad33aSDoug Rabson
413e97ad33aSDoug Rabson fid = uma_zalloc(p9fs_fid_zone, M_WAITOK | M_ZERO);
414e97ad33aSDoug Rabson fid->fid = alloc_unr(&clnt->fidpool);
415e97ad33aSDoug Rabson P9_DEBUG(LPROTO, "%s: fid %d\n", __func__, fid->fid);
416e97ad33aSDoug Rabson
417e97ad33aSDoug Rabson /* Alloc_unr returning -1 is an error for no units left */
418e97ad33aSDoug Rabson if (fid->fid == -1) {
419e97ad33aSDoug Rabson uma_zfree(p9fs_fid_zone, fid);
420e97ad33aSDoug Rabson return (NULL);
421e97ad33aSDoug Rabson }
422e97ad33aSDoug Rabson fid->mode = -1;
423e97ad33aSDoug Rabson fid->uid = -1;
424e97ad33aSDoug Rabson fid->clnt = clnt;
425e97ad33aSDoug Rabson
426e97ad33aSDoug Rabson return (fid);
427e97ad33aSDoug Rabson }
428e97ad33aSDoug Rabson
429e97ad33aSDoug Rabson /* Free the fid by releasing it to fidpool */
430e97ad33aSDoug Rabson void
p9_fid_destroy(struct p9_fid * fid)431e97ad33aSDoug Rabson p9_fid_destroy(struct p9_fid *fid)
432e97ad33aSDoug Rabson {
433e97ad33aSDoug Rabson struct p9_client *clnt;
434e97ad33aSDoug Rabson
435e97ad33aSDoug Rabson P9_DEBUG(LPROTO, "%s: fid %d\n", __func__, fid->fid);
436e97ad33aSDoug Rabson clnt = fid->clnt;
437e97ad33aSDoug Rabson /* Release to the pool */
438e97ad33aSDoug Rabson free_unr(&clnt->fidpool, fid->fid);
439e97ad33aSDoug Rabson uma_zfree(p9fs_fid_zone, fid);
440e97ad33aSDoug Rabson }
441e97ad33aSDoug Rabson
442e97ad33aSDoug Rabson /* Request the version of 9P protocol */
443e97ad33aSDoug Rabson int
p9_client_version(struct p9_client * c)444e97ad33aSDoug Rabson p9_client_version(struct p9_client *c)
445e97ad33aSDoug Rabson {
446e97ad33aSDoug Rabson int error;
447e97ad33aSDoug Rabson struct p9_req_t *req;
448e97ad33aSDoug Rabson char *version;
449e97ad33aSDoug Rabson int msize;
450e97ad33aSDoug Rabson
451e97ad33aSDoug Rabson error = 0;
452e97ad33aSDoug Rabson
453e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TVERSION msize %d protocol %d\n",
454e97ad33aSDoug Rabson c->msize, c->proto_version);
455e97ad33aSDoug Rabson
456e97ad33aSDoug Rabson switch (c->proto_version) {
457e97ad33aSDoug Rabson case p9_proto_2000L:
458e97ad33aSDoug Rabson req = p9_client_request(c, P9PROTO_TVERSION, &error, "ds",
459e97ad33aSDoug Rabson c->msize, "9P2000.L");
460e97ad33aSDoug Rabson break;
461e97ad33aSDoug Rabson case p9_proto_2000u:
462e97ad33aSDoug Rabson req = p9_client_request(c, P9PROTO_TVERSION, &error, "ds",
463e97ad33aSDoug Rabson c->msize, "9P2000.u");
464e97ad33aSDoug Rabson break;
465e97ad33aSDoug Rabson case p9_proto_legacy:
466e97ad33aSDoug Rabson req = p9_client_request(c, P9PROTO_TVERSION, &error, "ds",
467e97ad33aSDoug Rabson c->msize, "9P2000");
468e97ad33aSDoug Rabson break;
469e97ad33aSDoug Rabson default:
470e97ad33aSDoug Rabson return (EINVAL);
471e97ad33aSDoug Rabson }
472e97ad33aSDoug Rabson
473e97ad33aSDoug Rabson /* Always return the relevant error code */
474e97ad33aSDoug Rabson if (error != 0)
475e97ad33aSDoug Rabson return (error);
476e97ad33aSDoug Rabson
477e97ad33aSDoug Rabson error = p9_buf_readf(req->rc, c->proto_version, "ds", &msize, &version);
478e97ad33aSDoug Rabson if (error != 0) {
479e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: version error: %d\n", __func__, error);
480e97ad33aSDoug Rabson goto out;
481e97ad33aSDoug Rabson }
482e97ad33aSDoug Rabson
483e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RVERSION msize %d %s\n", msize, version);
484e97ad33aSDoug Rabson
485e97ad33aSDoug Rabson if (!strncmp(version, "9P2000.L", 8))
486e97ad33aSDoug Rabson c->proto_version = p9_proto_2000L;
487e97ad33aSDoug Rabson else if (!strncmp(version, "9P2000.u", 8))
488e97ad33aSDoug Rabson c->proto_version = p9_proto_2000u;
489e97ad33aSDoug Rabson else if (!strncmp(version, "9P2000", 6))
490e97ad33aSDoug Rabson c->proto_version = p9_proto_legacy;
491e97ad33aSDoug Rabson else {
492e97ad33aSDoug Rabson error = ENOMEM;
493e97ad33aSDoug Rabson goto out;
494e97ad33aSDoug Rabson }
495e97ad33aSDoug Rabson
496e97ad33aSDoug Rabson /* limit the msize .*/
497e97ad33aSDoug Rabson if (msize < c->msize)
498e97ad33aSDoug Rabson c->msize = msize;
499e97ad33aSDoug Rabson out:
500e97ad33aSDoug Rabson p9_free_req(c, req);
501e97ad33aSDoug Rabson return (error);
502e97ad33aSDoug Rabson }
503e97ad33aSDoug Rabson
504e97ad33aSDoug Rabson /*
505e97ad33aSDoug Rabson * Initialize zones for different things. This is called from Init module
506e97ad33aSDoug Rabson * so that we just have them initalized once.
507e97ad33aSDoug Rabson */
508e97ad33aSDoug Rabson void
p9_init_zones(void)509e97ad33aSDoug Rabson p9_init_zones(void)
510e97ad33aSDoug Rabson {
511e97ad33aSDoug Rabson
512e97ad33aSDoug Rabson /* Create the request and the fid zones */
513e97ad33aSDoug Rabson p9fs_fid_zone = uma_zcreate("p9fs fid zone",
514e97ad33aSDoug Rabson sizeof(struct p9_fid), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
515e97ad33aSDoug Rabson
516e97ad33aSDoug Rabson /* Create the request and the fid zones */
517e97ad33aSDoug Rabson p9fs_req_zone = uma_zcreate("p9fs req zone",
518e97ad33aSDoug Rabson sizeof(struct p9_req_t), NULL, NULL, NULL, NULL, UMA_ALIGN_PTR, 0);
519e97ad33aSDoug Rabson
520e97ad33aSDoug Rabson /* Create the buffer zone */
521e97ad33aSDoug Rabson p9fs_buf_zone = uma_zcreate("p9fs buf zone",
522e97ad33aSDoug Rabson sizeof(struct p9_buffer) + P9FS_MTU, NULL, NULL,
523e97ad33aSDoug Rabson NULL, NULL, UMA_ALIGN_PTR, 0);
524e97ad33aSDoug Rabson }
525e97ad33aSDoug Rabson
526e97ad33aSDoug Rabson void
p9_destroy_zones(void)527e97ad33aSDoug Rabson p9_destroy_zones(void)
528e97ad33aSDoug Rabson {
529e97ad33aSDoug Rabson
530e97ad33aSDoug Rabson uma_zdestroy(p9fs_fid_zone);
531e97ad33aSDoug Rabson uma_zdestroy(p9fs_req_zone);
532e97ad33aSDoug Rabson uma_zdestroy(p9fs_buf_zone);
533e97ad33aSDoug Rabson }
534e97ad33aSDoug Rabson
535e97ad33aSDoug Rabson /* Return the client to the session in the FS to hold it */
536e97ad33aSDoug Rabson struct p9_client *
p9_client_create(struct mount * mp,int * error,const char * mount_tag)537e97ad33aSDoug Rabson p9_client_create(struct mount *mp, int *error, const char *mount_tag)
538e97ad33aSDoug Rabson {
539e97ad33aSDoug Rabson struct p9_client *clnt;
540e97ad33aSDoug Rabson
541e97ad33aSDoug Rabson clnt = malloc(sizeof(struct p9_client), M_P9CLNT, M_WAITOK | M_ZERO);
542e97ad33aSDoug Rabson mtx_init(&clnt->clnt_mtx, "p9clnt", NULL, MTX_DEF);
543e97ad33aSDoug Rabson
544e97ad33aSDoug Rabson /* Parse should have set trans_mod */
545e97ad33aSDoug Rabson *error = p9_parse_opts(mp, clnt);
546e97ad33aSDoug Rabson if (*error != 0)
547e97ad33aSDoug Rabson goto out;
548e97ad33aSDoug Rabson
549e97ad33aSDoug Rabson if (clnt->ops == NULL) {
550e97ad33aSDoug Rabson *error = EINVAL;
551e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: no transport\n", __func__);
552e97ad33aSDoug Rabson goto out;
553e97ad33aSDoug Rabson }
554e97ad33aSDoug Rabson
555e97ad33aSDoug Rabson /* All the structures from here are protected by the lock clnt_mtx */
556e97ad33aSDoug Rabson init_unrhdr(&clnt->fidpool, P9FS_ROOT_FID_NO, P9FS_MAX_FID_CNT,
557e97ad33aSDoug Rabson &clnt->clnt_mtx);
558e97ad33aSDoug Rabson init_unrhdr(&clnt->tagpool, P9FS_MIN_TAG, P9FS_MAX_TAG,
559e97ad33aSDoug Rabson &clnt->clnt_mtx);
560e97ad33aSDoug Rabson
561e97ad33aSDoug Rabson P9_DEBUG(TRANS, "%s: clnt %p trans %p msize %d protocol %d\n",
562e97ad33aSDoug Rabson __func__, clnt, clnt->ops, clnt->msize, clnt->proto_version);
563e97ad33aSDoug Rabson
564e97ad33aSDoug Rabson *error = clnt->ops->create(mount_tag, &clnt->handle);
565e97ad33aSDoug Rabson if (*error != 0) {
566e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: transport create failed .%d \n",
567e97ad33aSDoug Rabson __func__, *error);
568e97ad33aSDoug Rabson goto out;
569e97ad33aSDoug Rabson }
570e97ad33aSDoug Rabson clnt->trans_status = P9FS_CONNECT;
571e97ad33aSDoug Rabson
572e97ad33aSDoug Rabson *error = p9_client_version(clnt);
573e97ad33aSDoug Rabson if (*error != 0)
574e97ad33aSDoug Rabson goto out;
575e97ad33aSDoug Rabson
576e97ad33aSDoug Rabson P9_DEBUG(TRANS, "%s: client creation succeeded.\n", __func__);
577e97ad33aSDoug Rabson return (clnt);
578e97ad33aSDoug Rabson out:
579e97ad33aSDoug Rabson free(clnt, M_P9CLNT);
580e97ad33aSDoug Rabson return (NULL);
581e97ad33aSDoug Rabson }
582e97ad33aSDoug Rabson
583e97ad33aSDoug Rabson /* Destroy the client by destroying associated fidpool and tagpool */
584e97ad33aSDoug Rabson void
p9_client_destroy(struct p9_client * clnt)585e97ad33aSDoug Rabson p9_client_destroy(struct p9_client *clnt)
586e97ad33aSDoug Rabson {
587e97ad33aSDoug Rabson
588e97ad33aSDoug Rabson P9_DEBUG(TRANS, "%s: client %p\n", __func__, clnt);
589e97ad33aSDoug Rabson clnt->ops->close(clnt->handle);
590e97ad33aSDoug Rabson
591e97ad33aSDoug Rabson P9_DEBUG(TRANS, "%s : Destroying fidpool\n", __func__);
592e97ad33aSDoug Rabson clear_unrhdr(&clnt->fidpool);
593e97ad33aSDoug Rabson
594e97ad33aSDoug Rabson P9_DEBUG(TRANS, "%s : Destroying tagpool\n", __func__);
595e97ad33aSDoug Rabson clear_unrhdr(&clnt->tagpool);
596e97ad33aSDoug Rabson
597e97ad33aSDoug Rabson free(clnt, M_P9CLNT);
598e97ad33aSDoug Rabson }
599e97ad33aSDoug Rabson
600e97ad33aSDoug Rabson /*
601e97ad33aSDoug Rabson * Attach a user to the filesystem. Create a fid for that user to access
602e97ad33aSDoug Rabson * the root of the filesystem.
603e97ad33aSDoug Rabson */
604e97ad33aSDoug Rabson struct p9_fid *
p9_client_attach(struct p9_client * clnt,struct p9_fid * afid,const char * uname,uid_t n_uname,const char * aname,int * error)605e97ad33aSDoug Rabson p9_client_attach(struct p9_client *clnt, struct p9_fid *afid,
606e97ad33aSDoug Rabson const char *uname, uid_t n_uname, const char *aname, int *error)
607e97ad33aSDoug Rabson {
608e97ad33aSDoug Rabson struct p9_req_t *req;
609e97ad33aSDoug Rabson struct p9_fid *fid;
610e97ad33aSDoug Rabson struct p9_qid qid;
611e97ad33aSDoug Rabson
612e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TATTACH uname=%s aname=%s, n_uname=%d\n",
613e97ad33aSDoug Rabson uname, aname, n_uname);
614e97ad33aSDoug Rabson fid = p9_fid_create(clnt);
615e97ad33aSDoug Rabson if (fid == NULL) {
616e97ad33aSDoug Rabson *error = ENOMEM;
617e97ad33aSDoug Rabson return (NULL);
618e97ad33aSDoug Rabson }
619e97ad33aSDoug Rabson fid->uid = n_uname;
620e97ad33aSDoug Rabson
621e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TATTACH, error, "ddssd", fid->fid,
622e97ad33aSDoug Rabson P9PROTO_NOFID, uname, aname, n_uname);
623e97ad33aSDoug Rabson if (*error != 0)
624e97ad33aSDoug Rabson goto out;
625e97ad33aSDoug Rabson
626e97ad33aSDoug Rabson *error = p9_buf_readf(req->rc, clnt->proto_version, "Q", &qid);
627e97ad33aSDoug Rabson if (*error != 0) {
628e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: p9_buf_readf failed: %d \n",
629e97ad33aSDoug Rabson __func__, *error);
630e97ad33aSDoug Rabson goto out;
631e97ad33aSDoug Rabson }
632e97ad33aSDoug Rabson
633e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RATTACH qid %x.%llx.%x\n",
634e97ad33aSDoug Rabson qid.type, (unsigned long long)qid.path, qid.version);
635e97ad33aSDoug Rabson
636e97ad33aSDoug Rabson memmove(&fid->qid, &qid, sizeof(struct p9_qid));
637e97ad33aSDoug Rabson p9_free_req(clnt, req);
638e97ad33aSDoug Rabson
639e97ad33aSDoug Rabson return (fid);
640e97ad33aSDoug Rabson out:
641e97ad33aSDoug Rabson if (req != NULL)
642e97ad33aSDoug Rabson p9_free_req(clnt, req);
643e97ad33aSDoug Rabson if (fid != NULL)
644e97ad33aSDoug Rabson p9_fid_destroy(fid);
645e97ad33aSDoug Rabson
646e97ad33aSDoug Rabson return (NULL);
647e97ad33aSDoug Rabson }
648e97ad33aSDoug Rabson
649e97ad33aSDoug Rabson /* Delete a file/directory. Corresponding fid will be cluncked too */
650e97ad33aSDoug Rabson int
p9_client_remove(struct p9_fid * fid)651e97ad33aSDoug Rabson p9_client_remove(struct p9_fid *fid)
652e97ad33aSDoug Rabson {
653e97ad33aSDoug Rabson int error;
654e97ad33aSDoug Rabson struct p9_client *clnt;
655e97ad33aSDoug Rabson struct p9_req_t *req;
656e97ad33aSDoug Rabson
657e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TREMOVE fid %d\n", fid->fid);
658e97ad33aSDoug Rabson
659e97ad33aSDoug Rabson error = 0;
660e97ad33aSDoug Rabson clnt = fid->clnt;
661e97ad33aSDoug Rabson
662e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TREMOVE, &error, "d", fid->fid);
663e97ad33aSDoug Rabson if (error != 0) {
664e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RREMOVE fid %d\n", fid->fid);
665e97ad33aSDoug Rabson return (error);
666e97ad33aSDoug Rabson }
667e97ad33aSDoug Rabson
668e97ad33aSDoug Rabson p9_free_req(clnt, req);
669e97ad33aSDoug Rabson return (error);
670e97ad33aSDoug Rabson }
671e97ad33aSDoug Rabson
672*1d99e8d9SMark Johnston int
p9_client_unlink(struct p9_fid * dfid,const char * name,int32_t flags)673*1d99e8d9SMark Johnston p9_client_unlink(struct p9_fid *dfid, const char *name, int32_t flags)
674*1d99e8d9SMark Johnston {
675*1d99e8d9SMark Johnston int error;
676*1d99e8d9SMark Johnston struct p9_client *clnt;
677*1d99e8d9SMark Johnston struct p9_req_t *req;
678*1d99e8d9SMark Johnston
679*1d99e8d9SMark Johnston error = 0;
680*1d99e8d9SMark Johnston clnt = dfid->clnt;
681*1d99e8d9SMark Johnston
682*1d99e8d9SMark Johnston req = p9_client_request(clnt, P9PROTO_TUNLINKAT, &error, "dsd",
683*1d99e8d9SMark Johnston dfid->fid, name, flags);
684*1d99e8d9SMark Johnston if (error != 0) {
685*1d99e8d9SMark Johnston P9_DEBUG(PROTO, "RUNLINKAT fid %d\n", dfid->fid);
686*1d99e8d9SMark Johnston return (error);
687*1d99e8d9SMark Johnston }
688*1d99e8d9SMark Johnston
689*1d99e8d9SMark Johnston p9_free_req(clnt, req);
690*1d99e8d9SMark Johnston return (error);
691*1d99e8d9SMark Johnston }
692*1d99e8d9SMark Johnston
693e97ad33aSDoug Rabson /* Inform the file server that the current file represented by fid is no longer
694e97ad33aSDoug Rabson * needed by the client. Any allocated fid on the server needs a clunk to be
695e97ad33aSDoug Rabson * destroyed.
696e97ad33aSDoug Rabson */
697e97ad33aSDoug Rabson int
p9_client_clunk(struct p9_fid * fid)698e97ad33aSDoug Rabson p9_client_clunk(struct p9_fid *fid)
699e97ad33aSDoug Rabson {
700e97ad33aSDoug Rabson int error;
701e97ad33aSDoug Rabson struct p9_client *clnt;
702e97ad33aSDoug Rabson struct p9_req_t *req;
703e97ad33aSDoug Rabson
704e97ad33aSDoug Rabson error = 0;
705e97ad33aSDoug Rabson
706e97ad33aSDoug Rabson if (fid == NULL) {
707e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: clunk with NULL fid is bad\n", __func__);
708e97ad33aSDoug Rabson return (0);
709e97ad33aSDoug Rabson }
710e97ad33aSDoug Rabson
711e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TCLUNK fid %d \n", fid->fid);
712e97ad33aSDoug Rabson
713e97ad33aSDoug Rabson clnt = fid->clnt;
714e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TCLUNK, &error, "d", fid->fid);
715e97ad33aSDoug Rabson if (req != NULL) {
716e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RCLUNK fid %d\n", fid->fid);
717e97ad33aSDoug Rabson p9_free_req(clnt, req);
718e97ad33aSDoug Rabson }
719e97ad33aSDoug Rabson
720e97ad33aSDoug Rabson p9_fid_destroy(fid);
721e97ad33aSDoug Rabson return (error);
722e97ad33aSDoug Rabson }
723e97ad33aSDoug Rabson
724e97ad33aSDoug Rabson /*
725e97ad33aSDoug Rabson * Client_walk is for searching any component name in a directory.
726e97ad33aSDoug Rabson * This is usually called on lookups. Also when we need a new open fid
727e97ad33aSDoug Rabson * as 9p needs to have an open fid for every file to fileops, we call this
728e97ad33aSDoug Rabson * validate the component of the file and return the newfid(openfid) created.
729e97ad33aSDoug Rabson */
730e97ad33aSDoug Rabson struct p9_fid *
p9_client_walk(struct p9_fid * oldfid,uint16_t nwnames,char ** wnames,int clone,int * error)731e97ad33aSDoug Rabson p9_client_walk(struct p9_fid *oldfid, uint16_t nwnames, char **wnames,
732e97ad33aSDoug Rabson int clone, int *error)
733e97ad33aSDoug Rabson {
734e97ad33aSDoug Rabson struct p9_client *clnt;
735e97ad33aSDoug Rabson struct p9_fid *fid;
736e97ad33aSDoug Rabson struct p9_qid *wqids;
737e97ad33aSDoug Rabson struct p9_req_t *req;
738e97ad33aSDoug Rabson uint16_t nwqids, count;
739e97ad33aSDoug Rabson
740e97ad33aSDoug Rabson clnt = oldfid->clnt;
741e97ad33aSDoug Rabson wqids = NULL;
742e97ad33aSDoug Rabson nwqids = 0;
743e97ad33aSDoug Rabson
744e97ad33aSDoug Rabson /*
745e97ad33aSDoug Rabson * Before, we go and create fid, make sure we are not tearing
746e97ad33aSDoug Rabson * down. Only then we create.
747e97ad33aSDoug Rabson * Allow only cleanup clunk messages once we are starting to teardown.
748e97ad33aSDoug Rabson */
749e97ad33aSDoug Rabson if (clnt->trans_status != P9FS_CONNECT) {
750e97ad33aSDoug Rabson *error = EIO;
751e97ad33aSDoug Rabson return (NULL);
752e97ad33aSDoug Rabson }
753e97ad33aSDoug Rabson
754e97ad33aSDoug Rabson if (clone) {
755e97ad33aSDoug Rabson fid = p9_fid_create(clnt);
756e97ad33aSDoug Rabson if (fid == NULL) {
757e97ad33aSDoug Rabson *error = ENOMEM;
758e97ad33aSDoug Rabson return (NULL);
759e97ad33aSDoug Rabson }
760e97ad33aSDoug Rabson fid->uid = oldfid->uid;
761e97ad33aSDoug Rabson } else
762e97ad33aSDoug Rabson fid = oldfid;
763e97ad33aSDoug Rabson
764e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TWALK fids %d,%d nwnames %u wname %s\n",
765e97ad33aSDoug Rabson oldfid->fid, fid->fid, nwnames,
766e97ad33aSDoug Rabson wnames != NULL ? wnames[nwnames-1] : NULL);
767e97ad33aSDoug Rabson
768e97ad33aSDoug Rabson /*
769e97ad33aSDoug Rabson * The newfid is for the component in search. We are preallocating as
770e97ad33aSDoug Rabson * qemu on other side allocates or returns a fid if it sees a match
771e97ad33aSDoug Rabson */
772e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TWALK, error, "ddT", oldfid->fid,
773e97ad33aSDoug Rabson fid->fid, wnames, nwnames);
774e97ad33aSDoug Rabson if (*error != 0) {
775e97ad33aSDoug Rabson if (fid != oldfid)
776e97ad33aSDoug Rabson p9_fid_destroy(fid);
777e97ad33aSDoug Rabson return (NULL);
778e97ad33aSDoug Rabson }
779e97ad33aSDoug Rabson
780e97ad33aSDoug Rabson *error = p9_buf_readf(req->rc, clnt->proto_version, "R", &nwqids,
781e97ad33aSDoug Rabson &wqids);
782e97ad33aSDoug Rabson if (*error != 0)
783e97ad33aSDoug Rabson goto out;
784e97ad33aSDoug Rabson
785e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RWALK nwqid %d:\n", nwqids);
786e97ad33aSDoug Rabson
787e97ad33aSDoug Rabson if (nwqids != nwnames) {
788e97ad33aSDoug Rabson *error = ENOENT;
789e97ad33aSDoug Rabson goto out;
790e97ad33aSDoug Rabson }
791e97ad33aSDoug Rabson
792e97ad33aSDoug Rabson for (count = 0; count < nwqids; count++)
793e97ad33aSDoug Rabson P9_DEBUG(TRANS, "%s: [%d] %x.%llx.%x\n",
794e97ad33aSDoug Rabson __func__, count, wqids[count].type,
795e97ad33aSDoug Rabson (unsigned long long)wqids[count].path,
796e97ad33aSDoug Rabson wqids[count].version);
797e97ad33aSDoug Rabson
798e97ad33aSDoug Rabson if (nwnames)
799e97ad33aSDoug Rabson memmove(&fid->qid, &wqids[nwqids - 1], sizeof(struct p9_qid));
800e97ad33aSDoug Rabson else
801e97ad33aSDoug Rabson fid->qid = oldfid->qid;
802e97ad33aSDoug Rabson
803e97ad33aSDoug Rabson p9_free_req(clnt, req);
804e97ad33aSDoug Rabson free(wqids, M_TEMP);
805e97ad33aSDoug Rabson return (fid);
806e97ad33aSDoug Rabson
807e97ad33aSDoug Rabson out:
808e97ad33aSDoug Rabson p9_free_req(clnt, req);
809e97ad33aSDoug Rabson if (wqids)
810e97ad33aSDoug Rabson free(wqids, M_TEMP);
811e97ad33aSDoug Rabson if (fid && fid != oldfid)
812e97ad33aSDoug Rabson p9_client_clunk(fid);
813e97ad33aSDoug Rabson return (NULL);
814e97ad33aSDoug Rabson }
815e97ad33aSDoug Rabson
816e97ad33aSDoug Rabson /* Open a file with given fid and mode */
817e97ad33aSDoug Rabson int
p9_client_open(struct p9_fid * fid,int mode)818e97ad33aSDoug Rabson p9_client_open(struct p9_fid *fid, int mode)
819e97ad33aSDoug Rabson {
820e97ad33aSDoug Rabson int error, mtu;
821e97ad33aSDoug Rabson struct p9_client *clnt;
822e97ad33aSDoug Rabson struct p9_req_t *req;
823e97ad33aSDoug Rabson
824e97ad33aSDoug Rabson error = 0;
825e97ad33aSDoug Rabson clnt = fid->clnt;
826e97ad33aSDoug Rabson mtu = 0;
827e97ad33aSDoug Rabson
828e97ad33aSDoug Rabson P9_DEBUG(PROTO, "%s fid %d mode %d\n",
829e97ad33aSDoug Rabson p9_is_proto_dotl(clnt) ? "TLOPEN" : "TOPEN",
830e97ad33aSDoug Rabson fid->fid, mode);
831e97ad33aSDoug Rabson
832e97ad33aSDoug Rabson if (fid->mode != -1)
833e97ad33aSDoug Rabson return (EINVAL);
834e97ad33aSDoug Rabson
835e97ad33aSDoug Rabson if (p9_is_proto_dotl(clnt))
836e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TLOPEN, &error, "dd",
837e97ad33aSDoug Rabson fid->fid, mode);
838e97ad33aSDoug Rabson else
839e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TOPEN, &error, "db",
840e97ad33aSDoug Rabson fid->fid, mode);
841e97ad33aSDoug Rabson
842e97ad33aSDoug Rabson if (error != 0)
843e97ad33aSDoug Rabson return (error);
844e97ad33aSDoug Rabson
845e97ad33aSDoug Rabson error = p9_buf_readf(req->rc, clnt->proto_version, "Qd", &fid->qid,
846e97ad33aSDoug Rabson &mtu);
847e97ad33aSDoug Rabson if (error != 0)
848e97ad33aSDoug Rabson goto out;
849e97ad33aSDoug Rabson
850e97ad33aSDoug Rabson P9_DEBUG(PROTO, "%s qid %x.%llx.%x mtu %x\n",
851e97ad33aSDoug Rabson p9_is_proto_dotl(clnt) ? "RLOPEN" : "ROPEN",
852e97ad33aSDoug Rabson (fid->qid).type, (unsigned long long)(fid->qid).path,
853e97ad33aSDoug Rabson (fid->qid).version, mtu);
854e97ad33aSDoug Rabson
855e97ad33aSDoug Rabson fid->mode = mode;
856e97ad33aSDoug Rabson fid->mtu = mtu;
857e97ad33aSDoug Rabson out:
858e97ad33aSDoug Rabson p9_free_req(clnt, req);
859e97ad33aSDoug Rabson return (error);
860e97ad33aSDoug Rabson }
861e97ad33aSDoug Rabson
862e97ad33aSDoug Rabson /* Request to get directory entries */
863e97ad33aSDoug Rabson int
p9_client_readdir(struct p9_fid * fid,char * data,uint64_t offset,uint32_t count)864e97ad33aSDoug Rabson p9_client_readdir(struct p9_fid *fid, char *data, uint64_t offset,
865e97ad33aSDoug Rabson uint32_t count)
866e97ad33aSDoug Rabson {
867e97ad33aSDoug Rabson int error;
868e97ad33aSDoug Rabson uint32_t rsize;
869e97ad33aSDoug Rabson struct p9_client *clnt;
870e97ad33aSDoug Rabson struct p9_req_t *req;
871e97ad33aSDoug Rabson char *dataptr;
872e97ad33aSDoug Rabson
873e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TREADDIR fid %d offset %llu count %d\n",
874e97ad33aSDoug Rabson fid->fid, (unsigned long long) offset, count);
875e97ad33aSDoug Rabson
876e97ad33aSDoug Rabson error = 0;
877e97ad33aSDoug Rabson rsize = fid->mtu;
878e97ad33aSDoug Rabson clnt = fid->clnt;
879e97ad33aSDoug Rabson
880e97ad33aSDoug Rabson if (rsize == 0 || rsize > clnt->msize)
881e97ad33aSDoug Rabson rsize = clnt->msize;
882e97ad33aSDoug Rabson
883e97ad33aSDoug Rabson if (count < rsize)
884e97ad33aSDoug Rabson rsize = count;
885e97ad33aSDoug Rabson
886e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TREADDIR, &error, "dqd",
887e97ad33aSDoug Rabson fid->fid, offset, rsize);
888e97ad33aSDoug Rabson
889e97ad33aSDoug Rabson if (error != 0) {
890e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: couldn't allocate req in client_readdir\n",
891e97ad33aSDoug Rabson __func__);
892e97ad33aSDoug Rabson return (-error);
893e97ad33aSDoug Rabson }
894e97ad33aSDoug Rabson
895e97ad33aSDoug Rabson error = p9_buf_readf(req->rc, clnt->proto_version, "D", &count,
896e97ad33aSDoug Rabson &dataptr);
897e97ad33aSDoug Rabson if (error != 0) {
898e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: p0_buf_readf failed: %d\n",
899e97ad33aSDoug Rabson __func__, error);
900e97ad33aSDoug Rabson p9_free_req(clnt, req);
901e97ad33aSDoug Rabson return (-error);
902e97ad33aSDoug Rabson }
903e97ad33aSDoug Rabson
904e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RREADDIR count %u\n", count);
905e97ad33aSDoug Rabson
906e97ad33aSDoug Rabson /* Copy back the data into the input buffer. */
907e97ad33aSDoug Rabson memmove(data, dataptr, count);
908e97ad33aSDoug Rabson p9_free_req(clnt, req);
909e97ad33aSDoug Rabson return (count);
910e97ad33aSDoug Rabson }
911e97ad33aSDoug Rabson
912e97ad33aSDoug Rabson /*
913e97ad33aSDoug Rabson * Read count bytes from offset for the file fid into the character
914e97ad33aSDoug Rabson * buffer data. This buffer is handed over to p9fs to process into user
915e97ad33aSDoug Rabson * buffers. Note that this function typically returns the number of bytes read
916e97ad33aSDoug Rabson * so in case of an error we return -error so that we can distinguish between
917e97ad33aSDoug Rabson * error codes and bytes.
918e97ad33aSDoug Rabson */
919e97ad33aSDoug Rabson int
p9_client_read(struct p9_fid * fid,uint64_t offset,uint32_t count,char * data)920e97ad33aSDoug Rabson p9_client_read(struct p9_fid *fid, uint64_t offset, uint32_t count, char *data)
921e97ad33aSDoug Rabson {
922e97ad33aSDoug Rabson struct p9_client *clnt;
923e97ad33aSDoug Rabson struct p9_req_t *req;
924e97ad33aSDoug Rabson char *dataptr;
925e97ad33aSDoug Rabson int error, rsize;
926e97ad33aSDoug Rabson
927e97ad33aSDoug Rabson clnt = fid->clnt;
928e97ad33aSDoug Rabson rsize = fid->mtu;
929e97ad33aSDoug Rabson error = 0;
930e97ad33aSDoug Rabson
931e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TREAD fid %d offset %llu %u\n",
932e97ad33aSDoug Rabson fid->fid, (unsigned long long) offset, count);
933e97ad33aSDoug Rabson
934e97ad33aSDoug Rabson if (!rsize || rsize > clnt->msize)
935e97ad33aSDoug Rabson rsize = clnt->msize;
936e97ad33aSDoug Rabson
937e97ad33aSDoug Rabson if (count < rsize)
938e97ad33aSDoug Rabson rsize = count;
939e97ad33aSDoug Rabson
940e97ad33aSDoug Rabson /* At this stage, we only have 8K buffers so only transfer */
941e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TREAD, &error, "dqd", fid->fid,
942e97ad33aSDoug Rabson offset, rsize);
943e97ad33aSDoug Rabson if (error != 0) {
944e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: failed allocate request\n", __func__);
945e97ad33aSDoug Rabson return (-error);
946e97ad33aSDoug Rabson }
947e97ad33aSDoug Rabson
948e97ad33aSDoug Rabson error = p9_buf_readf(req->rc, clnt->proto_version, "D", &count,
949e97ad33aSDoug Rabson &dataptr);
950e97ad33aSDoug Rabson if (error != 0) {
951e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: p9_buf_readf failed: %d\n",
952e97ad33aSDoug Rabson __func__, error);
953e97ad33aSDoug Rabson goto out;
954e97ad33aSDoug Rabson }
955e97ad33aSDoug Rabson
956e97ad33aSDoug Rabson if (rsize < count) {
957e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RREAD count (%d > %d)\n", count, rsize);
958e97ad33aSDoug Rabson count = rsize;
959e97ad33aSDoug Rabson }
960e97ad33aSDoug Rabson
961e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RREAD count %d\n", count);
962e97ad33aSDoug Rabson
963e97ad33aSDoug Rabson if (count == 0) {
964e97ad33aSDoug Rabson error = -EIO;
965e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: EIO error in client_read \n", __func__);
966e97ad33aSDoug Rabson goto out;
967e97ad33aSDoug Rabson }
968e97ad33aSDoug Rabson
969e97ad33aSDoug Rabson /* Copy back the data into the input buffer. */
970e97ad33aSDoug Rabson memmove(data, dataptr, count);
971e97ad33aSDoug Rabson p9_free_req(clnt, req);
972e97ad33aSDoug Rabson return (count);
973e97ad33aSDoug Rabson out:
974e97ad33aSDoug Rabson p9_free_req(clnt, req);
975e97ad33aSDoug Rabson return (-error);
976e97ad33aSDoug Rabson }
977e97ad33aSDoug Rabson
978e97ad33aSDoug Rabson /*
979e97ad33aSDoug Rabson * Write count bytes from buffer to the offset for the file fid
980e97ad33aSDoug Rabson * Note that this function typically returns the number of bytes written
981e97ad33aSDoug Rabson * so in case of an error we return -error so that we can distinguish between
982e97ad33aSDoug Rabson * error codes and bytes.
983e97ad33aSDoug Rabson */
984e97ad33aSDoug Rabson
985e97ad33aSDoug Rabson int
p9_client_write(struct p9_fid * fid,uint64_t offset,uint32_t count,char * data)986e97ad33aSDoug Rabson p9_client_write(struct p9_fid *fid, uint64_t offset, uint32_t count, char *data)
987e97ad33aSDoug Rabson {
988e97ad33aSDoug Rabson struct p9_client *clnt;
989e97ad33aSDoug Rabson struct p9_req_t *req;
990e97ad33aSDoug Rabson int ret, error, rsize;
991e97ad33aSDoug Rabson
992e97ad33aSDoug Rabson clnt = fid->clnt;
993e97ad33aSDoug Rabson rsize = fid->mtu;
994e97ad33aSDoug Rabson ret = 0;
995e97ad33aSDoug Rabson error = 0;
996e97ad33aSDoug Rabson
997e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TWRITE fid %d offset %llu %u\n",
998e97ad33aSDoug Rabson fid->fid, (unsigned long long) offset, count);
999e97ad33aSDoug Rabson
1000e97ad33aSDoug Rabson if (!rsize || rsize > clnt->msize)
1001e97ad33aSDoug Rabson rsize = clnt->msize;
1002e97ad33aSDoug Rabson
1003e97ad33aSDoug Rabson /* Limit set by Qemu ,8168 */
1004e97ad33aSDoug Rabson if (count > rsize) {
1005e97ad33aSDoug Rabson count = rsize;
1006e97ad33aSDoug Rabson }
1007e97ad33aSDoug Rabson
1008e97ad33aSDoug Rabson /*
1009e97ad33aSDoug Rabson * Doing the Data blob instead. If at all we add the zerocopy, we can
1010e97ad33aSDoug Rabson * change it to uio direct copy
1011e97ad33aSDoug Rabson */
1012e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TWRITE, &error, "dqD", fid->fid,
1013e97ad33aSDoug Rabson offset, count, data);
1014e97ad33aSDoug Rabson if (error != 0) {
1015e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: failed allocate request: %d\n",
1016e97ad33aSDoug Rabson __func__, error);
1017e97ad33aSDoug Rabson return (-error);
1018e97ad33aSDoug Rabson }
1019e97ad33aSDoug Rabson
1020e97ad33aSDoug Rabson error = p9_buf_readf(req->rc, clnt->proto_version, "d", &ret);
1021e97ad33aSDoug Rabson if (error != 0) {
1022e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: p9_buf_readf error: %d\n",
1023e97ad33aSDoug Rabson __func__, error);
1024e97ad33aSDoug Rabson goto out;
1025e97ad33aSDoug Rabson }
1026e97ad33aSDoug Rabson
1027e97ad33aSDoug Rabson if (count < ret) {
1028e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RWRITE count (%d > %d)\n", count, ret);
1029e97ad33aSDoug Rabson ret = count;
1030e97ad33aSDoug Rabson }
1031e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RWRITE count %d\n", ret);
1032e97ad33aSDoug Rabson
1033e97ad33aSDoug Rabson if (count == 0) {
1034e97ad33aSDoug Rabson error = EIO;
1035e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: EIO error\n", __func__);
1036e97ad33aSDoug Rabson goto out;
1037e97ad33aSDoug Rabson }
1038e97ad33aSDoug Rabson
1039e97ad33aSDoug Rabson p9_free_req(clnt, req);
1040e97ad33aSDoug Rabson return (ret);
1041e97ad33aSDoug Rabson out:
1042e97ad33aSDoug Rabson p9_free_req(clnt, req);
1043e97ad33aSDoug Rabson return (-error);
1044e97ad33aSDoug Rabson }
1045e97ad33aSDoug Rabson
1046e97ad33aSDoug Rabson
1047e97ad33aSDoug Rabson /* Create file under directory fid, with name, permissions, mode. */
1048e97ad33aSDoug Rabson int
p9_client_file_create(struct p9_fid * fid,char * name,uint32_t perm,int mode,char * extension)1049e97ad33aSDoug Rabson p9_client_file_create(struct p9_fid *fid, char *name, uint32_t perm, int mode,
1050e97ad33aSDoug Rabson char *extension)
1051e97ad33aSDoug Rabson {
1052e97ad33aSDoug Rabson int error;
1053e97ad33aSDoug Rabson struct p9_client *clnt;
1054e97ad33aSDoug Rabson struct p9_req_t *req;
1055e97ad33aSDoug Rabson struct p9_qid qid;
1056e97ad33aSDoug Rabson int mtu;
1057e97ad33aSDoug Rabson
1058e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TCREATE fid %d name %s perm %d mode %d\n",
1059e97ad33aSDoug Rabson fid->fid, name, perm, mode);
1060e97ad33aSDoug Rabson
1061e97ad33aSDoug Rabson clnt = fid->clnt;
1062e97ad33aSDoug Rabson error = 0;
1063e97ad33aSDoug Rabson
1064e97ad33aSDoug Rabson if (fid->mode != -1)
1065e97ad33aSDoug Rabson return (EINVAL);
1066e97ad33aSDoug Rabson
1067e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TCREATE, &error, "dsdb?s",
1068e97ad33aSDoug Rabson fid->fid, name, perm, mode, extension);
1069e97ad33aSDoug Rabson if (error != 0)
1070e97ad33aSDoug Rabson return (error);
1071e97ad33aSDoug Rabson
1072e97ad33aSDoug Rabson error = p9_buf_readf(req->rc, clnt->proto_version, "Qd", &qid, &mtu);
1073e97ad33aSDoug Rabson if (error != 0)
1074e97ad33aSDoug Rabson goto out;
1075e97ad33aSDoug Rabson
1076e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RCREATE qid %x.%jx.%x mtu %x\n",
1077e97ad33aSDoug Rabson qid.type, (uintmax_t)qid.path, qid.version, mtu);
1078e97ad33aSDoug Rabson fid->mode = mode;
1079e97ad33aSDoug Rabson fid->mtu = mtu;
1080e97ad33aSDoug Rabson
1081e97ad33aSDoug Rabson out:
1082e97ad33aSDoug Rabson p9_free_req(clnt, req);
1083e97ad33aSDoug Rabson return (error);
1084e97ad33aSDoug Rabson }
1085e97ad33aSDoug Rabson
1086e97ad33aSDoug Rabson /* Request file system information of the file system */
1087e97ad33aSDoug Rabson int
p9_client_statfs(struct p9_fid * fid,struct p9_statfs * stat)1088e97ad33aSDoug Rabson p9_client_statfs(struct p9_fid *fid, struct p9_statfs *stat)
1089e97ad33aSDoug Rabson {
1090e97ad33aSDoug Rabson int error;
1091e97ad33aSDoug Rabson struct p9_req_t *req;
1092e97ad33aSDoug Rabson struct p9_client *clnt;
1093e97ad33aSDoug Rabson
1094e97ad33aSDoug Rabson error = 0;
1095e97ad33aSDoug Rabson clnt = fid->clnt;
1096e97ad33aSDoug Rabson
1097e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TSTATFS fid %d\n", fid->fid);
1098e97ad33aSDoug Rabson
1099e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TSTATFS, &error, "d", fid->fid);
1100e97ad33aSDoug Rabson if (error != 0) {
1101e97ad33aSDoug Rabson return (error);
1102e97ad33aSDoug Rabson }
1103e97ad33aSDoug Rabson
1104e97ad33aSDoug Rabson error = p9_buf_readf(req->rc, clnt->proto_version, "ddqqqqqqd",
1105e97ad33aSDoug Rabson &stat->type, &stat->bsize, &stat->blocks, &stat->bfree,
1106e97ad33aSDoug Rabson &stat->bavail, &stat->files, &stat->ffree, &stat->fsid,
1107e97ad33aSDoug Rabson &stat->namelen);
1108e97ad33aSDoug Rabson
1109e97ad33aSDoug Rabson if (error != 0)
1110e97ad33aSDoug Rabson goto out;
1111e97ad33aSDoug Rabson
1112e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RSTATFS fid %d type 0x%jx bsize %ju "
1113e97ad33aSDoug Rabson "blocks %ju bfree %ju bavail %ju files %ju ffree %ju "
1114e97ad33aSDoug Rabson "fsid %ju namelen %ju\n",
1115e97ad33aSDoug Rabson fid->fid, (uintmax_t)stat->type,
1116e97ad33aSDoug Rabson (uintmax_t)stat->bsize, (uintmax_t)stat->blocks,
1117e97ad33aSDoug Rabson (uintmax_t)stat->bfree, (uintmax_t)stat->bavail,
1118e97ad33aSDoug Rabson (uintmax_t)stat->files, (uintmax_t)stat->ffree,
1119e97ad33aSDoug Rabson (uintmax_t)stat->fsid, (uintmax_t)stat->namelen);
1120e97ad33aSDoug Rabson
1121e97ad33aSDoug Rabson out:
1122e97ad33aSDoug Rabson p9_free_req(clnt, req);
1123e97ad33aSDoug Rabson return (error);
1124e97ad33aSDoug Rabson }
1125e97ad33aSDoug Rabson
1126e97ad33aSDoug Rabson /* Rename file referenced by the fid */
1127e97ad33aSDoug Rabson int
p9_client_renameat(struct p9_fid * oldfid,char * oldname,struct p9_fid * newfid,char * newname)1128e97ad33aSDoug Rabson p9_client_renameat(struct p9_fid *oldfid, char *oldname, struct p9_fid *newfid,
1129e97ad33aSDoug Rabson char *newname)
1130e97ad33aSDoug Rabson {
1131e97ad33aSDoug Rabson int error;
1132e97ad33aSDoug Rabson struct p9_client *clnt;
1133e97ad33aSDoug Rabson struct p9_req_t *req;
1134e97ad33aSDoug Rabson
1135e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TRENAMEAT oldfid %d oldname %s newfid %d newfid %s",
1136e97ad33aSDoug Rabson oldfid->fid, oldname, newfid->fid, newname);
1137e97ad33aSDoug Rabson
1138e97ad33aSDoug Rabson error = 0;
1139e97ad33aSDoug Rabson clnt = oldfid->clnt;
1140e97ad33aSDoug Rabson
1141e97ad33aSDoug Rabson /*
1142e97ad33aSDoug Rabson * we are calling the request with TRENAMEAT tag and not TRENAME with
1143e97ad33aSDoug Rabson * the 9p protocol version 9p2000.u as the QEMU version supports this
1144e97ad33aSDoug Rabson * version of renaming
1145e97ad33aSDoug Rabson */
1146e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TRENAMEAT, &error, "dsds",
1147e97ad33aSDoug Rabson oldfid->fid, oldname, newfid->fid, newname);
1148e97ad33aSDoug Rabson
1149e97ad33aSDoug Rabson if (error != 0)
1150e97ad33aSDoug Rabson return (error);
1151e97ad33aSDoug Rabson
1152e97ad33aSDoug Rabson p9_free_req(clnt, req);
1153e97ad33aSDoug Rabson return (error);
1154e97ad33aSDoug Rabson }
1155e97ad33aSDoug Rabson
1156e97ad33aSDoug Rabson /* Request to create symbolic link */
1157e97ad33aSDoug Rabson int
p9_create_symlink(struct p9_fid * fid,char * name,char * symtgt,gid_t gid)1158e97ad33aSDoug Rabson p9_create_symlink(struct p9_fid *fid, char *name, char *symtgt, gid_t gid)
1159e97ad33aSDoug Rabson {
1160e97ad33aSDoug Rabson int error;
1161e97ad33aSDoug Rabson struct p9_req_t *req;
1162e97ad33aSDoug Rabson struct p9_client *clnt;
1163e97ad33aSDoug Rabson struct p9_qid qid;
1164e97ad33aSDoug Rabson
1165e97ad33aSDoug Rabson error = 0;
1166e97ad33aSDoug Rabson clnt = fid->clnt;
1167e97ad33aSDoug Rabson
1168e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TSYMLINK fid %d name %s\n", fid->fid, name);
1169e97ad33aSDoug Rabson
1170e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TSYMLINK, &error, "dssd",
1171e97ad33aSDoug Rabson fid->fid, name, symtgt, gid);
1172e97ad33aSDoug Rabson
1173e97ad33aSDoug Rabson if (error != 0)
1174e97ad33aSDoug Rabson return (error);
1175e97ad33aSDoug Rabson
1176e97ad33aSDoug Rabson error = p9_buf_readf(req->rc, clnt->proto_version, "Q", &qid);
1177e97ad33aSDoug Rabson if (error != 0) {
1178e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: buf_readf failed %d\n", __func__, error);
1179e97ad33aSDoug Rabson return (error);
1180e97ad33aSDoug Rabson }
1181e97ad33aSDoug Rabson
1182e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RSYMLINK qid %x.%jx.%x\n",
1183e97ad33aSDoug Rabson qid.type, (uintmax_t)qid.path, qid.version);
1184e97ad33aSDoug Rabson
1185e97ad33aSDoug Rabson p9_free_req(clnt, req);
1186e97ad33aSDoug Rabson return (0);
1187e97ad33aSDoug Rabson }
1188e97ad33aSDoug Rabson
1189e97ad33aSDoug Rabson /* Request to create hard link */
1190e97ad33aSDoug Rabson int
p9_create_hardlink(struct p9_fid * dfid,struct p9_fid * oldfid,char * name)1191e97ad33aSDoug Rabson p9_create_hardlink(struct p9_fid *dfid, struct p9_fid *oldfid, char *name)
1192e97ad33aSDoug Rabson {
1193e97ad33aSDoug Rabson int error;
1194e97ad33aSDoug Rabson struct p9_req_t *req;
1195e97ad33aSDoug Rabson struct p9_client *clnt;
1196e97ad33aSDoug Rabson
1197e97ad33aSDoug Rabson error = 0;
1198e97ad33aSDoug Rabson clnt = dfid->clnt;
1199e97ad33aSDoug Rabson
1200e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TLINK dfid %d oldfid %d name %s\n",
1201e97ad33aSDoug Rabson dfid->fid, oldfid->fid, name);
1202e97ad33aSDoug Rabson
1203e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TLINK, &error, "dds", dfid->fid,
1204e97ad33aSDoug Rabson oldfid->fid, name);
1205e97ad33aSDoug Rabson if (error != 0)
1206e97ad33aSDoug Rabson return (error);
1207e97ad33aSDoug Rabson
1208e97ad33aSDoug Rabson p9_free_req(clnt, req);
1209e97ad33aSDoug Rabson return (0);
1210e97ad33aSDoug Rabson }
1211e97ad33aSDoug Rabson
1212e97ad33aSDoug Rabson /* Request to read contents of symbolic link */
1213e97ad33aSDoug Rabson int
p9_readlink(struct p9_fid * fid,char ** target)1214e97ad33aSDoug Rabson p9_readlink(struct p9_fid *fid, char **target)
1215e97ad33aSDoug Rabson {
1216e97ad33aSDoug Rabson int error;
1217e97ad33aSDoug Rabson struct p9_client *clnt;
1218e97ad33aSDoug Rabson struct p9_req_t *req;
1219e97ad33aSDoug Rabson
1220e97ad33aSDoug Rabson error = 0;
1221e97ad33aSDoug Rabson clnt = fid->clnt;
1222e97ad33aSDoug Rabson
1223e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TREADLINK fid %d\n", fid->fid);
1224e97ad33aSDoug Rabson
1225e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TREADLINK, &error, "d", fid->fid);
1226e97ad33aSDoug Rabson if (error != 0)
1227e97ad33aSDoug Rabson return (error);
1228e97ad33aSDoug Rabson
1229e97ad33aSDoug Rabson error = p9_buf_readf(req->rc, clnt->proto_version, "s", target);
1230e97ad33aSDoug Rabson if (error != 0) {
1231e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: buf_readf failed %d\n", __func__, error);
1232e97ad33aSDoug Rabson return (error);
1233e97ad33aSDoug Rabson }
1234e97ad33aSDoug Rabson
1235e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RREADLINK target %s \n", *target);
1236e97ad33aSDoug Rabson
1237e97ad33aSDoug Rabson p9_free_req(clnt, req);
1238e97ad33aSDoug Rabson return (0);
1239e97ad33aSDoug Rabson }
1240e97ad33aSDoug Rabson
1241e97ad33aSDoug Rabson /* Get file attributes of the file referenced by the fid */
1242e97ad33aSDoug Rabson int
p9_client_getattr(struct p9_fid * fid,struct p9_stat_dotl * stat_dotl,uint64_t request_mask)1243e97ad33aSDoug Rabson p9_client_getattr(struct p9_fid *fid, struct p9_stat_dotl *stat_dotl,
1244e97ad33aSDoug Rabson uint64_t request_mask)
1245e97ad33aSDoug Rabson {
1246e97ad33aSDoug Rabson int err;
1247e97ad33aSDoug Rabson struct p9_client *clnt;
1248e97ad33aSDoug Rabson struct p9_req_t *req;
1249e97ad33aSDoug Rabson
1250e97ad33aSDoug Rabson err = 0;
1251e97ad33aSDoug Rabson
1252e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TGETATTR fid %d mask %ju\n",
1253e97ad33aSDoug Rabson fid->fid, (uintmax_t)request_mask);
1254e97ad33aSDoug Rabson
1255e97ad33aSDoug Rabson clnt = fid->clnt;
1256e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TGETATTR, &err, "dq", fid->fid,
1257e97ad33aSDoug Rabson request_mask);
1258e97ad33aSDoug Rabson if (req == NULL) {
1259e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: allocation failed %d", __func__, err);
1260e97ad33aSDoug Rabson goto error;
1261e97ad33aSDoug Rabson }
1262e97ad33aSDoug Rabson
1263e97ad33aSDoug Rabson err = p9_buf_readf(req->rc, clnt->proto_version, "A", stat_dotl);
1264e97ad33aSDoug Rabson if (err != 0) {
1265e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: buf_readf failed %d\n", __func__, err);
1266e97ad33aSDoug Rabson goto error;
1267e97ad33aSDoug Rabson }
1268e97ad33aSDoug Rabson
1269e97ad33aSDoug Rabson p9_free_req(clnt, req);
1270e97ad33aSDoug Rabson P9_DEBUG(PROTO, "RGETATTR fid %d qid %x.%jx.%x st_mode %8.8x "
1271e97ad33aSDoug Rabson "uid %d gid %d nlink %ju rdev %jx st_size %jx blksize %ju "
1272e97ad33aSDoug Rabson "blocks %ju st_atime_sec %ju, st_atime_nsec %ju "
1273e97ad33aSDoug Rabson "st_mtime_sec %ju, st_mtime_nsec %ju st_ctime_sec %ju "
1274e97ad33aSDoug Rabson "st_ctime_nsec %ju st_btime_sec %ju, st_btime_nsec %ju "
1275e97ad33aSDoug Rabson "st_stat %ju, st_data_version %ju \n", fid->fid,
1276e97ad33aSDoug Rabson stat_dotl->qid.type, (uintmax_t)stat_dotl->qid.path,
1277e97ad33aSDoug Rabson stat_dotl->qid.version, stat_dotl->st_mode, stat_dotl->st_uid,
1278e97ad33aSDoug Rabson stat_dotl->st_gid, (uintmax_t)stat_dotl->st_nlink,
1279e97ad33aSDoug Rabson (uintmax_t)stat_dotl->st_rdev, (uintmax_t)stat_dotl->st_size,
1280e97ad33aSDoug Rabson (uintmax_t)stat_dotl->st_blksize,
1281e97ad33aSDoug Rabson (uintmax_t)stat_dotl->st_blocks, (uintmax_t)stat_dotl->st_atime_sec,
1282e97ad33aSDoug Rabson (uintmax_t)stat_dotl->st_atime_nsec, (uintmax_t)stat_dotl->st_mtime_sec,
1283e97ad33aSDoug Rabson (uintmax_t)stat_dotl->st_mtime_nsec, (uintmax_t)stat_dotl->st_ctime_sec,
1284e97ad33aSDoug Rabson (uintmax_t)stat_dotl->st_ctime_nsec, (uintmax_t)stat_dotl->st_btime_sec,
1285e97ad33aSDoug Rabson (uintmax_t)stat_dotl->st_btime_nsec, (uintmax_t)stat_dotl->st_gen,
1286e97ad33aSDoug Rabson (uintmax_t)stat_dotl->st_data_version);
1287e97ad33aSDoug Rabson
1288e97ad33aSDoug Rabson return (err);
1289e97ad33aSDoug Rabson
1290e97ad33aSDoug Rabson error:
1291e97ad33aSDoug Rabson if (req != NULL)
1292e97ad33aSDoug Rabson p9_free_req(clnt, req);
1293e97ad33aSDoug Rabson
1294e97ad33aSDoug Rabson return (err);
1295e97ad33aSDoug Rabson }
1296e97ad33aSDoug Rabson
1297e97ad33aSDoug Rabson /* Set file attributes of the file referenced by the fid */
1298e97ad33aSDoug Rabson int
p9_client_setattr(struct p9_fid * fid,struct p9_iattr_dotl * p9attr)1299e97ad33aSDoug Rabson p9_client_setattr(struct p9_fid *fid, struct p9_iattr_dotl *p9attr)
1300e97ad33aSDoug Rabson {
1301e97ad33aSDoug Rabson int err;
1302e97ad33aSDoug Rabson struct p9_req_t *req;
1303e97ad33aSDoug Rabson struct p9_client *clnt;
1304e97ad33aSDoug Rabson
1305e97ad33aSDoug Rabson err = 0;
1306e97ad33aSDoug Rabson
1307e97ad33aSDoug Rabson P9_DEBUG(PROTO, "TSETATTR fid %d"
1308e97ad33aSDoug Rabson " valid %x mode %x uid %d gid %d size %ju"
1309e97ad33aSDoug Rabson " atime_sec %ju atime_nsec %ju"
1310e97ad33aSDoug Rabson " mtime_sec %ju mtime_nsec %ju\n",
1311e97ad33aSDoug Rabson fid->fid,
1312e97ad33aSDoug Rabson p9attr->valid, p9attr->mode, p9attr->uid, p9attr->gid,
1313e97ad33aSDoug Rabson (uintmax_t)p9attr->size, (uintmax_t)p9attr->atime_sec,
1314e97ad33aSDoug Rabson (uintmax_t)p9attr->atime_nsec, (uintmax_t)p9attr->mtime_sec,
1315e97ad33aSDoug Rabson (uintmax_t)p9attr->mtime_nsec);
1316e97ad33aSDoug Rabson
1317e97ad33aSDoug Rabson clnt = fid->clnt;
1318e97ad33aSDoug Rabson
1319e97ad33aSDoug Rabson /* Any client_request error is converted to req == NULL error*/
1320e97ad33aSDoug Rabson req = p9_client_request(clnt, P9PROTO_TSETATTR, &err, "dA", fid->fid,
1321e97ad33aSDoug Rabson p9attr);
1322e97ad33aSDoug Rabson
1323e97ad33aSDoug Rabson if (req == NULL) {
1324e97ad33aSDoug Rabson P9_DEBUG(ERROR, "%s: allocation failed %d\n", __func__, err);
1325e97ad33aSDoug Rabson goto error;
1326e97ad33aSDoug Rabson }
1327e97ad33aSDoug Rabson
1328e97ad33aSDoug Rabson p9_free_req(clnt, req);
1329e97ad33aSDoug Rabson error:
1330e97ad33aSDoug Rabson return (err);
1331e97ad33aSDoug Rabson }
1332e97ad33aSDoug Rabson
1333