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