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 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 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 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 * 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 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 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 * 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 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 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 */ 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 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 * 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 * 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 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 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 * 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 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 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 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 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 * 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 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 * 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 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 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 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 * 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 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 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 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 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 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 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 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 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 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 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 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 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