1*60ce86c7SWei Liu /* 2*60ce86c7SWei Liu * Virtio 9p backend 3*60ce86c7SWei Liu * 4*60ce86c7SWei Liu * Copyright IBM, Corp. 2010 5*60ce86c7SWei Liu * 6*60ce86c7SWei Liu * Authors: 7*60ce86c7SWei Liu * Anthony Liguori <aliguori@us.ibm.com> 8*60ce86c7SWei Liu * 9*60ce86c7SWei Liu * This work is licensed under the terms of the GNU GPL, version 2. See 10*60ce86c7SWei Liu * the COPYING file in the top-level directory. 11*60ce86c7SWei Liu * 12*60ce86c7SWei Liu */ 13*60ce86c7SWei Liu 14*60ce86c7SWei Liu #include "hw/virtio/virtio.h" 15*60ce86c7SWei Liu #include "hw/i386/pc.h" 16*60ce86c7SWei Liu #include "qemu/error-report.h" 17*60ce86c7SWei Liu #include "qemu/iov.h" 18*60ce86c7SWei Liu #include "qemu/sockets.h" 19*60ce86c7SWei Liu #include "virtio-9p.h" 20*60ce86c7SWei Liu #include "fsdev/qemu-fsdev.h" 21*60ce86c7SWei Liu #include "9p-xattr.h" 22*60ce86c7SWei Liu #include "coth.h" 23*60ce86c7SWei Liu #include "trace.h" 24*60ce86c7SWei Liu #include "migration/migration.h" 25*60ce86c7SWei Liu 26*60ce86c7SWei Liu int open_fd_hw; 27*60ce86c7SWei Liu int total_open_fd; 28*60ce86c7SWei Liu static int open_fd_rc; 29*60ce86c7SWei Liu 30*60ce86c7SWei Liu enum { 31*60ce86c7SWei Liu Oread = 0x00, 32*60ce86c7SWei Liu Owrite = 0x01, 33*60ce86c7SWei Liu Ordwr = 0x02, 34*60ce86c7SWei Liu Oexec = 0x03, 35*60ce86c7SWei Liu Oexcl = 0x04, 36*60ce86c7SWei Liu Otrunc = 0x10, 37*60ce86c7SWei Liu Orexec = 0x20, 38*60ce86c7SWei Liu Orclose = 0x40, 39*60ce86c7SWei Liu Oappend = 0x80, 40*60ce86c7SWei Liu }; 41*60ce86c7SWei Liu 42*60ce86c7SWei Liu ssize_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) 43*60ce86c7SWei Liu { 44*60ce86c7SWei Liu ssize_t ret; 45*60ce86c7SWei Liu va_list ap; 46*60ce86c7SWei Liu 47*60ce86c7SWei Liu va_start(ap, fmt); 48*60ce86c7SWei Liu ret = virtio_pdu_vmarshal(pdu, offset, fmt, ap); 49*60ce86c7SWei Liu va_end(ap); 50*60ce86c7SWei Liu 51*60ce86c7SWei Liu return ret; 52*60ce86c7SWei Liu } 53*60ce86c7SWei Liu 54*60ce86c7SWei Liu ssize_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...) 55*60ce86c7SWei Liu { 56*60ce86c7SWei Liu ssize_t ret; 57*60ce86c7SWei Liu va_list ap; 58*60ce86c7SWei Liu 59*60ce86c7SWei Liu va_start(ap, fmt); 60*60ce86c7SWei Liu ret = virtio_pdu_vunmarshal(pdu, offset, fmt, ap); 61*60ce86c7SWei Liu va_end(ap); 62*60ce86c7SWei Liu 63*60ce86c7SWei Liu return ret; 64*60ce86c7SWei Liu } 65*60ce86c7SWei Liu 66*60ce86c7SWei Liu static void pdu_push_and_notify(V9fsPDU *pdu) 67*60ce86c7SWei Liu { 68*60ce86c7SWei Liu virtio_9p_push_and_notify(pdu); 69*60ce86c7SWei Liu } 70*60ce86c7SWei Liu 71*60ce86c7SWei Liu static int omode_to_uflags(int8_t mode) 72*60ce86c7SWei Liu { 73*60ce86c7SWei Liu int ret = 0; 74*60ce86c7SWei Liu 75*60ce86c7SWei Liu switch (mode & 3) { 76*60ce86c7SWei Liu case Oread: 77*60ce86c7SWei Liu ret = O_RDONLY; 78*60ce86c7SWei Liu break; 79*60ce86c7SWei Liu case Ordwr: 80*60ce86c7SWei Liu ret = O_RDWR; 81*60ce86c7SWei Liu break; 82*60ce86c7SWei Liu case Owrite: 83*60ce86c7SWei Liu ret = O_WRONLY; 84*60ce86c7SWei Liu break; 85*60ce86c7SWei Liu case Oexec: 86*60ce86c7SWei Liu ret = O_RDONLY; 87*60ce86c7SWei Liu break; 88*60ce86c7SWei Liu } 89*60ce86c7SWei Liu 90*60ce86c7SWei Liu if (mode & Otrunc) { 91*60ce86c7SWei Liu ret |= O_TRUNC; 92*60ce86c7SWei Liu } 93*60ce86c7SWei Liu 94*60ce86c7SWei Liu if (mode & Oappend) { 95*60ce86c7SWei Liu ret |= O_APPEND; 96*60ce86c7SWei Liu } 97*60ce86c7SWei Liu 98*60ce86c7SWei Liu if (mode & Oexcl) { 99*60ce86c7SWei Liu ret |= O_EXCL; 100*60ce86c7SWei Liu } 101*60ce86c7SWei Liu 102*60ce86c7SWei Liu return ret; 103*60ce86c7SWei Liu } 104*60ce86c7SWei Liu 105*60ce86c7SWei Liu struct dotl_openflag_map { 106*60ce86c7SWei Liu int dotl_flag; 107*60ce86c7SWei Liu int open_flag; 108*60ce86c7SWei Liu }; 109*60ce86c7SWei Liu 110*60ce86c7SWei Liu static int dotl_to_open_flags(int flags) 111*60ce86c7SWei Liu { 112*60ce86c7SWei Liu int i; 113*60ce86c7SWei Liu /* 114*60ce86c7SWei Liu * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY 115*60ce86c7SWei Liu * and P9_DOTL_NOACCESS 116*60ce86c7SWei Liu */ 117*60ce86c7SWei Liu int oflags = flags & O_ACCMODE; 118*60ce86c7SWei Liu 119*60ce86c7SWei Liu struct dotl_openflag_map dotl_oflag_map[] = { 120*60ce86c7SWei Liu { P9_DOTL_CREATE, O_CREAT }, 121*60ce86c7SWei Liu { P9_DOTL_EXCL, O_EXCL }, 122*60ce86c7SWei Liu { P9_DOTL_NOCTTY , O_NOCTTY }, 123*60ce86c7SWei Liu { P9_DOTL_TRUNC, O_TRUNC }, 124*60ce86c7SWei Liu { P9_DOTL_APPEND, O_APPEND }, 125*60ce86c7SWei Liu { P9_DOTL_NONBLOCK, O_NONBLOCK } , 126*60ce86c7SWei Liu { P9_DOTL_DSYNC, O_DSYNC }, 127*60ce86c7SWei Liu { P9_DOTL_FASYNC, FASYNC }, 128*60ce86c7SWei Liu { P9_DOTL_DIRECT, O_DIRECT }, 129*60ce86c7SWei Liu { P9_DOTL_LARGEFILE, O_LARGEFILE }, 130*60ce86c7SWei Liu { P9_DOTL_DIRECTORY, O_DIRECTORY }, 131*60ce86c7SWei Liu { P9_DOTL_NOFOLLOW, O_NOFOLLOW }, 132*60ce86c7SWei Liu { P9_DOTL_NOATIME, O_NOATIME }, 133*60ce86c7SWei Liu { P9_DOTL_SYNC, O_SYNC }, 134*60ce86c7SWei Liu }; 135*60ce86c7SWei Liu 136*60ce86c7SWei Liu for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) { 137*60ce86c7SWei Liu if (flags & dotl_oflag_map[i].dotl_flag) { 138*60ce86c7SWei Liu oflags |= dotl_oflag_map[i].open_flag; 139*60ce86c7SWei Liu } 140*60ce86c7SWei Liu } 141*60ce86c7SWei Liu 142*60ce86c7SWei Liu return oflags; 143*60ce86c7SWei Liu } 144*60ce86c7SWei Liu 145*60ce86c7SWei Liu void cred_init(FsCred *credp) 146*60ce86c7SWei Liu { 147*60ce86c7SWei Liu credp->fc_uid = -1; 148*60ce86c7SWei Liu credp->fc_gid = -1; 149*60ce86c7SWei Liu credp->fc_mode = -1; 150*60ce86c7SWei Liu credp->fc_rdev = -1; 151*60ce86c7SWei Liu } 152*60ce86c7SWei Liu 153*60ce86c7SWei Liu static int get_dotl_openflags(V9fsState *s, int oflags) 154*60ce86c7SWei Liu { 155*60ce86c7SWei Liu int flags; 156*60ce86c7SWei Liu /* 157*60ce86c7SWei Liu * Filter the client open flags 158*60ce86c7SWei Liu */ 159*60ce86c7SWei Liu flags = dotl_to_open_flags(oflags); 160*60ce86c7SWei Liu flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT); 161*60ce86c7SWei Liu /* 162*60ce86c7SWei Liu * Ignore direct disk access hint until the server supports it. 163*60ce86c7SWei Liu */ 164*60ce86c7SWei Liu flags &= ~O_DIRECT; 165*60ce86c7SWei Liu return flags; 166*60ce86c7SWei Liu } 167*60ce86c7SWei Liu 168*60ce86c7SWei Liu void v9fs_path_init(V9fsPath *path) 169*60ce86c7SWei Liu { 170*60ce86c7SWei Liu path->data = NULL; 171*60ce86c7SWei Liu path->size = 0; 172*60ce86c7SWei Liu } 173*60ce86c7SWei Liu 174*60ce86c7SWei Liu void v9fs_path_free(V9fsPath *path) 175*60ce86c7SWei Liu { 176*60ce86c7SWei Liu g_free(path->data); 177*60ce86c7SWei Liu path->data = NULL; 178*60ce86c7SWei Liu path->size = 0; 179*60ce86c7SWei Liu } 180*60ce86c7SWei Liu 181*60ce86c7SWei Liu void v9fs_path_copy(V9fsPath *lhs, V9fsPath *rhs) 182*60ce86c7SWei Liu { 183*60ce86c7SWei Liu v9fs_path_free(lhs); 184*60ce86c7SWei Liu lhs->data = g_malloc(rhs->size); 185*60ce86c7SWei Liu memcpy(lhs->data, rhs->data, rhs->size); 186*60ce86c7SWei Liu lhs->size = rhs->size; 187*60ce86c7SWei Liu } 188*60ce86c7SWei Liu 189*60ce86c7SWei Liu int v9fs_name_to_path(V9fsState *s, V9fsPath *dirpath, 190*60ce86c7SWei Liu const char *name, V9fsPath *path) 191*60ce86c7SWei Liu { 192*60ce86c7SWei Liu int err; 193*60ce86c7SWei Liu err = s->ops->name_to_path(&s->ctx, dirpath, name, path); 194*60ce86c7SWei Liu if (err < 0) { 195*60ce86c7SWei Liu err = -errno; 196*60ce86c7SWei Liu } 197*60ce86c7SWei Liu return err; 198*60ce86c7SWei Liu } 199*60ce86c7SWei Liu 200*60ce86c7SWei Liu /* 201*60ce86c7SWei Liu * Return TRUE if s1 is an ancestor of s2. 202*60ce86c7SWei Liu * 203*60ce86c7SWei Liu * E.g. "a/b" is an ancestor of "a/b/c" but not of "a/bc/d". 204*60ce86c7SWei Liu * As a special case, We treat s1 as ancestor of s2 if they are same! 205*60ce86c7SWei Liu */ 206*60ce86c7SWei Liu static int v9fs_path_is_ancestor(V9fsPath *s1, V9fsPath *s2) 207*60ce86c7SWei Liu { 208*60ce86c7SWei Liu if (!strncmp(s1->data, s2->data, s1->size - 1)) { 209*60ce86c7SWei Liu if (s2->data[s1->size - 1] == '\0' || s2->data[s1->size - 1] == '/') { 210*60ce86c7SWei Liu return 1; 211*60ce86c7SWei Liu } 212*60ce86c7SWei Liu } 213*60ce86c7SWei Liu return 0; 214*60ce86c7SWei Liu } 215*60ce86c7SWei Liu 216*60ce86c7SWei Liu static size_t v9fs_string_size(V9fsString *str) 217*60ce86c7SWei Liu { 218*60ce86c7SWei Liu return str->size; 219*60ce86c7SWei Liu } 220*60ce86c7SWei Liu 221*60ce86c7SWei Liu /* 222*60ce86c7SWei Liu * returns 0 if fid got re-opened, 1 if not, < 0 on error */ 223*60ce86c7SWei Liu static int v9fs_reopen_fid(V9fsPDU *pdu, V9fsFidState *f) 224*60ce86c7SWei Liu { 225*60ce86c7SWei Liu int err = 1; 226*60ce86c7SWei Liu if (f->fid_type == P9_FID_FILE) { 227*60ce86c7SWei Liu if (f->fs.fd == -1) { 228*60ce86c7SWei Liu do { 229*60ce86c7SWei Liu err = v9fs_co_open(pdu, f, f->open_flags); 230*60ce86c7SWei Liu } while (err == -EINTR && !pdu->cancelled); 231*60ce86c7SWei Liu } 232*60ce86c7SWei Liu } else if (f->fid_type == P9_FID_DIR) { 233*60ce86c7SWei Liu if (f->fs.dir == NULL) { 234*60ce86c7SWei Liu do { 235*60ce86c7SWei Liu err = v9fs_co_opendir(pdu, f); 236*60ce86c7SWei Liu } while (err == -EINTR && !pdu->cancelled); 237*60ce86c7SWei Liu } 238*60ce86c7SWei Liu } 239*60ce86c7SWei Liu return err; 240*60ce86c7SWei Liu } 241*60ce86c7SWei Liu 242*60ce86c7SWei Liu static V9fsFidState *get_fid(V9fsPDU *pdu, int32_t fid) 243*60ce86c7SWei Liu { 244*60ce86c7SWei Liu int err; 245*60ce86c7SWei Liu V9fsFidState *f; 246*60ce86c7SWei Liu V9fsState *s = pdu->s; 247*60ce86c7SWei Liu 248*60ce86c7SWei Liu for (f = s->fid_list; f; f = f->next) { 249*60ce86c7SWei Liu BUG_ON(f->clunked); 250*60ce86c7SWei Liu if (f->fid == fid) { 251*60ce86c7SWei Liu /* 252*60ce86c7SWei Liu * Update the fid ref upfront so that 253*60ce86c7SWei Liu * we don't get reclaimed when we yield 254*60ce86c7SWei Liu * in open later. 255*60ce86c7SWei Liu */ 256*60ce86c7SWei Liu f->ref++; 257*60ce86c7SWei Liu /* 258*60ce86c7SWei Liu * check whether we need to reopen the 259*60ce86c7SWei Liu * file. We might have closed the fd 260*60ce86c7SWei Liu * while trying to free up some file 261*60ce86c7SWei Liu * descriptors. 262*60ce86c7SWei Liu */ 263*60ce86c7SWei Liu err = v9fs_reopen_fid(pdu, f); 264*60ce86c7SWei Liu if (err < 0) { 265*60ce86c7SWei Liu f->ref--; 266*60ce86c7SWei Liu return NULL; 267*60ce86c7SWei Liu } 268*60ce86c7SWei Liu /* 269*60ce86c7SWei Liu * Mark the fid as referenced so that the LRU 270*60ce86c7SWei Liu * reclaim won't close the file descriptor 271*60ce86c7SWei Liu */ 272*60ce86c7SWei Liu f->flags |= FID_REFERENCED; 273*60ce86c7SWei Liu return f; 274*60ce86c7SWei Liu } 275*60ce86c7SWei Liu } 276*60ce86c7SWei Liu return NULL; 277*60ce86c7SWei Liu } 278*60ce86c7SWei Liu 279*60ce86c7SWei Liu static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid) 280*60ce86c7SWei Liu { 281*60ce86c7SWei Liu V9fsFidState *f; 282*60ce86c7SWei Liu 283*60ce86c7SWei Liu for (f = s->fid_list; f; f = f->next) { 284*60ce86c7SWei Liu /* If fid is already there return NULL */ 285*60ce86c7SWei Liu BUG_ON(f->clunked); 286*60ce86c7SWei Liu if (f->fid == fid) { 287*60ce86c7SWei Liu return NULL; 288*60ce86c7SWei Liu } 289*60ce86c7SWei Liu } 290*60ce86c7SWei Liu f = g_malloc0(sizeof(V9fsFidState)); 291*60ce86c7SWei Liu f->fid = fid; 292*60ce86c7SWei Liu f->fid_type = P9_FID_NONE; 293*60ce86c7SWei Liu f->ref = 1; 294*60ce86c7SWei Liu /* 295*60ce86c7SWei Liu * Mark the fid as referenced so that the LRU 296*60ce86c7SWei Liu * reclaim won't close the file descriptor 297*60ce86c7SWei Liu */ 298*60ce86c7SWei Liu f->flags |= FID_REFERENCED; 299*60ce86c7SWei Liu f->next = s->fid_list; 300*60ce86c7SWei Liu s->fid_list = f; 301*60ce86c7SWei Liu 302*60ce86c7SWei Liu return f; 303*60ce86c7SWei Liu } 304*60ce86c7SWei Liu 305*60ce86c7SWei Liu static int v9fs_xattr_fid_clunk(V9fsPDU *pdu, V9fsFidState *fidp) 306*60ce86c7SWei Liu { 307*60ce86c7SWei Liu int retval = 0; 308*60ce86c7SWei Liu 309*60ce86c7SWei Liu if (fidp->fs.xattr.copied_len == -1) { 310*60ce86c7SWei Liu /* getxattr/listxattr fid */ 311*60ce86c7SWei Liu goto free_value; 312*60ce86c7SWei Liu } 313*60ce86c7SWei Liu /* 314*60ce86c7SWei Liu * if this is fid for setxattr. clunk should 315*60ce86c7SWei Liu * result in setxattr localcall 316*60ce86c7SWei Liu */ 317*60ce86c7SWei Liu if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) { 318*60ce86c7SWei Liu /* clunk after partial write */ 319*60ce86c7SWei Liu retval = -EINVAL; 320*60ce86c7SWei Liu goto free_out; 321*60ce86c7SWei Liu } 322*60ce86c7SWei Liu if (fidp->fs.xattr.len) { 323*60ce86c7SWei Liu retval = v9fs_co_lsetxattr(pdu, &fidp->path, &fidp->fs.xattr.name, 324*60ce86c7SWei Liu fidp->fs.xattr.value, 325*60ce86c7SWei Liu fidp->fs.xattr.len, 326*60ce86c7SWei Liu fidp->fs.xattr.flags); 327*60ce86c7SWei Liu } else { 328*60ce86c7SWei Liu retval = v9fs_co_lremovexattr(pdu, &fidp->path, &fidp->fs.xattr.name); 329*60ce86c7SWei Liu } 330*60ce86c7SWei Liu free_out: 331*60ce86c7SWei Liu v9fs_string_free(&fidp->fs.xattr.name); 332*60ce86c7SWei Liu free_value: 333*60ce86c7SWei Liu g_free(fidp->fs.xattr.value); 334*60ce86c7SWei Liu return retval; 335*60ce86c7SWei Liu } 336*60ce86c7SWei Liu 337*60ce86c7SWei Liu static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp) 338*60ce86c7SWei Liu { 339*60ce86c7SWei Liu int retval = 0; 340*60ce86c7SWei Liu 341*60ce86c7SWei Liu if (fidp->fid_type == P9_FID_FILE) { 342*60ce86c7SWei Liu /* If we reclaimed the fd no need to close */ 343*60ce86c7SWei Liu if (fidp->fs.fd != -1) { 344*60ce86c7SWei Liu retval = v9fs_co_close(pdu, &fidp->fs); 345*60ce86c7SWei Liu } 346*60ce86c7SWei Liu } else if (fidp->fid_type == P9_FID_DIR) { 347*60ce86c7SWei Liu if (fidp->fs.dir != NULL) { 348*60ce86c7SWei Liu retval = v9fs_co_closedir(pdu, &fidp->fs); 349*60ce86c7SWei Liu } 350*60ce86c7SWei Liu } else if (fidp->fid_type == P9_FID_XATTR) { 351*60ce86c7SWei Liu retval = v9fs_xattr_fid_clunk(pdu, fidp); 352*60ce86c7SWei Liu } 353*60ce86c7SWei Liu v9fs_path_free(&fidp->path); 354*60ce86c7SWei Liu g_free(fidp); 355*60ce86c7SWei Liu return retval; 356*60ce86c7SWei Liu } 357*60ce86c7SWei Liu 358*60ce86c7SWei Liu static int put_fid(V9fsPDU *pdu, V9fsFidState *fidp) 359*60ce86c7SWei Liu { 360*60ce86c7SWei Liu BUG_ON(!fidp->ref); 361*60ce86c7SWei Liu fidp->ref--; 362*60ce86c7SWei Liu /* 363*60ce86c7SWei Liu * Don't free the fid if it is in reclaim list 364*60ce86c7SWei Liu */ 365*60ce86c7SWei Liu if (!fidp->ref && fidp->clunked) { 366*60ce86c7SWei Liu if (fidp->fid == pdu->s->root_fid) { 367*60ce86c7SWei Liu /* 368*60ce86c7SWei Liu * if the clunked fid is root fid then we 369*60ce86c7SWei Liu * have unmounted the fs on the client side. 370*60ce86c7SWei Liu * delete the migration blocker. Ideally, this 371*60ce86c7SWei Liu * should be hooked to transport close notification 372*60ce86c7SWei Liu */ 373*60ce86c7SWei Liu if (pdu->s->migration_blocker) { 374*60ce86c7SWei Liu migrate_del_blocker(pdu->s->migration_blocker); 375*60ce86c7SWei Liu error_free(pdu->s->migration_blocker); 376*60ce86c7SWei Liu pdu->s->migration_blocker = NULL; 377*60ce86c7SWei Liu } 378*60ce86c7SWei Liu } 379*60ce86c7SWei Liu return free_fid(pdu, fidp); 380*60ce86c7SWei Liu } 381*60ce86c7SWei Liu return 0; 382*60ce86c7SWei Liu } 383*60ce86c7SWei Liu 384*60ce86c7SWei Liu static V9fsFidState *clunk_fid(V9fsState *s, int32_t fid) 385*60ce86c7SWei Liu { 386*60ce86c7SWei Liu V9fsFidState **fidpp, *fidp; 387*60ce86c7SWei Liu 388*60ce86c7SWei Liu for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) { 389*60ce86c7SWei Liu if ((*fidpp)->fid == fid) { 390*60ce86c7SWei Liu break; 391*60ce86c7SWei Liu } 392*60ce86c7SWei Liu } 393*60ce86c7SWei Liu if (*fidpp == NULL) { 394*60ce86c7SWei Liu return NULL; 395*60ce86c7SWei Liu } 396*60ce86c7SWei Liu fidp = *fidpp; 397*60ce86c7SWei Liu *fidpp = fidp->next; 398*60ce86c7SWei Liu fidp->clunked = 1; 399*60ce86c7SWei Liu return fidp; 400*60ce86c7SWei Liu } 401*60ce86c7SWei Liu 402*60ce86c7SWei Liu void v9fs_reclaim_fd(V9fsPDU *pdu) 403*60ce86c7SWei Liu { 404*60ce86c7SWei Liu int reclaim_count = 0; 405*60ce86c7SWei Liu V9fsState *s = pdu->s; 406*60ce86c7SWei Liu V9fsFidState *f, *reclaim_list = NULL; 407*60ce86c7SWei Liu 408*60ce86c7SWei Liu for (f = s->fid_list; f; f = f->next) { 409*60ce86c7SWei Liu /* 410*60ce86c7SWei Liu * Unlink fids cannot be reclaimed. Check 411*60ce86c7SWei Liu * for them and skip them. Also skip fids 412*60ce86c7SWei Liu * currently being operated on. 413*60ce86c7SWei Liu */ 414*60ce86c7SWei Liu if (f->ref || f->flags & FID_NON_RECLAIMABLE) { 415*60ce86c7SWei Liu continue; 416*60ce86c7SWei Liu } 417*60ce86c7SWei Liu /* 418*60ce86c7SWei Liu * if it is a recently referenced fid 419*60ce86c7SWei Liu * we leave the fid untouched and clear the 420*60ce86c7SWei Liu * reference bit. We come back to it later 421*60ce86c7SWei Liu * in the next iteration. (a simple LRU without 422*60ce86c7SWei Liu * moving list elements around) 423*60ce86c7SWei Liu */ 424*60ce86c7SWei Liu if (f->flags & FID_REFERENCED) { 425*60ce86c7SWei Liu f->flags &= ~FID_REFERENCED; 426*60ce86c7SWei Liu continue; 427*60ce86c7SWei Liu } 428*60ce86c7SWei Liu /* 429*60ce86c7SWei Liu * Add fids to reclaim list. 430*60ce86c7SWei Liu */ 431*60ce86c7SWei Liu if (f->fid_type == P9_FID_FILE) { 432*60ce86c7SWei Liu if (f->fs.fd != -1) { 433*60ce86c7SWei Liu /* 434*60ce86c7SWei Liu * Up the reference count so that 435*60ce86c7SWei Liu * a clunk request won't free this fid 436*60ce86c7SWei Liu */ 437*60ce86c7SWei Liu f->ref++; 438*60ce86c7SWei Liu f->rclm_lst = reclaim_list; 439*60ce86c7SWei Liu reclaim_list = f; 440*60ce86c7SWei Liu f->fs_reclaim.fd = f->fs.fd; 441*60ce86c7SWei Liu f->fs.fd = -1; 442*60ce86c7SWei Liu reclaim_count++; 443*60ce86c7SWei Liu } 444*60ce86c7SWei Liu } else if (f->fid_type == P9_FID_DIR) { 445*60ce86c7SWei Liu if (f->fs.dir != NULL) { 446*60ce86c7SWei Liu /* 447*60ce86c7SWei Liu * Up the reference count so that 448*60ce86c7SWei Liu * a clunk request won't free this fid 449*60ce86c7SWei Liu */ 450*60ce86c7SWei Liu f->ref++; 451*60ce86c7SWei Liu f->rclm_lst = reclaim_list; 452*60ce86c7SWei Liu reclaim_list = f; 453*60ce86c7SWei Liu f->fs_reclaim.dir = f->fs.dir; 454*60ce86c7SWei Liu f->fs.dir = NULL; 455*60ce86c7SWei Liu reclaim_count++; 456*60ce86c7SWei Liu } 457*60ce86c7SWei Liu } 458*60ce86c7SWei Liu if (reclaim_count >= open_fd_rc) { 459*60ce86c7SWei Liu break; 460*60ce86c7SWei Liu } 461*60ce86c7SWei Liu } 462*60ce86c7SWei Liu /* 463*60ce86c7SWei Liu * Now close the fid in reclaim list. Free them if they 464*60ce86c7SWei Liu * are already clunked. 465*60ce86c7SWei Liu */ 466*60ce86c7SWei Liu while (reclaim_list) { 467*60ce86c7SWei Liu f = reclaim_list; 468*60ce86c7SWei Liu reclaim_list = f->rclm_lst; 469*60ce86c7SWei Liu if (f->fid_type == P9_FID_FILE) { 470*60ce86c7SWei Liu v9fs_co_close(pdu, &f->fs_reclaim); 471*60ce86c7SWei Liu } else if (f->fid_type == P9_FID_DIR) { 472*60ce86c7SWei Liu v9fs_co_closedir(pdu, &f->fs_reclaim); 473*60ce86c7SWei Liu } 474*60ce86c7SWei Liu f->rclm_lst = NULL; 475*60ce86c7SWei Liu /* 476*60ce86c7SWei Liu * Now drop the fid reference, free it 477*60ce86c7SWei Liu * if clunked. 478*60ce86c7SWei Liu */ 479*60ce86c7SWei Liu put_fid(pdu, f); 480*60ce86c7SWei Liu } 481*60ce86c7SWei Liu } 482*60ce86c7SWei Liu 483*60ce86c7SWei Liu static int v9fs_mark_fids_unreclaim(V9fsPDU *pdu, V9fsPath *path) 484*60ce86c7SWei Liu { 485*60ce86c7SWei Liu int err; 486*60ce86c7SWei Liu V9fsState *s = pdu->s; 487*60ce86c7SWei Liu V9fsFidState *fidp, head_fid; 488*60ce86c7SWei Liu 489*60ce86c7SWei Liu head_fid.next = s->fid_list; 490*60ce86c7SWei Liu for (fidp = s->fid_list; fidp; fidp = fidp->next) { 491*60ce86c7SWei Liu if (fidp->path.size != path->size) { 492*60ce86c7SWei Liu continue; 493*60ce86c7SWei Liu } 494*60ce86c7SWei Liu if (!memcmp(fidp->path.data, path->data, path->size)) { 495*60ce86c7SWei Liu /* Mark the fid non reclaimable. */ 496*60ce86c7SWei Liu fidp->flags |= FID_NON_RECLAIMABLE; 497*60ce86c7SWei Liu 498*60ce86c7SWei Liu /* reopen the file/dir if already closed */ 499*60ce86c7SWei Liu err = v9fs_reopen_fid(pdu, fidp); 500*60ce86c7SWei Liu if (err < 0) { 501*60ce86c7SWei Liu return -1; 502*60ce86c7SWei Liu } 503*60ce86c7SWei Liu /* 504*60ce86c7SWei Liu * Go back to head of fid list because 505*60ce86c7SWei Liu * the list could have got updated when 506*60ce86c7SWei Liu * switched to the worker thread 507*60ce86c7SWei Liu */ 508*60ce86c7SWei Liu if (err == 0) { 509*60ce86c7SWei Liu fidp = &head_fid; 510*60ce86c7SWei Liu } 511*60ce86c7SWei Liu } 512*60ce86c7SWei Liu } 513*60ce86c7SWei Liu return 0; 514*60ce86c7SWei Liu } 515*60ce86c7SWei Liu 516*60ce86c7SWei Liu static void virtfs_reset(V9fsPDU *pdu) 517*60ce86c7SWei Liu { 518*60ce86c7SWei Liu V9fsState *s = pdu->s; 519*60ce86c7SWei Liu V9fsFidState *fidp = NULL; 520*60ce86c7SWei Liu 521*60ce86c7SWei Liu /* Free all fids */ 522*60ce86c7SWei Liu while (s->fid_list) { 523*60ce86c7SWei Liu fidp = s->fid_list; 524*60ce86c7SWei Liu s->fid_list = fidp->next; 525*60ce86c7SWei Liu 526*60ce86c7SWei Liu if (fidp->ref) { 527*60ce86c7SWei Liu fidp->clunked = 1; 528*60ce86c7SWei Liu } else { 529*60ce86c7SWei Liu free_fid(pdu, fidp); 530*60ce86c7SWei Liu } 531*60ce86c7SWei Liu } 532*60ce86c7SWei Liu if (fidp) { 533*60ce86c7SWei Liu /* One or more unclunked fids found... */ 534*60ce86c7SWei Liu error_report("9pfs:%s: One or more uncluncked fids " 535*60ce86c7SWei Liu "found during reset", __func__); 536*60ce86c7SWei Liu } 537*60ce86c7SWei Liu } 538*60ce86c7SWei Liu 539*60ce86c7SWei Liu #define P9_QID_TYPE_DIR 0x80 540*60ce86c7SWei Liu #define P9_QID_TYPE_SYMLINK 0x02 541*60ce86c7SWei Liu 542*60ce86c7SWei Liu #define P9_STAT_MODE_DIR 0x80000000 543*60ce86c7SWei Liu #define P9_STAT_MODE_APPEND 0x40000000 544*60ce86c7SWei Liu #define P9_STAT_MODE_EXCL 0x20000000 545*60ce86c7SWei Liu #define P9_STAT_MODE_MOUNT 0x10000000 546*60ce86c7SWei Liu #define P9_STAT_MODE_AUTH 0x08000000 547*60ce86c7SWei Liu #define P9_STAT_MODE_TMP 0x04000000 548*60ce86c7SWei Liu #define P9_STAT_MODE_SYMLINK 0x02000000 549*60ce86c7SWei Liu #define P9_STAT_MODE_LINK 0x01000000 550*60ce86c7SWei Liu #define P9_STAT_MODE_DEVICE 0x00800000 551*60ce86c7SWei Liu #define P9_STAT_MODE_NAMED_PIPE 0x00200000 552*60ce86c7SWei Liu #define P9_STAT_MODE_SOCKET 0x00100000 553*60ce86c7SWei Liu #define P9_STAT_MODE_SETUID 0x00080000 554*60ce86c7SWei Liu #define P9_STAT_MODE_SETGID 0x00040000 555*60ce86c7SWei Liu #define P9_STAT_MODE_SETVTX 0x00010000 556*60ce86c7SWei Liu 557*60ce86c7SWei Liu #define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR | \ 558*60ce86c7SWei Liu P9_STAT_MODE_SYMLINK | \ 559*60ce86c7SWei Liu P9_STAT_MODE_LINK | \ 560*60ce86c7SWei Liu P9_STAT_MODE_DEVICE | \ 561*60ce86c7SWei Liu P9_STAT_MODE_NAMED_PIPE | \ 562*60ce86c7SWei Liu P9_STAT_MODE_SOCKET) 563*60ce86c7SWei Liu 564*60ce86c7SWei Liu /* This is the algorithm from ufs in spfs */ 565*60ce86c7SWei Liu static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp) 566*60ce86c7SWei Liu { 567*60ce86c7SWei Liu size_t size; 568*60ce86c7SWei Liu 569*60ce86c7SWei Liu memset(&qidp->path, 0, sizeof(qidp->path)); 570*60ce86c7SWei Liu size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path)); 571*60ce86c7SWei Liu memcpy(&qidp->path, &stbuf->st_ino, size); 572*60ce86c7SWei Liu qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8); 573*60ce86c7SWei Liu qidp->type = 0; 574*60ce86c7SWei Liu if (S_ISDIR(stbuf->st_mode)) { 575*60ce86c7SWei Liu qidp->type |= P9_QID_TYPE_DIR; 576*60ce86c7SWei Liu } 577*60ce86c7SWei Liu if (S_ISLNK(stbuf->st_mode)) { 578*60ce86c7SWei Liu qidp->type |= P9_QID_TYPE_SYMLINK; 579*60ce86c7SWei Liu } 580*60ce86c7SWei Liu } 581*60ce86c7SWei Liu 582*60ce86c7SWei Liu static int fid_to_qid(V9fsPDU *pdu, V9fsFidState *fidp, V9fsQID *qidp) 583*60ce86c7SWei Liu { 584*60ce86c7SWei Liu struct stat stbuf; 585*60ce86c7SWei Liu int err; 586*60ce86c7SWei Liu 587*60ce86c7SWei Liu err = v9fs_co_lstat(pdu, &fidp->path, &stbuf); 588*60ce86c7SWei Liu if (err < 0) { 589*60ce86c7SWei Liu return err; 590*60ce86c7SWei Liu } 591*60ce86c7SWei Liu stat_to_qid(&stbuf, qidp); 592*60ce86c7SWei Liu return 0; 593*60ce86c7SWei Liu } 594*60ce86c7SWei Liu 595*60ce86c7SWei Liu V9fsPDU *pdu_alloc(V9fsState *s) 596*60ce86c7SWei Liu { 597*60ce86c7SWei Liu V9fsPDU *pdu = NULL; 598*60ce86c7SWei Liu 599*60ce86c7SWei Liu if (!QLIST_EMPTY(&s->free_list)) { 600*60ce86c7SWei Liu pdu = QLIST_FIRST(&s->free_list); 601*60ce86c7SWei Liu QLIST_REMOVE(pdu, next); 602*60ce86c7SWei Liu QLIST_INSERT_HEAD(&s->active_list, pdu, next); 603*60ce86c7SWei Liu } 604*60ce86c7SWei Liu return pdu; 605*60ce86c7SWei Liu } 606*60ce86c7SWei Liu 607*60ce86c7SWei Liu void pdu_free(V9fsPDU *pdu) 608*60ce86c7SWei Liu { 609*60ce86c7SWei Liu if (pdu) { 610*60ce86c7SWei Liu V9fsState *s = pdu->s; 611*60ce86c7SWei Liu /* 612*60ce86c7SWei Liu * Cancelled pdu are added back to the freelist 613*60ce86c7SWei Liu * by flush request . 614*60ce86c7SWei Liu */ 615*60ce86c7SWei Liu if (!pdu->cancelled) { 616*60ce86c7SWei Liu QLIST_REMOVE(pdu, next); 617*60ce86c7SWei Liu QLIST_INSERT_HEAD(&s->free_list, pdu, next); 618*60ce86c7SWei Liu } 619*60ce86c7SWei Liu } 620*60ce86c7SWei Liu } 621*60ce86c7SWei Liu 622*60ce86c7SWei Liu /* 623*60ce86c7SWei Liu * We don't do error checking for pdu_marshal/unmarshal here 624*60ce86c7SWei Liu * because we always expect to have enough space to encode 625*60ce86c7SWei Liu * error details 626*60ce86c7SWei Liu */ 627*60ce86c7SWei Liu static void pdu_complete(V9fsPDU *pdu, ssize_t len) 628*60ce86c7SWei Liu { 629*60ce86c7SWei Liu int8_t id = pdu->id + 1; /* Response */ 630*60ce86c7SWei Liu V9fsState *s = pdu->s; 631*60ce86c7SWei Liu 632*60ce86c7SWei Liu if (len < 0) { 633*60ce86c7SWei Liu int err = -len; 634*60ce86c7SWei Liu len = 7; 635*60ce86c7SWei Liu 636*60ce86c7SWei Liu if (s->proto_version != V9FS_PROTO_2000L) { 637*60ce86c7SWei Liu V9fsString str; 638*60ce86c7SWei Liu 639*60ce86c7SWei Liu str.data = strerror(err); 640*60ce86c7SWei Liu str.size = strlen(str.data); 641*60ce86c7SWei Liu 642*60ce86c7SWei Liu len += pdu_marshal(pdu, len, "s", &str); 643*60ce86c7SWei Liu id = P9_RERROR; 644*60ce86c7SWei Liu } 645*60ce86c7SWei Liu 646*60ce86c7SWei Liu len += pdu_marshal(pdu, len, "d", err); 647*60ce86c7SWei Liu 648*60ce86c7SWei Liu if (s->proto_version == V9FS_PROTO_2000L) { 649*60ce86c7SWei Liu id = P9_RLERROR; 650*60ce86c7SWei Liu } 651*60ce86c7SWei Liu trace_v9fs_rerror(pdu->tag, pdu->id, err); /* Trace ERROR */ 652*60ce86c7SWei Liu } 653*60ce86c7SWei Liu 654*60ce86c7SWei Liu /* fill out the header */ 655*60ce86c7SWei Liu pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag); 656*60ce86c7SWei Liu 657*60ce86c7SWei Liu /* keep these in sync */ 658*60ce86c7SWei Liu pdu->size = len; 659*60ce86c7SWei Liu pdu->id = id; 660*60ce86c7SWei Liu 661*60ce86c7SWei Liu pdu_push_and_notify(pdu); 662*60ce86c7SWei Liu 663*60ce86c7SWei Liu /* Now wakeup anybody waiting in flush for this request */ 664*60ce86c7SWei Liu qemu_co_queue_next(&pdu->complete); 665*60ce86c7SWei Liu 666*60ce86c7SWei Liu pdu_free(pdu); 667*60ce86c7SWei Liu } 668*60ce86c7SWei Liu 669*60ce86c7SWei Liu static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension) 670*60ce86c7SWei Liu { 671*60ce86c7SWei Liu mode_t ret; 672*60ce86c7SWei Liu 673*60ce86c7SWei Liu ret = mode & 0777; 674*60ce86c7SWei Liu if (mode & P9_STAT_MODE_DIR) { 675*60ce86c7SWei Liu ret |= S_IFDIR; 676*60ce86c7SWei Liu } 677*60ce86c7SWei Liu 678*60ce86c7SWei Liu if (mode & P9_STAT_MODE_SYMLINK) { 679*60ce86c7SWei Liu ret |= S_IFLNK; 680*60ce86c7SWei Liu } 681*60ce86c7SWei Liu if (mode & P9_STAT_MODE_SOCKET) { 682*60ce86c7SWei Liu ret |= S_IFSOCK; 683*60ce86c7SWei Liu } 684*60ce86c7SWei Liu if (mode & P9_STAT_MODE_NAMED_PIPE) { 685*60ce86c7SWei Liu ret |= S_IFIFO; 686*60ce86c7SWei Liu } 687*60ce86c7SWei Liu if (mode & P9_STAT_MODE_DEVICE) { 688*60ce86c7SWei Liu if (extension->size && extension->data[0] == 'c') { 689*60ce86c7SWei Liu ret |= S_IFCHR; 690*60ce86c7SWei Liu } else { 691*60ce86c7SWei Liu ret |= S_IFBLK; 692*60ce86c7SWei Liu } 693*60ce86c7SWei Liu } 694*60ce86c7SWei Liu 695*60ce86c7SWei Liu if (!(ret&~0777)) { 696*60ce86c7SWei Liu ret |= S_IFREG; 697*60ce86c7SWei Liu } 698*60ce86c7SWei Liu 699*60ce86c7SWei Liu if (mode & P9_STAT_MODE_SETUID) { 700*60ce86c7SWei Liu ret |= S_ISUID; 701*60ce86c7SWei Liu } 702*60ce86c7SWei Liu if (mode & P9_STAT_MODE_SETGID) { 703*60ce86c7SWei Liu ret |= S_ISGID; 704*60ce86c7SWei Liu } 705*60ce86c7SWei Liu if (mode & P9_STAT_MODE_SETVTX) { 706*60ce86c7SWei Liu ret |= S_ISVTX; 707*60ce86c7SWei Liu } 708*60ce86c7SWei Liu 709*60ce86c7SWei Liu return ret; 710*60ce86c7SWei Liu } 711*60ce86c7SWei Liu 712*60ce86c7SWei Liu static int donttouch_stat(V9fsStat *stat) 713*60ce86c7SWei Liu { 714*60ce86c7SWei Liu if (stat->type == -1 && 715*60ce86c7SWei Liu stat->dev == -1 && 716*60ce86c7SWei Liu stat->qid.type == -1 && 717*60ce86c7SWei Liu stat->qid.version == -1 && 718*60ce86c7SWei Liu stat->qid.path == -1 && 719*60ce86c7SWei Liu stat->mode == -1 && 720*60ce86c7SWei Liu stat->atime == -1 && 721*60ce86c7SWei Liu stat->mtime == -1 && 722*60ce86c7SWei Liu stat->length == -1 && 723*60ce86c7SWei Liu !stat->name.size && 724*60ce86c7SWei Liu !stat->uid.size && 725*60ce86c7SWei Liu !stat->gid.size && 726*60ce86c7SWei Liu !stat->muid.size && 727*60ce86c7SWei Liu stat->n_uid == -1 && 728*60ce86c7SWei Liu stat->n_gid == -1 && 729*60ce86c7SWei Liu stat->n_muid == -1) { 730*60ce86c7SWei Liu return 1; 731*60ce86c7SWei Liu } 732*60ce86c7SWei Liu 733*60ce86c7SWei Liu return 0; 734*60ce86c7SWei Liu } 735*60ce86c7SWei Liu 736*60ce86c7SWei Liu static void v9fs_stat_init(V9fsStat *stat) 737*60ce86c7SWei Liu { 738*60ce86c7SWei Liu v9fs_string_init(&stat->name); 739*60ce86c7SWei Liu v9fs_string_init(&stat->uid); 740*60ce86c7SWei Liu v9fs_string_init(&stat->gid); 741*60ce86c7SWei Liu v9fs_string_init(&stat->muid); 742*60ce86c7SWei Liu v9fs_string_init(&stat->extension); 743*60ce86c7SWei Liu } 744*60ce86c7SWei Liu 745*60ce86c7SWei Liu static void v9fs_stat_free(V9fsStat *stat) 746*60ce86c7SWei Liu { 747*60ce86c7SWei Liu v9fs_string_free(&stat->name); 748*60ce86c7SWei Liu v9fs_string_free(&stat->uid); 749*60ce86c7SWei Liu v9fs_string_free(&stat->gid); 750*60ce86c7SWei Liu v9fs_string_free(&stat->muid); 751*60ce86c7SWei Liu v9fs_string_free(&stat->extension); 752*60ce86c7SWei Liu } 753*60ce86c7SWei Liu 754*60ce86c7SWei Liu static uint32_t stat_to_v9mode(const struct stat *stbuf) 755*60ce86c7SWei Liu { 756*60ce86c7SWei Liu uint32_t mode; 757*60ce86c7SWei Liu 758*60ce86c7SWei Liu mode = stbuf->st_mode & 0777; 759*60ce86c7SWei Liu if (S_ISDIR(stbuf->st_mode)) { 760*60ce86c7SWei Liu mode |= P9_STAT_MODE_DIR; 761*60ce86c7SWei Liu } 762*60ce86c7SWei Liu 763*60ce86c7SWei Liu if (S_ISLNK(stbuf->st_mode)) { 764*60ce86c7SWei Liu mode |= P9_STAT_MODE_SYMLINK; 765*60ce86c7SWei Liu } 766*60ce86c7SWei Liu 767*60ce86c7SWei Liu if (S_ISSOCK(stbuf->st_mode)) { 768*60ce86c7SWei Liu mode |= P9_STAT_MODE_SOCKET; 769*60ce86c7SWei Liu } 770*60ce86c7SWei Liu 771*60ce86c7SWei Liu if (S_ISFIFO(stbuf->st_mode)) { 772*60ce86c7SWei Liu mode |= P9_STAT_MODE_NAMED_PIPE; 773*60ce86c7SWei Liu } 774*60ce86c7SWei Liu 775*60ce86c7SWei Liu if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) { 776*60ce86c7SWei Liu mode |= P9_STAT_MODE_DEVICE; 777*60ce86c7SWei Liu } 778*60ce86c7SWei Liu 779*60ce86c7SWei Liu if (stbuf->st_mode & S_ISUID) { 780*60ce86c7SWei Liu mode |= P9_STAT_MODE_SETUID; 781*60ce86c7SWei Liu } 782*60ce86c7SWei Liu 783*60ce86c7SWei Liu if (stbuf->st_mode & S_ISGID) { 784*60ce86c7SWei Liu mode |= P9_STAT_MODE_SETGID; 785*60ce86c7SWei Liu } 786*60ce86c7SWei Liu 787*60ce86c7SWei Liu if (stbuf->st_mode & S_ISVTX) { 788*60ce86c7SWei Liu mode |= P9_STAT_MODE_SETVTX; 789*60ce86c7SWei Liu } 790*60ce86c7SWei Liu 791*60ce86c7SWei Liu return mode; 792*60ce86c7SWei Liu } 793*60ce86c7SWei Liu 794*60ce86c7SWei Liu static int stat_to_v9stat(V9fsPDU *pdu, V9fsPath *name, 795*60ce86c7SWei Liu const struct stat *stbuf, 796*60ce86c7SWei Liu V9fsStat *v9stat) 797*60ce86c7SWei Liu { 798*60ce86c7SWei Liu int err; 799*60ce86c7SWei Liu const char *str; 800*60ce86c7SWei Liu 801*60ce86c7SWei Liu memset(v9stat, 0, sizeof(*v9stat)); 802*60ce86c7SWei Liu 803*60ce86c7SWei Liu stat_to_qid(stbuf, &v9stat->qid); 804*60ce86c7SWei Liu v9stat->mode = stat_to_v9mode(stbuf); 805*60ce86c7SWei Liu v9stat->atime = stbuf->st_atime; 806*60ce86c7SWei Liu v9stat->mtime = stbuf->st_mtime; 807*60ce86c7SWei Liu v9stat->length = stbuf->st_size; 808*60ce86c7SWei Liu 809*60ce86c7SWei Liu v9fs_string_null(&v9stat->uid); 810*60ce86c7SWei Liu v9fs_string_null(&v9stat->gid); 811*60ce86c7SWei Liu v9fs_string_null(&v9stat->muid); 812*60ce86c7SWei Liu 813*60ce86c7SWei Liu v9stat->n_uid = stbuf->st_uid; 814*60ce86c7SWei Liu v9stat->n_gid = stbuf->st_gid; 815*60ce86c7SWei Liu v9stat->n_muid = 0; 816*60ce86c7SWei Liu 817*60ce86c7SWei Liu v9fs_string_null(&v9stat->extension); 818*60ce86c7SWei Liu 819*60ce86c7SWei Liu if (v9stat->mode & P9_STAT_MODE_SYMLINK) { 820*60ce86c7SWei Liu err = v9fs_co_readlink(pdu, name, &v9stat->extension); 821*60ce86c7SWei Liu if (err < 0) { 822*60ce86c7SWei Liu return err; 823*60ce86c7SWei Liu } 824*60ce86c7SWei Liu } else if (v9stat->mode & P9_STAT_MODE_DEVICE) { 825*60ce86c7SWei Liu v9fs_string_sprintf(&v9stat->extension, "%c %u %u", 826*60ce86c7SWei Liu S_ISCHR(stbuf->st_mode) ? 'c' : 'b', 827*60ce86c7SWei Liu major(stbuf->st_rdev), minor(stbuf->st_rdev)); 828*60ce86c7SWei Liu } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) { 829*60ce86c7SWei Liu v9fs_string_sprintf(&v9stat->extension, "%s %lu", 830*60ce86c7SWei Liu "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink); 831*60ce86c7SWei Liu } 832*60ce86c7SWei Liu 833*60ce86c7SWei Liu str = strrchr(name->data, '/'); 834*60ce86c7SWei Liu if (str) { 835*60ce86c7SWei Liu str += 1; 836*60ce86c7SWei Liu } else { 837*60ce86c7SWei Liu str = name->data; 838*60ce86c7SWei Liu } 839*60ce86c7SWei Liu 840*60ce86c7SWei Liu v9fs_string_sprintf(&v9stat->name, "%s", str); 841*60ce86c7SWei Liu 842*60ce86c7SWei Liu v9stat->size = 61 + 843*60ce86c7SWei Liu v9fs_string_size(&v9stat->name) + 844*60ce86c7SWei Liu v9fs_string_size(&v9stat->uid) + 845*60ce86c7SWei Liu v9fs_string_size(&v9stat->gid) + 846*60ce86c7SWei Liu v9fs_string_size(&v9stat->muid) + 847*60ce86c7SWei Liu v9fs_string_size(&v9stat->extension); 848*60ce86c7SWei Liu return 0; 849*60ce86c7SWei Liu } 850*60ce86c7SWei Liu 851*60ce86c7SWei Liu #define P9_STATS_MODE 0x00000001ULL 852*60ce86c7SWei Liu #define P9_STATS_NLINK 0x00000002ULL 853*60ce86c7SWei Liu #define P9_STATS_UID 0x00000004ULL 854*60ce86c7SWei Liu #define P9_STATS_GID 0x00000008ULL 855*60ce86c7SWei Liu #define P9_STATS_RDEV 0x00000010ULL 856*60ce86c7SWei Liu #define P9_STATS_ATIME 0x00000020ULL 857*60ce86c7SWei Liu #define P9_STATS_MTIME 0x00000040ULL 858*60ce86c7SWei Liu #define P9_STATS_CTIME 0x00000080ULL 859*60ce86c7SWei Liu #define P9_STATS_INO 0x00000100ULL 860*60ce86c7SWei Liu #define P9_STATS_SIZE 0x00000200ULL 861*60ce86c7SWei Liu #define P9_STATS_BLOCKS 0x00000400ULL 862*60ce86c7SWei Liu 863*60ce86c7SWei Liu #define P9_STATS_BTIME 0x00000800ULL 864*60ce86c7SWei Liu #define P9_STATS_GEN 0x00001000ULL 865*60ce86c7SWei Liu #define P9_STATS_DATA_VERSION 0x00002000ULL 866*60ce86c7SWei Liu 867*60ce86c7SWei Liu #define P9_STATS_BASIC 0x000007ffULL /* Mask for fields up to BLOCKS */ 868*60ce86c7SWei Liu #define P9_STATS_ALL 0x00003fffULL /* Mask for All fields above */ 869*60ce86c7SWei Liu 870*60ce86c7SWei Liu 871*60ce86c7SWei Liu static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf, 872*60ce86c7SWei Liu V9fsStatDotl *v9lstat) 873*60ce86c7SWei Liu { 874*60ce86c7SWei Liu memset(v9lstat, 0, sizeof(*v9lstat)); 875*60ce86c7SWei Liu 876*60ce86c7SWei Liu v9lstat->st_mode = stbuf->st_mode; 877*60ce86c7SWei Liu v9lstat->st_nlink = stbuf->st_nlink; 878*60ce86c7SWei Liu v9lstat->st_uid = stbuf->st_uid; 879*60ce86c7SWei Liu v9lstat->st_gid = stbuf->st_gid; 880*60ce86c7SWei Liu v9lstat->st_rdev = stbuf->st_rdev; 881*60ce86c7SWei Liu v9lstat->st_size = stbuf->st_size; 882*60ce86c7SWei Liu v9lstat->st_blksize = stbuf->st_blksize; 883*60ce86c7SWei Liu v9lstat->st_blocks = stbuf->st_blocks; 884*60ce86c7SWei Liu v9lstat->st_atime_sec = stbuf->st_atime; 885*60ce86c7SWei Liu v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec; 886*60ce86c7SWei Liu v9lstat->st_mtime_sec = stbuf->st_mtime; 887*60ce86c7SWei Liu v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec; 888*60ce86c7SWei Liu v9lstat->st_ctime_sec = stbuf->st_ctime; 889*60ce86c7SWei Liu v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec; 890*60ce86c7SWei Liu /* Currently we only support BASIC fields in stat */ 891*60ce86c7SWei Liu v9lstat->st_result_mask = P9_STATS_BASIC; 892*60ce86c7SWei Liu 893*60ce86c7SWei Liu stat_to_qid(stbuf, &v9lstat->qid); 894*60ce86c7SWei Liu } 895*60ce86c7SWei Liu 896*60ce86c7SWei Liu static void print_sg(struct iovec *sg, int cnt) 897*60ce86c7SWei Liu { 898*60ce86c7SWei Liu int i; 899*60ce86c7SWei Liu 900*60ce86c7SWei Liu printf("sg[%d]: {", cnt); 901*60ce86c7SWei Liu for (i = 0; i < cnt; i++) { 902*60ce86c7SWei Liu if (i) { 903*60ce86c7SWei Liu printf(", "); 904*60ce86c7SWei Liu } 905*60ce86c7SWei Liu printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len); 906*60ce86c7SWei Liu } 907*60ce86c7SWei Liu printf("}\n"); 908*60ce86c7SWei Liu } 909*60ce86c7SWei Liu 910*60ce86c7SWei Liu /* Will call this only for path name based fid */ 911*60ce86c7SWei Liu static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len) 912*60ce86c7SWei Liu { 913*60ce86c7SWei Liu V9fsPath str; 914*60ce86c7SWei Liu v9fs_path_init(&str); 915*60ce86c7SWei Liu v9fs_path_copy(&str, dst); 916*60ce86c7SWei Liu v9fs_string_sprintf((V9fsString *)dst, "%s%s", src->data, str.data+len); 917*60ce86c7SWei Liu v9fs_path_free(&str); 918*60ce86c7SWei Liu /* +1 to include terminating NULL */ 919*60ce86c7SWei Liu dst->size++; 920*60ce86c7SWei Liu } 921*60ce86c7SWei Liu 922*60ce86c7SWei Liu static inline bool is_ro_export(FsContext *ctx) 923*60ce86c7SWei Liu { 924*60ce86c7SWei Liu return ctx->export_flags & V9FS_RDONLY; 925*60ce86c7SWei Liu } 926*60ce86c7SWei Liu 927*60ce86c7SWei Liu static void v9fs_version(void *opaque) 928*60ce86c7SWei Liu { 929*60ce86c7SWei Liu ssize_t err; 930*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 931*60ce86c7SWei Liu V9fsState *s = pdu->s; 932*60ce86c7SWei Liu V9fsString version; 933*60ce86c7SWei Liu size_t offset = 7; 934*60ce86c7SWei Liu 935*60ce86c7SWei Liu v9fs_string_init(&version); 936*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "ds", &s->msize, &version); 937*60ce86c7SWei Liu if (err < 0) { 938*60ce86c7SWei Liu offset = err; 939*60ce86c7SWei Liu goto out; 940*60ce86c7SWei Liu } 941*60ce86c7SWei Liu trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data); 942*60ce86c7SWei Liu 943*60ce86c7SWei Liu virtfs_reset(pdu); 944*60ce86c7SWei Liu 945*60ce86c7SWei Liu if (!strcmp(version.data, "9P2000.u")) { 946*60ce86c7SWei Liu s->proto_version = V9FS_PROTO_2000U; 947*60ce86c7SWei Liu } else if (!strcmp(version.data, "9P2000.L")) { 948*60ce86c7SWei Liu s->proto_version = V9FS_PROTO_2000L; 949*60ce86c7SWei Liu } else { 950*60ce86c7SWei Liu v9fs_string_sprintf(&version, "unknown"); 951*60ce86c7SWei Liu } 952*60ce86c7SWei Liu 953*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "ds", s->msize, &version); 954*60ce86c7SWei Liu if (err < 0) { 955*60ce86c7SWei Liu offset = err; 956*60ce86c7SWei Liu goto out; 957*60ce86c7SWei Liu } 958*60ce86c7SWei Liu offset += err; 959*60ce86c7SWei Liu trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data); 960*60ce86c7SWei Liu out: 961*60ce86c7SWei Liu pdu_complete(pdu, offset); 962*60ce86c7SWei Liu v9fs_string_free(&version); 963*60ce86c7SWei Liu } 964*60ce86c7SWei Liu 965*60ce86c7SWei Liu static void v9fs_attach(void *opaque) 966*60ce86c7SWei Liu { 967*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 968*60ce86c7SWei Liu V9fsState *s = pdu->s; 969*60ce86c7SWei Liu int32_t fid, afid, n_uname; 970*60ce86c7SWei Liu V9fsString uname, aname; 971*60ce86c7SWei Liu V9fsFidState *fidp; 972*60ce86c7SWei Liu size_t offset = 7; 973*60ce86c7SWei Liu V9fsQID qid; 974*60ce86c7SWei Liu ssize_t err; 975*60ce86c7SWei Liu 976*60ce86c7SWei Liu v9fs_string_init(&uname); 977*60ce86c7SWei Liu v9fs_string_init(&aname); 978*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "ddssd", &fid, 979*60ce86c7SWei Liu &afid, &uname, &aname, &n_uname); 980*60ce86c7SWei Liu if (err < 0) { 981*60ce86c7SWei Liu goto out_nofid; 982*60ce86c7SWei Liu } 983*60ce86c7SWei Liu trace_v9fs_attach(pdu->tag, pdu->id, fid, afid, uname.data, aname.data); 984*60ce86c7SWei Liu 985*60ce86c7SWei Liu fidp = alloc_fid(s, fid); 986*60ce86c7SWei Liu if (fidp == NULL) { 987*60ce86c7SWei Liu err = -EINVAL; 988*60ce86c7SWei Liu goto out_nofid; 989*60ce86c7SWei Liu } 990*60ce86c7SWei Liu fidp->uid = n_uname; 991*60ce86c7SWei Liu err = v9fs_co_name_to_path(pdu, NULL, "/", &fidp->path); 992*60ce86c7SWei Liu if (err < 0) { 993*60ce86c7SWei Liu err = -EINVAL; 994*60ce86c7SWei Liu clunk_fid(s, fid); 995*60ce86c7SWei Liu goto out; 996*60ce86c7SWei Liu } 997*60ce86c7SWei Liu err = fid_to_qid(pdu, fidp, &qid); 998*60ce86c7SWei Liu if (err < 0) { 999*60ce86c7SWei Liu err = -EINVAL; 1000*60ce86c7SWei Liu clunk_fid(s, fid); 1001*60ce86c7SWei Liu goto out; 1002*60ce86c7SWei Liu } 1003*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "Q", &qid); 1004*60ce86c7SWei Liu if (err < 0) { 1005*60ce86c7SWei Liu clunk_fid(s, fid); 1006*60ce86c7SWei Liu goto out; 1007*60ce86c7SWei Liu } 1008*60ce86c7SWei Liu err += offset; 1009*60ce86c7SWei Liu trace_v9fs_attach_return(pdu->tag, pdu->id, 1010*60ce86c7SWei Liu qid.type, qid.version, qid.path); 1011*60ce86c7SWei Liu /* 1012*60ce86c7SWei Liu * disable migration if we haven't done already. 1013*60ce86c7SWei Liu * attach could get called multiple times for the same export. 1014*60ce86c7SWei Liu */ 1015*60ce86c7SWei Liu if (!s->migration_blocker) { 1016*60ce86c7SWei Liu s->root_fid = fid; 1017*60ce86c7SWei Liu error_setg(&s->migration_blocker, 1018*60ce86c7SWei Liu "Migration is disabled when VirtFS export path '%s' is mounted in the guest using mount_tag '%s'", 1019*60ce86c7SWei Liu s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag); 1020*60ce86c7SWei Liu migrate_add_blocker(s->migration_blocker); 1021*60ce86c7SWei Liu } 1022*60ce86c7SWei Liu out: 1023*60ce86c7SWei Liu put_fid(pdu, fidp); 1024*60ce86c7SWei Liu out_nofid: 1025*60ce86c7SWei Liu pdu_complete(pdu, err); 1026*60ce86c7SWei Liu v9fs_string_free(&uname); 1027*60ce86c7SWei Liu v9fs_string_free(&aname); 1028*60ce86c7SWei Liu } 1029*60ce86c7SWei Liu 1030*60ce86c7SWei Liu static void v9fs_stat(void *opaque) 1031*60ce86c7SWei Liu { 1032*60ce86c7SWei Liu int32_t fid; 1033*60ce86c7SWei Liu V9fsStat v9stat; 1034*60ce86c7SWei Liu ssize_t err = 0; 1035*60ce86c7SWei Liu size_t offset = 7; 1036*60ce86c7SWei Liu struct stat stbuf; 1037*60ce86c7SWei Liu V9fsFidState *fidp; 1038*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 1039*60ce86c7SWei Liu 1040*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "d", &fid); 1041*60ce86c7SWei Liu if (err < 0) { 1042*60ce86c7SWei Liu goto out_nofid; 1043*60ce86c7SWei Liu } 1044*60ce86c7SWei Liu trace_v9fs_stat(pdu->tag, pdu->id, fid); 1045*60ce86c7SWei Liu 1046*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 1047*60ce86c7SWei Liu if (fidp == NULL) { 1048*60ce86c7SWei Liu err = -ENOENT; 1049*60ce86c7SWei Liu goto out_nofid; 1050*60ce86c7SWei Liu } 1051*60ce86c7SWei Liu err = v9fs_co_lstat(pdu, &fidp->path, &stbuf); 1052*60ce86c7SWei Liu if (err < 0) { 1053*60ce86c7SWei Liu goto out; 1054*60ce86c7SWei Liu } 1055*60ce86c7SWei Liu err = stat_to_v9stat(pdu, &fidp->path, &stbuf, &v9stat); 1056*60ce86c7SWei Liu if (err < 0) { 1057*60ce86c7SWei Liu goto out; 1058*60ce86c7SWei Liu } 1059*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "wS", 0, &v9stat); 1060*60ce86c7SWei Liu if (err < 0) { 1061*60ce86c7SWei Liu v9fs_stat_free(&v9stat); 1062*60ce86c7SWei Liu goto out; 1063*60ce86c7SWei Liu } 1064*60ce86c7SWei Liu trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode, 1065*60ce86c7SWei Liu v9stat.atime, v9stat.mtime, v9stat.length); 1066*60ce86c7SWei Liu err += offset; 1067*60ce86c7SWei Liu v9fs_stat_free(&v9stat); 1068*60ce86c7SWei Liu out: 1069*60ce86c7SWei Liu put_fid(pdu, fidp); 1070*60ce86c7SWei Liu out_nofid: 1071*60ce86c7SWei Liu pdu_complete(pdu, err); 1072*60ce86c7SWei Liu } 1073*60ce86c7SWei Liu 1074*60ce86c7SWei Liu static void v9fs_getattr(void *opaque) 1075*60ce86c7SWei Liu { 1076*60ce86c7SWei Liu int32_t fid; 1077*60ce86c7SWei Liu size_t offset = 7; 1078*60ce86c7SWei Liu ssize_t retval = 0; 1079*60ce86c7SWei Liu struct stat stbuf; 1080*60ce86c7SWei Liu V9fsFidState *fidp; 1081*60ce86c7SWei Liu uint64_t request_mask; 1082*60ce86c7SWei Liu V9fsStatDotl v9stat_dotl; 1083*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 1084*60ce86c7SWei Liu V9fsState *s = pdu->s; 1085*60ce86c7SWei Liu 1086*60ce86c7SWei Liu retval = pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask); 1087*60ce86c7SWei Liu if (retval < 0) { 1088*60ce86c7SWei Liu goto out_nofid; 1089*60ce86c7SWei Liu } 1090*60ce86c7SWei Liu trace_v9fs_getattr(pdu->tag, pdu->id, fid, request_mask); 1091*60ce86c7SWei Liu 1092*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 1093*60ce86c7SWei Liu if (fidp == NULL) { 1094*60ce86c7SWei Liu retval = -ENOENT; 1095*60ce86c7SWei Liu goto out_nofid; 1096*60ce86c7SWei Liu } 1097*60ce86c7SWei Liu /* 1098*60ce86c7SWei Liu * Currently we only support BASIC fields in stat, so there is no 1099*60ce86c7SWei Liu * need to look at request_mask. 1100*60ce86c7SWei Liu */ 1101*60ce86c7SWei Liu retval = v9fs_co_lstat(pdu, &fidp->path, &stbuf); 1102*60ce86c7SWei Liu if (retval < 0) { 1103*60ce86c7SWei Liu goto out; 1104*60ce86c7SWei Liu } 1105*60ce86c7SWei Liu stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl); 1106*60ce86c7SWei Liu 1107*60ce86c7SWei Liu /* fill st_gen if requested and supported by underlying fs */ 1108*60ce86c7SWei Liu if (request_mask & P9_STATS_GEN) { 1109*60ce86c7SWei Liu retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl); 1110*60ce86c7SWei Liu switch (retval) { 1111*60ce86c7SWei Liu case 0: 1112*60ce86c7SWei Liu /* we have valid st_gen: update result mask */ 1113*60ce86c7SWei Liu v9stat_dotl.st_result_mask |= P9_STATS_GEN; 1114*60ce86c7SWei Liu break; 1115*60ce86c7SWei Liu case -EINTR: 1116*60ce86c7SWei Liu /* request cancelled, e.g. by Tflush */ 1117*60ce86c7SWei Liu goto out; 1118*60ce86c7SWei Liu default: 1119*60ce86c7SWei Liu /* failed to get st_gen: not fatal, ignore */ 1120*60ce86c7SWei Liu break; 1121*60ce86c7SWei Liu } 1122*60ce86c7SWei Liu } 1123*60ce86c7SWei Liu retval = pdu_marshal(pdu, offset, "A", &v9stat_dotl); 1124*60ce86c7SWei Liu if (retval < 0) { 1125*60ce86c7SWei Liu goto out; 1126*60ce86c7SWei Liu } 1127*60ce86c7SWei Liu retval += offset; 1128*60ce86c7SWei Liu trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask, 1129*60ce86c7SWei Liu v9stat_dotl.st_mode, v9stat_dotl.st_uid, 1130*60ce86c7SWei Liu v9stat_dotl.st_gid); 1131*60ce86c7SWei Liu out: 1132*60ce86c7SWei Liu put_fid(pdu, fidp); 1133*60ce86c7SWei Liu out_nofid: 1134*60ce86c7SWei Liu pdu_complete(pdu, retval); 1135*60ce86c7SWei Liu } 1136*60ce86c7SWei Liu 1137*60ce86c7SWei Liu /* Attribute flags */ 1138*60ce86c7SWei Liu #define P9_ATTR_MODE (1 << 0) 1139*60ce86c7SWei Liu #define P9_ATTR_UID (1 << 1) 1140*60ce86c7SWei Liu #define P9_ATTR_GID (1 << 2) 1141*60ce86c7SWei Liu #define P9_ATTR_SIZE (1 << 3) 1142*60ce86c7SWei Liu #define P9_ATTR_ATIME (1 << 4) 1143*60ce86c7SWei Liu #define P9_ATTR_MTIME (1 << 5) 1144*60ce86c7SWei Liu #define P9_ATTR_CTIME (1 << 6) 1145*60ce86c7SWei Liu #define P9_ATTR_ATIME_SET (1 << 7) 1146*60ce86c7SWei Liu #define P9_ATTR_MTIME_SET (1 << 8) 1147*60ce86c7SWei Liu 1148*60ce86c7SWei Liu #define P9_ATTR_MASK 127 1149*60ce86c7SWei Liu 1150*60ce86c7SWei Liu static void v9fs_setattr(void *opaque) 1151*60ce86c7SWei Liu { 1152*60ce86c7SWei Liu int err = 0; 1153*60ce86c7SWei Liu int32_t fid; 1154*60ce86c7SWei Liu V9fsFidState *fidp; 1155*60ce86c7SWei Liu size_t offset = 7; 1156*60ce86c7SWei Liu V9fsIattr v9iattr; 1157*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 1158*60ce86c7SWei Liu 1159*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dI", &fid, &v9iattr); 1160*60ce86c7SWei Liu if (err < 0) { 1161*60ce86c7SWei Liu goto out_nofid; 1162*60ce86c7SWei Liu } 1163*60ce86c7SWei Liu 1164*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 1165*60ce86c7SWei Liu if (fidp == NULL) { 1166*60ce86c7SWei Liu err = -EINVAL; 1167*60ce86c7SWei Liu goto out_nofid; 1168*60ce86c7SWei Liu } 1169*60ce86c7SWei Liu if (v9iattr.valid & P9_ATTR_MODE) { 1170*60ce86c7SWei Liu err = v9fs_co_chmod(pdu, &fidp->path, v9iattr.mode); 1171*60ce86c7SWei Liu if (err < 0) { 1172*60ce86c7SWei Liu goto out; 1173*60ce86c7SWei Liu } 1174*60ce86c7SWei Liu } 1175*60ce86c7SWei Liu if (v9iattr.valid & (P9_ATTR_ATIME | P9_ATTR_MTIME)) { 1176*60ce86c7SWei Liu struct timespec times[2]; 1177*60ce86c7SWei Liu if (v9iattr.valid & P9_ATTR_ATIME) { 1178*60ce86c7SWei Liu if (v9iattr.valid & P9_ATTR_ATIME_SET) { 1179*60ce86c7SWei Liu times[0].tv_sec = v9iattr.atime_sec; 1180*60ce86c7SWei Liu times[0].tv_nsec = v9iattr.atime_nsec; 1181*60ce86c7SWei Liu } else { 1182*60ce86c7SWei Liu times[0].tv_nsec = UTIME_NOW; 1183*60ce86c7SWei Liu } 1184*60ce86c7SWei Liu } else { 1185*60ce86c7SWei Liu times[0].tv_nsec = UTIME_OMIT; 1186*60ce86c7SWei Liu } 1187*60ce86c7SWei Liu if (v9iattr.valid & P9_ATTR_MTIME) { 1188*60ce86c7SWei Liu if (v9iattr.valid & P9_ATTR_MTIME_SET) { 1189*60ce86c7SWei Liu times[1].tv_sec = v9iattr.mtime_sec; 1190*60ce86c7SWei Liu times[1].tv_nsec = v9iattr.mtime_nsec; 1191*60ce86c7SWei Liu } else { 1192*60ce86c7SWei Liu times[1].tv_nsec = UTIME_NOW; 1193*60ce86c7SWei Liu } 1194*60ce86c7SWei Liu } else { 1195*60ce86c7SWei Liu times[1].tv_nsec = UTIME_OMIT; 1196*60ce86c7SWei Liu } 1197*60ce86c7SWei Liu err = v9fs_co_utimensat(pdu, &fidp->path, times); 1198*60ce86c7SWei Liu if (err < 0) { 1199*60ce86c7SWei Liu goto out; 1200*60ce86c7SWei Liu } 1201*60ce86c7SWei Liu } 1202*60ce86c7SWei Liu /* 1203*60ce86c7SWei Liu * If the only valid entry in iattr is ctime we can call 1204*60ce86c7SWei Liu * chown(-1,-1) to update the ctime of the file 1205*60ce86c7SWei Liu */ 1206*60ce86c7SWei Liu if ((v9iattr.valid & (P9_ATTR_UID | P9_ATTR_GID)) || 1207*60ce86c7SWei Liu ((v9iattr.valid & P9_ATTR_CTIME) 1208*60ce86c7SWei Liu && !((v9iattr.valid & P9_ATTR_MASK) & ~P9_ATTR_CTIME))) { 1209*60ce86c7SWei Liu if (!(v9iattr.valid & P9_ATTR_UID)) { 1210*60ce86c7SWei Liu v9iattr.uid = -1; 1211*60ce86c7SWei Liu } 1212*60ce86c7SWei Liu if (!(v9iattr.valid & P9_ATTR_GID)) { 1213*60ce86c7SWei Liu v9iattr.gid = -1; 1214*60ce86c7SWei Liu } 1215*60ce86c7SWei Liu err = v9fs_co_chown(pdu, &fidp->path, v9iattr.uid, 1216*60ce86c7SWei Liu v9iattr.gid); 1217*60ce86c7SWei Liu if (err < 0) { 1218*60ce86c7SWei Liu goto out; 1219*60ce86c7SWei Liu } 1220*60ce86c7SWei Liu } 1221*60ce86c7SWei Liu if (v9iattr.valid & (P9_ATTR_SIZE)) { 1222*60ce86c7SWei Liu err = v9fs_co_truncate(pdu, &fidp->path, v9iattr.size); 1223*60ce86c7SWei Liu if (err < 0) { 1224*60ce86c7SWei Liu goto out; 1225*60ce86c7SWei Liu } 1226*60ce86c7SWei Liu } 1227*60ce86c7SWei Liu err = offset; 1228*60ce86c7SWei Liu out: 1229*60ce86c7SWei Liu put_fid(pdu, fidp); 1230*60ce86c7SWei Liu out_nofid: 1231*60ce86c7SWei Liu pdu_complete(pdu, err); 1232*60ce86c7SWei Liu } 1233*60ce86c7SWei Liu 1234*60ce86c7SWei Liu static int v9fs_walk_marshal(V9fsPDU *pdu, uint16_t nwnames, V9fsQID *qids) 1235*60ce86c7SWei Liu { 1236*60ce86c7SWei Liu int i; 1237*60ce86c7SWei Liu ssize_t err; 1238*60ce86c7SWei Liu size_t offset = 7; 1239*60ce86c7SWei Liu 1240*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "w", nwnames); 1241*60ce86c7SWei Liu if (err < 0) { 1242*60ce86c7SWei Liu return err; 1243*60ce86c7SWei Liu } 1244*60ce86c7SWei Liu offset += err; 1245*60ce86c7SWei Liu for (i = 0; i < nwnames; i++) { 1246*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "Q", &qids[i]); 1247*60ce86c7SWei Liu if (err < 0) { 1248*60ce86c7SWei Liu return err; 1249*60ce86c7SWei Liu } 1250*60ce86c7SWei Liu offset += err; 1251*60ce86c7SWei Liu } 1252*60ce86c7SWei Liu return offset; 1253*60ce86c7SWei Liu } 1254*60ce86c7SWei Liu 1255*60ce86c7SWei Liu static void v9fs_walk(void *opaque) 1256*60ce86c7SWei Liu { 1257*60ce86c7SWei Liu int name_idx; 1258*60ce86c7SWei Liu V9fsQID *qids = NULL; 1259*60ce86c7SWei Liu int i, err = 0; 1260*60ce86c7SWei Liu V9fsPath dpath, path; 1261*60ce86c7SWei Liu uint16_t nwnames; 1262*60ce86c7SWei Liu struct stat stbuf; 1263*60ce86c7SWei Liu size_t offset = 7; 1264*60ce86c7SWei Liu int32_t fid, newfid; 1265*60ce86c7SWei Liu V9fsString *wnames = NULL; 1266*60ce86c7SWei Liu V9fsFidState *fidp; 1267*60ce86c7SWei Liu V9fsFidState *newfidp = NULL; 1268*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 1269*60ce86c7SWei Liu V9fsState *s = pdu->s; 1270*60ce86c7SWei Liu 1271*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "ddw", &fid, &newfid, &nwnames); 1272*60ce86c7SWei Liu if (err < 0) { 1273*60ce86c7SWei Liu pdu_complete(pdu, err); 1274*60ce86c7SWei Liu return ; 1275*60ce86c7SWei Liu } 1276*60ce86c7SWei Liu offset += err; 1277*60ce86c7SWei Liu 1278*60ce86c7SWei Liu trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames); 1279*60ce86c7SWei Liu 1280*60ce86c7SWei Liu if (nwnames && nwnames <= P9_MAXWELEM) { 1281*60ce86c7SWei Liu wnames = g_malloc0(sizeof(wnames[0]) * nwnames); 1282*60ce86c7SWei Liu qids = g_malloc0(sizeof(qids[0]) * nwnames); 1283*60ce86c7SWei Liu for (i = 0; i < nwnames; i++) { 1284*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "s", &wnames[i]); 1285*60ce86c7SWei Liu if (err < 0) { 1286*60ce86c7SWei Liu goto out_nofid; 1287*60ce86c7SWei Liu } 1288*60ce86c7SWei Liu offset += err; 1289*60ce86c7SWei Liu } 1290*60ce86c7SWei Liu } else if (nwnames > P9_MAXWELEM) { 1291*60ce86c7SWei Liu err = -EINVAL; 1292*60ce86c7SWei Liu goto out_nofid; 1293*60ce86c7SWei Liu } 1294*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 1295*60ce86c7SWei Liu if (fidp == NULL) { 1296*60ce86c7SWei Liu err = -ENOENT; 1297*60ce86c7SWei Liu goto out_nofid; 1298*60ce86c7SWei Liu } 1299*60ce86c7SWei Liu v9fs_path_init(&dpath); 1300*60ce86c7SWei Liu v9fs_path_init(&path); 1301*60ce86c7SWei Liu /* 1302*60ce86c7SWei Liu * Both dpath and path initially poin to fidp. 1303*60ce86c7SWei Liu * Needed to handle request with nwnames == 0 1304*60ce86c7SWei Liu */ 1305*60ce86c7SWei Liu v9fs_path_copy(&dpath, &fidp->path); 1306*60ce86c7SWei Liu v9fs_path_copy(&path, &fidp->path); 1307*60ce86c7SWei Liu for (name_idx = 0; name_idx < nwnames; name_idx++) { 1308*60ce86c7SWei Liu err = v9fs_co_name_to_path(pdu, &dpath, wnames[name_idx].data, &path); 1309*60ce86c7SWei Liu if (err < 0) { 1310*60ce86c7SWei Liu goto out; 1311*60ce86c7SWei Liu } 1312*60ce86c7SWei Liu err = v9fs_co_lstat(pdu, &path, &stbuf); 1313*60ce86c7SWei Liu if (err < 0) { 1314*60ce86c7SWei Liu goto out; 1315*60ce86c7SWei Liu } 1316*60ce86c7SWei Liu stat_to_qid(&stbuf, &qids[name_idx]); 1317*60ce86c7SWei Liu v9fs_path_copy(&dpath, &path); 1318*60ce86c7SWei Liu } 1319*60ce86c7SWei Liu if (fid == newfid) { 1320*60ce86c7SWei Liu BUG_ON(fidp->fid_type != P9_FID_NONE); 1321*60ce86c7SWei Liu v9fs_path_copy(&fidp->path, &path); 1322*60ce86c7SWei Liu } else { 1323*60ce86c7SWei Liu newfidp = alloc_fid(s, newfid); 1324*60ce86c7SWei Liu if (newfidp == NULL) { 1325*60ce86c7SWei Liu err = -EINVAL; 1326*60ce86c7SWei Liu goto out; 1327*60ce86c7SWei Liu } 1328*60ce86c7SWei Liu newfidp->uid = fidp->uid; 1329*60ce86c7SWei Liu v9fs_path_copy(&newfidp->path, &path); 1330*60ce86c7SWei Liu } 1331*60ce86c7SWei Liu err = v9fs_walk_marshal(pdu, nwnames, qids); 1332*60ce86c7SWei Liu trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids); 1333*60ce86c7SWei Liu out: 1334*60ce86c7SWei Liu put_fid(pdu, fidp); 1335*60ce86c7SWei Liu if (newfidp) { 1336*60ce86c7SWei Liu put_fid(pdu, newfidp); 1337*60ce86c7SWei Liu } 1338*60ce86c7SWei Liu v9fs_path_free(&dpath); 1339*60ce86c7SWei Liu v9fs_path_free(&path); 1340*60ce86c7SWei Liu out_nofid: 1341*60ce86c7SWei Liu pdu_complete(pdu, err); 1342*60ce86c7SWei Liu if (nwnames && nwnames <= P9_MAXWELEM) { 1343*60ce86c7SWei Liu for (name_idx = 0; name_idx < nwnames; name_idx++) { 1344*60ce86c7SWei Liu v9fs_string_free(&wnames[name_idx]); 1345*60ce86c7SWei Liu } 1346*60ce86c7SWei Liu g_free(wnames); 1347*60ce86c7SWei Liu g_free(qids); 1348*60ce86c7SWei Liu } 1349*60ce86c7SWei Liu } 1350*60ce86c7SWei Liu 1351*60ce86c7SWei Liu static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path) 1352*60ce86c7SWei Liu { 1353*60ce86c7SWei Liu struct statfs stbuf; 1354*60ce86c7SWei Liu int32_t iounit = 0; 1355*60ce86c7SWei Liu V9fsState *s = pdu->s; 1356*60ce86c7SWei Liu 1357*60ce86c7SWei Liu /* 1358*60ce86c7SWei Liu * iounit should be multiples of f_bsize (host filesystem block size 1359*60ce86c7SWei Liu * and as well as less than (client msize - P9_IOHDRSZ)) 1360*60ce86c7SWei Liu */ 1361*60ce86c7SWei Liu if (!v9fs_co_statfs(pdu, path, &stbuf)) { 1362*60ce86c7SWei Liu iounit = stbuf.f_bsize; 1363*60ce86c7SWei Liu iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize; 1364*60ce86c7SWei Liu } 1365*60ce86c7SWei Liu if (!iounit) { 1366*60ce86c7SWei Liu iounit = s->msize - P9_IOHDRSZ; 1367*60ce86c7SWei Liu } 1368*60ce86c7SWei Liu return iounit; 1369*60ce86c7SWei Liu } 1370*60ce86c7SWei Liu 1371*60ce86c7SWei Liu static void v9fs_open(void *opaque) 1372*60ce86c7SWei Liu { 1373*60ce86c7SWei Liu int flags; 1374*60ce86c7SWei Liu int32_t fid; 1375*60ce86c7SWei Liu int32_t mode; 1376*60ce86c7SWei Liu V9fsQID qid; 1377*60ce86c7SWei Liu int iounit = 0; 1378*60ce86c7SWei Liu ssize_t err = 0; 1379*60ce86c7SWei Liu size_t offset = 7; 1380*60ce86c7SWei Liu struct stat stbuf; 1381*60ce86c7SWei Liu V9fsFidState *fidp; 1382*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 1383*60ce86c7SWei Liu V9fsState *s = pdu->s; 1384*60ce86c7SWei Liu 1385*60ce86c7SWei Liu if (s->proto_version == V9FS_PROTO_2000L) { 1386*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dd", &fid, &mode); 1387*60ce86c7SWei Liu } else { 1388*60ce86c7SWei Liu uint8_t modebyte; 1389*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "db", &fid, &modebyte); 1390*60ce86c7SWei Liu mode = modebyte; 1391*60ce86c7SWei Liu } 1392*60ce86c7SWei Liu if (err < 0) { 1393*60ce86c7SWei Liu goto out_nofid; 1394*60ce86c7SWei Liu } 1395*60ce86c7SWei Liu trace_v9fs_open(pdu->tag, pdu->id, fid, mode); 1396*60ce86c7SWei Liu 1397*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 1398*60ce86c7SWei Liu if (fidp == NULL) { 1399*60ce86c7SWei Liu err = -ENOENT; 1400*60ce86c7SWei Liu goto out_nofid; 1401*60ce86c7SWei Liu } 1402*60ce86c7SWei Liu BUG_ON(fidp->fid_type != P9_FID_NONE); 1403*60ce86c7SWei Liu 1404*60ce86c7SWei Liu err = v9fs_co_lstat(pdu, &fidp->path, &stbuf); 1405*60ce86c7SWei Liu if (err < 0) { 1406*60ce86c7SWei Liu goto out; 1407*60ce86c7SWei Liu } 1408*60ce86c7SWei Liu stat_to_qid(&stbuf, &qid); 1409*60ce86c7SWei Liu if (S_ISDIR(stbuf.st_mode)) { 1410*60ce86c7SWei Liu err = v9fs_co_opendir(pdu, fidp); 1411*60ce86c7SWei Liu if (err < 0) { 1412*60ce86c7SWei Liu goto out; 1413*60ce86c7SWei Liu } 1414*60ce86c7SWei Liu fidp->fid_type = P9_FID_DIR; 1415*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "Qd", &qid, 0); 1416*60ce86c7SWei Liu if (err < 0) { 1417*60ce86c7SWei Liu goto out; 1418*60ce86c7SWei Liu } 1419*60ce86c7SWei Liu err += offset; 1420*60ce86c7SWei Liu } else { 1421*60ce86c7SWei Liu if (s->proto_version == V9FS_PROTO_2000L) { 1422*60ce86c7SWei Liu flags = get_dotl_openflags(s, mode); 1423*60ce86c7SWei Liu } else { 1424*60ce86c7SWei Liu flags = omode_to_uflags(mode); 1425*60ce86c7SWei Liu } 1426*60ce86c7SWei Liu if (is_ro_export(&s->ctx)) { 1427*60ce86c7SWei Liu if (mode & O_WRONLY || mode & O_RDWR || 1428*60ce86c7SWei Liu mode & O_APPEND || mode & O_TRUNC) { 1429*60ce86c7SWei Liu err = -EROFS; 1430*60ce86c7SWei Liu goto out; 1431*60ce86c7SWei Liu } 1432*60ce86c7SWei Liu } 1433*60ce86c7SWei Liu err = v9fs_co_open(pdu, fidp, flags); 1434*60ce86c7SWei Liu if (err < 0) { 1435*60ce86c7SWei Liu goto out; 1436*60ce86c7SWei Liu } 1437*60ce86c7SWei Liu fidp->fid_type = P9_FID_FILE; 1438*60ce86c7SWei Liu fidp->open_flags = flags; 1439*60ce86c7SWei Liu if (flags & O_EXCL) { 1440*60ce86c7SWei Liu /* 1441*60ce86c7SWei Liu * We let the host file system do O_EXCL check 1442*60ce86c7SWei Liu * We should not reclaim such fd 1443*60ce86c7SWei Liu */ 1444*60ce86c7SWei Liu fidp->flags |= FID_NON_RECLAIMABLE; 1445*60ce86c7SWei Liu } 1446*60ce86c7SWei Liu iounit = get_iounit(pdu, &fidp->path); 1447*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "Qd", &qid, iounit); 1448*60ce86c7SWei Liu if (err < 0) { 1449*60ce86c7SWei Liu goto out; 1450*60ce86c7SWei Liu } 1451*60ce86c7SWei Liu err += offset; 1452*60ce86c7SWei Liu } 1453*60ce86c7SWei Liu trace_v9fs_open_return(pdu->tag, pdu->id, 1454*60ce86c7SWei Liu qid.type, qid.version, qid.path, iounit); 1455*60ce86c7SWei Liu out: 1456*60ce86c7SWei Liu put_fid(pdu, fidp); 1457*60ce86c7SWei Liu out_nofid: 1458*60ce86c7SWei Liu pdu_complete(pdu, err); 1459*60ce86c7SWei Liu } 1460*60ce86c7SWei Liu 1461*60ce86c7SWei Liu static void v9fs_lcreate(void *opaque) 1462*60ce86c7SWei Liu { 1463*60ce86c7SWei Liu int32_t dfid, flags, mode; 1464*60ce86c7SWei Liu gid_t gid; 1465*60ce86c7SWei Liu ssize_t err = 0; 1466*60ce86c7SWei Liu ssize_t offset = 7; 1467*60ce86c7SWei Liu V9fsString name; 1468*60ce86c7SWei Liu V9fsFidState *fidp; 1469*60ce86c7SWei Liu struct stat stbuf; 1470*60ce86c7SWei Liu V9fsQID qid; 1471*60ce86c7SWei Liu int32_t iounit; 1472*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 1473*60ce86c7SWei Liu 1474*60ce86c7SWei Liu v9fs_string_init(&name); 1475*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dsddd", &dfid, 1476*60ce86c7SWei Liu &name, &flags, &mode, &gid); 1477*60ce86c7SWei Liu if (err < 0) { 1478*60ce86c7SWei Liu goto out_nofid; 1479*60ce86c7SWei Liu } 1480*60ce86c7SWei Liu trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid); 1481*60ce86c7SWei Liu 1482*60ce86c7SWei Liu fidp = get_fid(pdu, dfid); 1483*60ce86c7SWei Liu if (fidp == NULL) { 1484*60ce86c7SWei Liu err = -ENOENT; 1485*60ce86c7SWei Liu goto out_nofid; 1486*60ce86c7SWei Liu } 1487*60ce86c7SWei Liu 1488*60ce86c7SWei Liu flags = get_dotl_openflags(pdu->s, flags); 1489*60ce86c7SWei Liu err = v9fs_co_open2(pdu, fidp, &name, gid, 1490*60ce86c7SWei Liu flags | O_CREAT, mode, &stbuf); 1491*60ce86c7SWei Liu if (err < 0) { 1492*60ce86c7SWei Liu goto out; 1493*60ce86c7SWei Liu } 1494*60ce86c7SWei Liu fidp->fid_type = P9_FID_FILE; 1495*60ce86c7SWei Liu fidp->open_flags = flags; 1496*60ce86c7SWei Liu if (flags & O_EXCL) { 1497*60ce86c7SWei Liu /* 1498*60ce86c7SWei Liu * We let the host file system do O_EXCL check 1499*60ce86c7SWei Liu * We should not reclaim such fd 1500*60ce86c7SWei Liu */ 1501*60ce86c7SWei Liu fidp->flags |= FID_NON_RECLAIMABLE; 1502*60ce86c7SWei Liu } 1503*60ce86c7SWei Liu iounit = get_iounit(pdu, &fidp->path); 1504*60ce86c7SWei Liu stat_to_qid(&stbuf, &qid); 1505*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "Qd", &qid, iounit); 1506*60ce86c7SWei Liu if (err < 0) { 1507*60ce86c7SWei Liu goto out; 1508*60ce86c7SWei Liu } 1509*60ce86c7SWei Liu err += offset; 1510*60ce86c7SWei Liu trace_v9fs_lcreate_return(pdu->tag, pdu->id, 1511*60ce86c7SWei Liu qid.type, qid.version, qid.path, iounit); 1512*60ce86c7SWei Liu out: 1513*60ce86c7SWei Liu put_fid(pdu, fidp); 1514*60ce86c7SWei Liu out_nofid: 1515*60ce86c7SWei Liu pdu_complete(pdu, err); 1516*60ce86c7SWei Liu v9fs_string_free(&name); 1517*60ce86c7SWei Liu } 1518*60ce86c7SWei Liu 1519*60ce86c7SWei Liu static void v9fs_fsync(void *opaque) 1520*60ce86c7SWei Liu { 1521*60ce86c7SWei Liu int err; 1522*60ce86c7SWei Liu int32_t fid; 1523*60ce86c7SWei Liu int datasync; 1524*60ce86c7SWei Liu size_t offset = 7; 1525*60ce86c7SWei Liu V9fsFidState *fidp; 1526*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 1527*60ce86c7SWei Liu 1528*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dd", &fid, &datasync); 1529*60ce86c7SWei Liu if (err < 0) { 1530*60ce86c7SWei Liu goto out_nofid; 1531*60ce86c7SWei Liu } 1532*60ce86c7SWei Liu trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync); 1533*60ce86c7SWei Liu 1534*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 1535*60ce86c7SWei Liu if (fidp == NULL) { 1536*60ce86c7SWei Liu err = -ENOENT; 1537*60ce86c7SWei Liu goto out_nofid; 1538*60ce86c7SWei Liu } 1539*60ce86c7SWei Liu err = v9fs_co_fsync(pdu, fidp, datasync); 1540*60ce86c7SWei Liu if (!err) { 1541*60ce86c7SWei Liu err = offset; 1542*60ce86c7SWei Liu } 1543*60ce86c7SWei Liu put_fid(pdu, fidp); 1544*60ce86c7SWei Liu out_nofid: 1545*60ce86c7SWei Liu pdu_complete(pdu, err); 1546*60ce86c7SWei Liu } 1547*60ce86c7SWei Liu 1548*60ce86c7SWei Liu static void v9fs_clunk(void *opaque) 1549*60ce86c7SWei Liu { 1550*60ce86c7SWei Liu int err; 1551*60ce86c7SWei Liu int32_t fid; 1552*60ce86c7SWei Liu size_t offset = 7; 1553*60ce86c7SWei Liu V9fsFidState *fidp; 1554*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 1555*60ce86c7SWei Liu V9fsState *s = pdu->s; 1556*60ce86c7SWei Liu 1557*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "d", &fid); 1558*60ce86c7SWei Liu if (err < 0) { 1559*60ce86c7SWei Liu goto out_nofid; 1560*60ce86c7SWei Liu } 1561*60ce86c7SWei Liu trace_v9fs_clunk(pdu->tag, pdu->id, fid); 1562*60ce86c7SWei Liu 1563*60ce86c7SWei Liu fidp = clunk_fid(s, fid); 1564*60ce86c7SWei Liu if (fidp == NULL) { 1565*60ce86c7SWei Liu err = -ENOENT; 1566*60ce86c7SWei Liu goto out_nofid; 1567*60ce86c7SWei Liu } 1568*60ce86c7SWei Liu /* 1569*60ce86c7SWei Liu * Bump the ref so that put_fid will 1570*60ce86c7SWei Liu * free the fid. 1571*60ce86c7SWei Liu */ 1572*60ce86c7SWei Liu fidp->ref++; 1573*60ce86c7SWei Liu err = put_fid(pdu, fidp); 1574*60ce86c7SWei Liu if (!err) { 1575*60ce86c7SWei Liu err = offset; 1576*60ce86c7SWei Liu } 1577*60ce86c7SWei Liu out_nofid: 1578*60ce86c7SWei Liu pdu_complete(pdu, err); 1579*60ce86c7SWei Liu } 1580*60ce86c7SWei Liu 1581*60ce86c7SWei Liu static int v9fs_xattr_read(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, 1582*60ce86c7SWei Liu uint64_t off, uint32_t max_count) 1583*60ce86c7SWei Liu { 1584*60ce86c7SWei Liu ssize_t err; 1585*60ce86c7SWei Liu size_t offset = 7; 1586*60ce86c7SWei Liu int read_count; 1587*60ce86c7SWei Liu int64_t xattr_len; 1588*60ce86c7SWei Liu 1589*60ce86c7SWei Liu xattr_len = fidp->fs.xattr.len; 1590*60ce86c7SWei Liu read_count = xattr_len - off; 1591*60ce86c7SWei Liu if (read_count > max_count) { 1592*60ce86c7SWei Liu read_count = max_count; 1593*60ce86c7SWei Liu } else if (read_count < 0) { 1594*60ce86c7SWei Liu /* 1595*60ce86c7SWei Liu * read beyond XATTR value 1596*60ce86c7SWei Liu */ 1597*60ce86c7SWei Liu read_count = 0; 1598*60ce86c7SWei Liu } 1599*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "d", read_count); 1600*60ce86c7SWei Liu if (err < 0) { 1601*60ce86c7SWei Liu return err; 1602*60ce86c7SWei Liu } 1603*60ce86c7SWei Liu offset += err; 1604*60ce86c7SWei Liu err = v9fs_pack(pdu->elem.in_sg, pdu->elem.in_num, offset, 1605*60ce86c7SWei Liu ((char *)fidp->fs.xattr.value) + off, 1606*60ce86c7SWei Liu read_count); 1607*60ce86c7SWei Liu if (err < 0) { 1608*60ce86c7SWei Liu return err; 1609*60ce86c7SWei Liu } 1610*60ce86c7SWei Liu offset += err; 1611*60ce86c7SWei Liu return offset; 1612*60ce86c7SWei Liu } 1613*60ce86c7SWei Liu 1614*60ce86c7SWei Liu static int v9fs_do_readdir_with_stat(V9fsPDU *pdu, 1615*60ce86c7SWei Liu V9fsFidState *fidp, uint32_t max_count) 1616*60ce86c7SWei Liu { 1617*60ce86c7SWei Liu V9fsPath path; 1618*60ce86c7SWei Liu V9fsStat v9stat; 1619*60ce86c7SWei Liu int len, err = 0; 1620*60ce86c7SWei Liu int32_t count = 0; 1621*60ce86c7SWei Liu struct stat stbuf; 1622*60ce86c7SWei Liu off_t saved_dir_pos; 1623*60ce86c7SWei Liu struct dirent *dent, *result; 1624*60ce86c7SWei Liu 1625*60ce86c7SWei Liu /* save the directory position */ 1626*60ce86c7SWei Liu saved_dir_pos = v9fs_co_telldir(pdu, fidp); 1627*60ce86c7SWei Liu if (saved_dir_pos < 0) { 1628*60ce86c7SWei Liu return saved_dir_pos; 1629*60ce86c7SWei Liu } 1630*60ce86c7SWei Liu 1631*60ce86c7SWei Liu dent = g_malloc(sizeof(struct dirent)); 1632*60ce86c7SWei Liu 1633*60ce86c7SWei Liu while (1) { 1634*60ce86c7SWei Liu v9fs_path_init(&path); 1635*60ce86c7SWei Liu err = v9fs_co_readdir_r(pdu, fidp, dent, &result); 1636*60ce86c7SWei Liu if (err || !result) { 1637*60ce86c7SWei Liu break; 1638*60ce86c7SWei Liu } 1639*60ce86c7SWei Liu err = v9fs_co_name_to_path(pdu, &fidp->path, dent->d_name, &path); 1640*60ce86c7SWei Liu if (err < 0) { 1641*60ce86c7SWei Liu goto out; 1642*60ce86c7SWei Liu } 1643*60ce86c7SWei Liu err = v9fs_co_lstat(pdu, &path, &stbuf); 1644*60ce86c7SWei Liu if (err < 0) { 1645*60ce86c7SWei Liu goto out; 1646*60ce86c7SWei Liu } 1647*60ce86c7SWei Liu err = stat_to_v9stat(pdu, &path, &stbuf, &v9stat); 1648*60ce86c7SWei Liu if (err < 0) { 1649*60ce86c7SWei Liu goto out; 1650*60ce86c7SWei Liu } 1651*60ce86c7SWei Liu /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */ 1652*60ce86c7SWei Liu len = pdu_marshal(pdu, 11 + count, "S", &v9stat); 1653*60ce86c7SWei Liu if ((len != (v9stat.size + 2)) || ((count + len) > max_count)) { 1654*60ce86c7SWei Liu /* Ran out of buffer. Set dir back to old position and return */ 1655*60ce86c7SWei Liu v9fs_co_seekdir(pdu, fidp, saved_dir_pos); 1656*60ce86c7SWei Liu v9fs_stat_free(&v9stat); 1657*60ce86c7SWei Liu v9fs_path_free(&path); 1658*60ce86c7SWei Liu g_free(dent); 1659*60ce86c7SWei Liu return count; 1660*60ce86c7SWei Liu } 1661*60ce86c7SWei Liu count += len; 1662*60ce86c7SWei Liu v9fs_stat_free(&v9stat); 1663*60ce86c7SWei Liu v9fs_path_free(&path); 1664*60ce86c7SWei Liu saved_dir_pos = dent->d_off; 1665*60ce86c7SWei Liu } 1666*60ce86c7SWei Liu out: 1667*60ce86c7SWei Liu g_free(dent); 1668*60ce86c7SWei Liu v9fs_path_free(&path); 1669*60ce86c7SWei Liu if (err < 0) { 1670*60ce86c7SWei Liu return err; 1671*60ce86c7SWei Liu } 1672*60ce86c7SWei Liu return count; 1673*60ce86c7SWei Liu } 1674*60ce86c7SWei Liu 1675*60ce86c7SWei Liu /* 1676*60ce86c7SWei Liu * Create a QEMUIOVector for a sub-region of PDU iovecs 1677*60ce86c7SWei Liu * 1678*60ce86c7SWei Liu * @qiov: uninitialized QEMUIOVector 1679*60ce86c7SWei Liu * @skip: number of bytes to skip from beginning of PDU 1680*60ce86c7SWei Liu * @size: number of bytes to include 1681*60ce86c7SWei Liu * @is_write: true - write, false - read 1682*60ce86c7SWei Liu * 1683*60ce86c7SWei Liu * The resulting QEMUIOVector has heap-allocated iovecs and must be cleaned up 1684*60ce86c7SWei Liu * with qemu_iovec_destroy(). 1685*60ce86c7SWei Liu */ 1686*60ce86c7SWei Liu static void v9fs_init_qiov_from_pdu(QEMUIOVector *qiov, V9fsPDU *pdu, 1687*60ce86c7SWei Liu size_t skip, size_t size, 1688*60ce86c7SWei Liu bool is_write) 1689*60ce86c7SWei Liu { 1690*60ce86c7SWei Liu QEMUIOVector elem; 1691*60ce86c7SWei Liu struct iovec *iov; 1692*60ce86c7SWei Liu unsigned int niov; 1693*60ce86c7SWei Liu 1694*60ce86c7SWei Liu virtio_init_iov_from_pdu(pdu, &iov, &niov, is_write); 1695*60ce86c7SWei Liu 1696*60ce86c7SWei Liu qemu_iovec_init_external(&elem, iov, niov); 1697*60ce86c7SWei Liu qemu_iovec_init(qiov, niov); 1698*60ce86c7SWei Liu qemu_iovec_concat(qiov, &elem, skip, size); 1699*60ce86c7SWei Liu } 1700*60ce86c7SWei Liu 1701*60ce86c7SWei Liu static void v9fs_read(void *opaque) 1702*60ce86c7SWei Liu { 1703*60ce86c7SWei Liu int32_t fid; 1704*60ce86c7SWei Liu uint64_t off; 1705*60ce86c7SWei Liu ssize_t err = 0; 1706*60ce86c7SWei Liu int32_t count = 0; 1707*60ce86c7SWei Liu size_t offset = 7; 1708*60ce86c7SWei Liu uint32_t max_count; 1709*60ce86c7SWei Liu V9fsFidState *fidp; 1710*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 1711*60ce86c7SWei Liu V9fsState *s = pdu->s; 1712*60ce86c7SWei Liu 1713*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count); 1714*60ce86c7SWei Liu if (err < 0) { 1715*60ce86c7SWei Liu goto out_nofid; 1716*60ce86c7SWei Liu } 1717*60ce86c7SWei Liu trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count); 1718*60ce86c7SWei Liu 1719*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 1720*60ce86c7SWei Liu if (fidp == NULL) { 1721*60ce86c7SWei Liu err = -EINVAL; 1722*60ce86c7SWei Liu goto out_nofid; 1723*60ce86c7SWei Liu } 1724*60ce86c7SWei Liu if (fidp->fid_type == P9_FID_DIR) { 1725*60ce86c7SWei Liu 1726*60ce86c7SWei Liu if (off == 0) { 1727*60ce86c7SWei Liu v9fs_co_rewinddir(pdu, fidp); 1728*60ce86c7SWei Liu } 1729*60ce86c7SWei Liu count = v9fs_do_readdir_with_stat(pdu, fidp, max_count); 1730*60ce86c7SWei Liu if (count < 0) { 1731*60ce86c7SWei Liu err = count; 1732*60ce86c7SWei Liu goto out; 1733*60ce86c7SWei Liu } 1734*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "d", count); 1735*60ce86c7SWei Liu if (err < 0) { 1736*60ce86c7SWei Liu goto out; 1737*60ce86c7SWei Liu } 1738*60ce86c7SWei Liu err += offset + count; 1739*60ce86c7SWei Liu } else if (fidp->fid_type == P9_FID_FILE) { 1740*60ce86c7SWei Liu QEMUIOVector qiov_full; 1741*60ce86c7SWei Liu QEMUIOVector qiov; 1742*60ce86c7SWei Liu int32_t len; 1743*60ce86c7SWei Liu 1744*60ce86c7SWei Liu v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset + 4, max_count, false); 1745*60ce86c7SWei Liu qemu_iovec_init(&qiov, qiov_full.niov); 1746*60ce86c7SWei Liu do { 1747*60ce86c7SWei Liu qemu_iovec_reset(&qiov); 1748*60ce86c7SWei Liu qemu_iovec_concat(&qiov, &qiov_full, count, qiov_full.size - count); 1749*60ce86c7SWei Liu if (0) { 1750*60ce86c7SWei Liu print_sg(qiov.iov, qiov.niov); 1751*60ce86c7SWei Liu } 1752*60ce86c7SWei Liu /* Loop in case of EINTR */ 1753*60ce86c7SWei Liu do { 1754*60ce86c7SWei Liu len = v9fs_co_preadv(pdu, fidp, qiov.iov, qiov.niov, off); 1755*60ce86c7SWei Liu if (len >= 0) { 1756*60ce86c7SWei Liu off += len; 1757*60ce86c7SWei Liu count += len; 1758*60ce86c7SWei Liu } 1759*60ce86c7SWei Liu } while (len == -EINTR && !pdu->cancelled); 1760*60ce86c7SWei Liu if (len < 0) { 1761*60ce86c7SWei Liu /* IO error return the error */ 1762*60ce86c7SWei Liu err = len; 1763*60ce86c7SWei Liu goto out; 1764*60ce86c7SWei Liu } 1765*60ce86c7SWei Liu } while (count < max_count && len > 0); 1766*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "d", count); 1767*60ce86c7SWei Liu if (err < 0) { 1768*60ce86c7SWei Liu goto out; 1769*60ce86c7SWei Liu } 1770*60ce86c7SWei Liu err += offset + count; 1771*60ce86c7SWei Liu qemu_iovec_destroy(&qiov); 1772*60ce86c7SWei Liu qemu_iovec_destroy(&qiov_full); 1773*60ce86c7SWei Liu } else if (fidp->fid_type == P9_FID_XATTR) { 1774*60ce86c7SWei Liu err = v9fs_xattr_read(s, pdu, fidp, off, max_count); 1775*60ce86c7SWei Liu } else { 1776*60ce86c7SWei Liu err = -EINVAL; 1777*60ce86c7SWei Liu } 1778*60ce86c7SWei Liu trace_v9fs_read_return(pdu->tag, pdu->id, count, err); 1779*60ce86c7SWei Liu out: 1780*60ce86c7SWei Liu put_fid(pdu, fidp); 1781*60ce86c7SWei Liu out_nofid: 1782*60ce86c7SWei Liu pdu_complete(pdu, err); 1783*60ce86c7SWei Liu } 1784*60ce86c7SWei Liu 1785*60ce86c7SWei Liu static size_t v9fs_readdir_data_size(V9fsString *name) 1786*60ce86c7SWei Liu { 1787*60ce86c7SWei Liu /* 1788*60ce86c7SWei Liu * Size of each dirent on the wire: size of qid (13) + size of offset (8) 1789*60ce86c7SWei Liu * size of type (1) + size of name.size (2) + strlen(name.data) 1790*60ce86c7SWei Liu */ 1791*60ce86c7SWei Liu return 24 + v9fs_string_size(name); 1792*60ce86c7SWei Liu } 1793*60ce86c7SWei Liu 1794*60ce86c7SWei Liu static int v9fs_do_readdir(V9fsPDU *pdu, 1795*60ce86c7SWei Liu V9fsFidState *fidp, int32_t max_count) 1796*60ce86c7SWei Liu { 1797*60ce86c7SWei Liu size_t size; 1798*60ce86c7SWei Liu V9fsQID qid; 1799*60ce86c7SWei Liu V9fsString name; 1800*60ce86c7SWei Liu int len, err = 0; 1801*60ce86c7SWei Liu int32_t count = 0; 1802*60ce86c7SWei Liu off_t saved_dir_pos; 1803*60ce86c7SWei Liu struct dirent *dent, *result; 1804*60ce86c7SWei Liu 1805*60ce86c7SWei Liu /* save the directory position */ 1806*60ce86c7SWei Liu saved_dir_pos = v9fs_co_telldir(pdu, fidp); 1807*60ce86c7SWei Liu if (saved_dir_pos < 0) { 1808*60ce86c7SWei Liu return saved_dir_pos; 1809*60ce86c7SWei Liu } 1810*60ce86c7SWei Liu 1811*60ce86c7SWei Liu dent = g_malloc(sizeof(struct dirent)); 1812*60ce86c7SWei Liu 1813*60ce86c7SWei Liu while (1) { 1814*60ce86c7SWei Liu err = v9fs_co_readdir_r(pdu, fidp, dent, &result); 1815*60ce86c7SWei Liu if (err || !result) { 1816*60ce86c7SWei Liu break; 1817*60ce86c7SWei Liu } 1818*60ce86c7SWei Liu v9fs_string_init(&name); 1819*60ce86c7SWei Liu v9fs_string_sprintf(&name, "%s", dent->d_name); 1820*60ce86c7SWei Liu if ((count + v9fs_readdir_data_size(&name)) > max_count) { 1821*60ce86c7SWei Liu /* Ran out of buffer. Set dir back to old position and return */ 1822*60ce86c7SWei Liu v9fs_co_seekdir(pdu, fidp, saved_dir_pos); 1823*60ce86c7SWei Liu v9fs_string_free(&name); 1824*60ce86c7SWei Liu g_free(dent); 1825*60ce86c7SWei Liu return count; 1826*60ce86c7SWei Liu } 1827*60ce86c7SWei Liu /* 1828*60ce86c7SWei Liu * Fill up just the path field of qid because the client uses 1829*60ce86c7SWei Liu * only that. To fill the entire qid structure we will have 1830*60ce86c7SWei Liu * to stat each dirent found, which is expensive 1831*60ce86c7SWei Liu */ 1832*60ce86c7SWei Liu size = MIN(sizeof(dent->d_ino), sizeof(qid.path)); 1833*60ce86c7SWei Liu memcpy(&qid.path, &dent->d_ino, size); 1834*60ce86c7SWei Liu /* Fill the other fields with dummy values */ 1835*60ce86c7SWei Liu qid.type = 0; 1836*60ce86c7SWei Liu qid.version = 0; 1837*60ce86c7SWei Liu 1838*60ce86c7SWei Liu /* 11 = 7 + 4 (7 = start offset, 4 = space for storing count) */ 1839*60ce86c7SWei Liu len = pdu_marshal(pdu, 11 + count, "Qqbs", 1840*60ce86c7SWei Liu &qid, dent->d_off, 1841*60ce86c7SWei Liu dent->d_type, &name); 1842*60ce86c7SWei Liu if (len < 0) { 1843*60ce86c7SWei Liu v9fs_co_seekdir(pdu, fidp, saved_dir_pos); 1844*60ce86c7SWei Liu v9fs_string_free(&name); 1845*60ce86c7SWei Liu g_free(dent); 1846*60ce86c7SWei Liu return len; 1847*60ce86c7SWei Liu } 1848*60ce86c7SWei Liu count += len; 1849*60ce86c7SWei Liu v9fs_string_free(&name); 1850*60ce86c7SWei Liu saved_dir_pos = dent->d_off; 1851*60ce86c7SWei Liu } 1852*60ce86c7SWei Liu g_free(dent); 1853*60ce86c7SWei Liu if (err < 0) { 1854*60ce86c7SWei Liu return err; 1855*60ce86c7SWei Liu } 1856*60ce86c7SWei Liu return count; 1857*60ce86c7SWei Liu } 1858*60ce86c7SWei Liu 1859*60ce86c7SWei Liu static void v9fs_readdir(void *opaque) 1860*60ce86c7SWei Liu { 1861*60ce86c7SWei Liu int32_t fid; 1862*60ce86c7SWei Liu V9fsFidState *fidp; 1863*60ce86c7SWei Liu ssize_t retval = 0; 1864*60ce86c7SWei Liu size_t offset = 7; 1865*60ce86c7SWei Liu uint64_t initial_offset; 1866*60ce86c7SWei Liu int32_t count; 1867*60ce86c7SWei Liu uint32_t max_count; 1868*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 1869*60ce86c7SWei Liu 1870*60ce86c7SWei Liu retval = pdu_unmarshal(pdu, offset, "dqd", &fid, 1871*60ce86c7SWei Liu &initial_offset, &max_count); 1872*60ce86c7SWei Liu if (retval < 0) { 1873*60ce86c7SWei Liu goto out_nofid; 1874*60ce86c7SWei Liu } 1875*60ce86c7SWei Liu trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count); 1876*60ce86c7SWei Liu 1877*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 1878*60ce86c7SWei Liu if (fidp == NULL) { 1879*60ce86c7SWei Liu retval = -EINVAL; 1880*60ce86c7SWei Liu goto out_nofid; 1881*60ce86c7SWei Liu } 1882*60ce86c7SWei Liu if (!fidp->fs.dir) { 1883*60ce86c7SWei Liu retval = -EINVAL; 1884*60ce86c7SWei Liu goto out; 1885*60ce86c7SWei Liu } 1886*60ce86c7SWei Liu if (initial_offset == 0) { 1887*60ce86c7SWei Liu v9fs_co_rewinddir(pdu, fidp); 1888*60ce86c7SWei Liu } else { 1889*60ce86c7SWei Liu v9fs_co_seekdir(pdu, fidp, initial_offset); 1890*60ce86c7SWei Liu } 1891*60ce86c7SWei Liu count = v9fs_do_readdir(pdu, fidp, max_count); 1892*60ce86c7SWei Liu if (count < 0) { 1893*60ce86c7SWei Liu retval = count; 1894*60ce86c7SWei Liu goto out; 1895*60ce86c7SWei Liu } 1896*60ce86c7SWei Liu retval = pdu_marshal(pdu, offset, "d", count); 1897*60ce86c7SWei Liu if (retval < 0) { 1898*60ce86c7SWei Liu goto out; 1899*60ce86c7SWei Liu } 1900*60ce86c7SWei Liu retval += count + offset; 1901*60ce86c7SWei Liu trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval); 1902*60ce86c7SWei Liu out: 1903*60ce86c7SWei Liu put_fid(pdu, fidp); 1904*60ce86c7SWei Liu out_nofid: 1905*60ce86c7SWei Liu pdu_complete(pdu, retval); 1906*60ce86c7SWei Liu } 1907*60ce86c7SWei Liu 1908*60ce86c7SWei Liu static int v9fs_xattr_write(V9fsState *s, V9fsPDU *pdu, V9fsFidState *fidp, 1909*60ce86c7SWei Liu uint64_t off, uint32_t count, 1910*60ce86c7SWei Liu struct iovec *sg, int cnt) 1911*60ce86c7SWei Liu { 1912*60ce86c7SWei Liu int i, to_copy; 1913*60ce86c7SWei Liu ssize_t err = 0; 1914*60ce86c7SWei Liu int write_count; 1915*60ce86c7SWei Liu int64_t xattr_len; 1916*60ce86c7SWei Liu size_t offset = 7; 1917*60ce86c7SWei Liu 1918*60ce86c7SWei Liu 1919*60ce86c7SWei Liu xattr_len = fidp->fs.xattr.len; 1920*60ce86c7SWei Liu write_count = xattr_len - off; 1921*60ce86c7SWei Liu if (write_count > count) { 1922*60ce86c7SWei Liu write_count = count; 1923*60ce86c7SWei Liu } else if (write_count < 0) { 1924*60ce86c7SWei Liu /* 1925*60ce86c7SWei Liu * write beyond XATTR value len specified in 1926*60ce86c7SWei Liu * xattrcreate 1927*60ce86c7SWei Liu */ 1928*60ce86c7SWei Liu err = -ENOSPC; 1929*60ce86c7SWei Liu goto out; 1930*60ce86c7SWei Liu } 1931*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "d", write_count); 1932*60ce86c7SWei Liu if (err < 0) { 1933*60ce86c7SWei Liu return err; 1934*60ce86c7SWei Liu } 1935*60ce86c7SWei Liu err += offset; 1936*60ce86c7SWei Liu fidp->fs.xattr.copied_len += write_count; 1937*60ce86c7SWei Liu /* 1938*60ce86c7SWei Liu * Now copy the content from sg list 1939*60ce86c7SWei Liu */ 1940*60ce86c7SWei Liu for (i = 0; i < cnt; i++) { 1941*60ce86c7SWei Liu if (write_count > sg[i].iov_len) { 1942*60ce86c7SWei Liu to_copy = sg[i].iov_len; 1943*60ce86c7SWei Liu } else { 1944*60ce86c7SWei Liu to_copy = write_count; 1945*60ce86c7SWei Liu } 1946*60ce86c7SWei Liu memcpy((char *)fidp->fs.xattr.value + off, sg[i].iov_base, to_copy); 1947*60ce86c7SWei Liu /* updating vs->off since we are not using below */ 1948*60ce86c7SWei Liu off += to_copy; 1949*60ce86c7SWei Liu write_count -= to_copy; 1950*60ce86c7SWei Liu } 1951*60ce86c7SWei Liu out: 1952*60ce86c7SWei Liu return err; 1953*60ce86c7SWei Liu } 1954*60ce86c7SWei Liu 1955*60ce86c7SWei Liu static void v9fs_write(void *opaque) 1956*60ce86c7SWei Liu { 1957*60ce86c7SWei Liu ssize_t err; 1958*60ce86c7SWei Liu int32_t fid; 1959*60ce86c7SWei Liu uint64_t off; 1960*60ce86c7SWei Liu uint32_t count; 1961*60ce86c7SWei Liu int32_t len = 0; 1962*60ce86c7SWei Liu int32_t total = 0; 1963*60ce86c7SWei Liu size_t offset = 7; 1964*60ce86c7SWei Liu V9fsFidState *fidp; 1965*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 1966*60ce86c7SWei Liu V9fsState *s = pdu->s; 1967*60ce86c7SWei Liu QEMUIOVector qiov_full; 1968*60ce86c7SWei Liu QEMUIOVector qiov; 1969*60ce86c7SWei Liu 1970*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &count); 1971*60ce86c7SWei Liu if (err < 0) { 1972*60ce86c7SWei Liu pdu_complete(pdu, err); 1973*60ce86c7SWei Liu return; 1974*60ce86c7SWei Liu } 1975*60ce86c7SWei Liu offset += err; 1976*60ce86c7SWei Liu v9fs_init_qiov_from_pdu(&qiov_full, pdu, offset, count, true); 1977*60ce86c7SWei Liu trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, qiov_full.niov); 1978*60ce86c7SWei Liu 1979*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 1980*60ce86c7SWei Liu if (fidp == NULL) { 1981*60ce86c7SWei Liu err = -EINVAL; 1982*60ce86c7SWei Liu goto out_nofid; 1983*60ce86c7SWei Liu } 1984*60ce86c7SWei Liu if (fidp->fid_type == P9_FID_FILE) { 1985*60ce86c7SWei Liu if (fidp->fs.fd == -1) { 1986*60ce86c7SWei Liu err = -EINVAL; 1987*60ce86c7SWei Liu goto out; 1988*60ce86c7SWei Liu } 1989*60ce86c7SWei Liu } else if (fidp->fid_type == P9_FID_XATTR) { 1990*60ce86c7SWei Liu /* 1991*60ce86c7SWei Liu * setxattr operation 1992*60ce86c7SWei Liu */ 1993*60ce86c7SWei Liu err = v9fs_xattr_write(s, pdu, fidp, off, count, 1994*60ce86c7SWei Liu qiov_full.iov, qiov_full.niov); 1995*60ce86c7SWei Liu goto out; 1996*60ce86c7SWei Liu } else { 1997*60ce86c7SWei Liu err = -EINVAL; 1998*60ce86c7SWei Liu goto out; 1999*60ce86c7SWei Liu } 2000*60ce86c7SWei Liu qemu_iovec_init(&qiov, qiov_full.niov); 2001*60ce86c7SWei Liu do { 2002*60ce86c7SWei Liu qemu_iovec_reset(&qiov); 2003*60ce86c7SWei Liu qemu_iovec_concat(&qiov, &qiov_full, total, qiov_full.size - total); 2004*60ce86c7SWei Liu if (0) { 2005*60ce86c7SWei Liu print_sg(qiov.iov, qiov.niov); 2006*60ce86c7SWei Liu } 2007*60ce86c7SWei Liu /* Loop in case of EINTR */ 2008*60ce86c7SWei Liu do { 2009*60ce86c7SWei Liu len = v9fs_co_pwritev(pdu, fidp, qiov.iov, qiov.niov, off); 2010*60ce86c7SWei Liu if (len >= 0) { 2011*60ce86c7SWei Liu off += len; 2012*60ce86c7SWei Liu total += len; 2013*60ce86c7SWei Liu } 2014*60ce86c7SWei Liu } while (len == -EINTR && !pdu->cancelled); 2015*60ce86c7SWei Liu if (len < 0) { 2016*60ce86c7SWei Liu /* IO error return the error */ 2017*60ce86c7SWei Liu err = len; 2018*60ce86c7SWei Liu goto out_qiov; 2019*60ce86c7SWei Liu } 2020*60ce86c7SWei Liu } while (total < count && len > 0); 2021*60ce86c7SWei Liu 2022*60ce86c7SWei Liu offset = 7; 2023*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "d", total); 2024*60ce86c7SWei Liu if (err < 0) { 2025*60ce86c7SWei Liu goto out; 2026*60ce86c7SWei Liu } 2027*60ce86c7SWei Liu err += offset; 2028*60ce86c7SWei Liu trace_v9fs_write_return(pdu->tag, pdu->id, total, err); 2029*60ce86c7SWei Liu out_qiov: 2030*60ce86c7SWei Liu qemu_iovec_destroy(&qiov); 2031*60ce86c7SWei Liu out: 2032*60ce86c7SWei Liu put_fid(pdu, fidp); 2033*60ce86c7SWei Liu out_nofid: 2034*60ce86c7SWei Liu qemu_iovec_destroy(&qiov_full); 2035*60ce86c7SWei Liu pdu_complete(pdu, err); 2036*60ce86c7SWei Liu } 2037*60ce86c7SWei Liu 2038*60ce86c7SWei Liu static void v9fs_create(void *opaque) 2039*60ce86c7SWei Liu { 2040*60ce86c7SWei Liu int32_t fid; 2041*60ce86c7SWei Liu int err = 0; 2042*60ce86c7SWei Liu size_t offset = 7; 2043*60ce86c7SWei Liu V9fsFidState *fidp; 2044*60ce86c7SWei Liu V9fsQID qid; 2045*60ce86c7SWei Liu int32_t perm; 2046*60ce86c7SWei Liu int8_t mode; 2047*60ce86c7SWei Liu V9fsPath path; 2048*60ce86c7SWei Liu struct stat stbuf; 2049*60ce86c7SWei Liu V9fsString name; 2050*60ce86c7SWei Liu V9fsString extension; 2051*60ce86c7SWei Liu int iounit; 2052*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 2053*60ce86c7SWei Liu 2054*60ce86c7SWei Liu v9fs_path_init(&path); 2055*60ce86c7SWei Liu v9fs_string_init(&name); 2056*60ce86c7SWei Liu v9fs_string_init(&extension); 2057*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name, 2058*60ce86c7SWei Liu &perm, &mode, &extension); 2059*60ce86c7SWei Liu if (err < 0) { 2060*60ce86c7SWei Liu goto out_nofid; 2061*60ce86c7SWei Liu } 2062*60ce86c7SWei Liu trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode); 2063*60ce86c7SWei Liu 2064*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 2065*60ce86c7SWei Liu if (fidp == NULL) { 2066*60ce86c7SWei Liu err = -EINVAL; 2067*60ce86c7SWei Liu goto out_nofid; 2068*60ce86c7SWei Liu } 2069*60ce86c7SWei Liu if (perm & P9_STAT_MODE_DIR) { 2070*60ce86c7SWei Liu err = v9fs_co_mkdir(pdu, fidp, &name, perm & 0777, 2071*60ce86c7SWei Liu fidp->uid, -1, &stbuf); 2072*60ce86c7SWei Liu if (err < 0) { 2073*60ce86c7SWei Liu goto out; 2074*60ce86c7SWei Liu } 2075*60ce86c7SWei Liu err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path); 2076*60ce86c7SWei Liu if (err < 0) { 2077*60ce86c7SWei Liu goto out; 2078*60ce86c7SWei Liu } 2079*60ce86c7SWei Liu v9fs_path_copy(&fidp->path, &path); 2080*60ce86c7SWei Liu err = v9fs_co_opendir(pdu, fidp); 2081*60ce86c7SWei Liu if (err < 0) { 2082*60ce86c7SWei Liu goto out; 2083*60ce86c7SWei Liu } 2084*60ce86c7SWei Liu fidp->fid_type = P9_FID_DIR; 2085*60ce86c7SWei Liu } else if (perm & P9_STAT_MODE_SYMLINK) { 2086*60ce86c7SWei Liu err = v9fs_co_symlink(pdu, fidp, &name, 2087*60ce86c7SWei Liu extension.data, -1 , &stbuf); 2088*60ce86c7SWei Liu if (err < 0) { 2089*60ce86c7SWei Liu goto out; 2090*60ce86c7SWei Liu } 2091*60ce86c7SWei Liu err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path); 2092*60ce86c7SWei Liu if (err < 0) { 2093*60ce86c7SWei Liu goto out; 2094*60ce86c7SWei Liu } 2095*60ce86c7SWei Liu v9fs_path_copy(&fidp->path, &path); 2096*60ce86c7SWei Liu } else if (perm & P9_STAT_MODE_LINK) { 2097*60ce86c7SWei Liu int32_t ofid = atoi(extension.data); 2098*60ce86c7SWei Liu V9fsFidState *ofidp = get_fid(pdu, ofid); 2099*60ce86c7SWei Liu if (ofidp == NULL) { 2100*60ce86c7SWei Liu err = -EINVAL; 2101*60ce86c7SWei Liu goto out; 2102*60ce86c7SWei Liu } 2103*60ce86c7SWei Liu err = v9fs_co_link(pdu, ofidp, fidp, &name); 2104*60ce86c7SWei Liu put_fid(pdu, ofidp); 2105*60ce86c7SWei Liu if (err < 0) { 2106*60ce86c7SWei Liu goto out; 2107*60ce86c7SWei Liu } 2108*60ce86c7SWei Liu err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path); 2109*60ce86c7SWei Liu if (err < 0) { 2110*60ce86c7SWei Liu fidp->fid_type = P9_FID_NONE; 2111*60ce86c7SWei Liu goto out; 2112*60ce86c7SWei Liu } 2113*60ce86c7SWei Liu v9fs_path_copy(&fidp->path, &path); 2114*60ce86c7SWei Liu err = v9fs_co_lstat(pdu, &fidp->path, &stbuf); 2115*60ce86c7SWei Liu if (err < 0) { 2116*60ce86c7SWei Liu fidp->fid_type = P9_FID_NONE; 2117*60ce86c7SWei Liu goto out; 2118*60ce86c7SWei Liu } 2119*60ce86c7SWei Liu } else if (perm & P9_STAT_MODE_DEVICE) { 2120*60ce86c7SWei Liu char ctype; 2121*60ce86c7SWei Liu uint32_t major, minor; 2122*60ce86c7SWei Liu mode_t nmode = 0; 2123*60ce86c7SWei Liu 2124*60ce86c7SWei Liu if (sscanf(extension.data, "%c %u %u", &ctype, &major, &minor) != 3) { 2125*60ce86c7SWei Liu err = -errno; 2126*60ce86c7SWei Liu goto out; 2127*60ce86c7SWei Liu } 2128*60ce86c7SWei Liu 2129*60ce86c7SWei Liu switch (ctype) { 2130*60ce86c7SWei Liu case 'c': 2131*60ce86c7SWei Liu nmode = S_IFCHR; 2132*60ce86c7SWei Liu break; 2133*60ce86c7SWei Liu case 'b': 2134*60ce86c7SWei Liu nmode = S_IFBLK; 2135*60ce86c7SWei Liu break; 2136*60ce86c7SWei Liu default: 2137*60ce86c7SWei Liu err = -EIO; 2138*60ce86c7SWei Liu goto out; 2139*60ce86c7SWei Liu } 2140*60ce86c7SWei Liu 2141*60ce86c7SWei Liu nmode |= perm & 0777; 2142*60ce86c7SWei Liu err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1, 2143*60ce86c7SWei Liu makedev(major, minor), nmode, &stbuf); 2144*60ce86c7SWei Liu if (err < 0) { 2145*60ce86c7SWei Liu goto out; 2146*60ce86c7SWei Liu } 2147*60ce86c7SWei Liu err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path); 2148*60ce86c7SWei Liu if (err < 0) { 2149*60ce86c7SWei Liu goto out; 2150*60ce86c7SWei Liu } 2151*60ce86c7SWei Liu v9fs_path_copy(&fidp->path, &path); 2152*60ce86c7SWei Liu } else if (perm & P9_STAT_MODE_NAMED_PIPE) { 2153*60ce86c7SWei Liu err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1, 2154*60ce86c7SWei Liu 0, S_IFIFO | (perm & 0777), &stbuf); 2155*60ce86c7SWei Liu if (err < 0) { 2156*60ce86c7SWei Liu goto out; 2157*60ce86c7SWei Liu } 2158*60ce86c7SWei Liu err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path); 2159*60ce86c7SWei Liu if (err < 0) { 2160*60ce86c7SWei Liu goto out; 2161*60ce86c7SWei Liu } 2162*60ce86c7SWei Liu v9fs_path_copy(&fidp->path, &path); 2163*60ce86c7SWei Liu } else if (perm & P9_STAT_MODE_SOCKET) { 2164*60ce86c7SWei Liu err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, -1, 2165*60ce86c7SWei Liu 0, S_IFSOCK | (perm & 0777), &stbuf); 2166*60ce86c7SWei Liu if (err < 0) { 2167*60ce86c7SWei Liu goto out; 2168*60ce86c7SWei Liu } 2169*60ce86c7SWei Liu err = v9fs_co_name_to_path(pdu, &fidp->path, name.data, &path); 2170*60ce86c7SWei Liu if (err < 0) { 2171*60ce86c7SWei Liu goto out; 2172*60ce86c7SWei Liu } 2173*60ce86c7SWei Liu v9fs_path_copy(&fidp->path, &path); 2174*60ce86c7SWei Liu } else { 2175*60ce86c7SWei Liu err = v9fs_co_open2(pdu, fidp, &name, -1, 2176*60ce86c7SWei Liu omode_to_uflags(mode)|O_CREAT, perm, &stbuf); 2177*60ce86c7SWei Liu if (err < 0) { 2178*60ce86c7SWei Liu goto out; 2179*60ce86c7SWei Liu } 2180*60ce86c7SWei Liu fidp->fid_type = P9_FID_FILE; 2181*60ce86c7SWei Liu fidp->open_flags = omode_to_uflags(mode); 2182*60ce86c7SWei Liu if (fidp->open_flags & O_EXCL) { 2183*60ce86c7SWei Liu /* 2184*60ce86c7SWei Liu * We let the host file system do O_EXCL check 2185*60ce86c7SWei Liu * We should not reclaim such fd 2186*60ce86c7SWei Liu */ 2187*60ce86c7SWei Liu fidp->flags |= FID_NON_RECLAIMABLE; 2188*60ce86c7SWei Liu } 2189*60ce86c7SWei Liu } 2190*60ce86c7SWei Liu iounit = get_iounit(pdu, &fidp->path); 2191*60ce86c7SWei Liu stat_to_qid(&stbuf, &qid); 2192*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "Qd", &qid, iounit); 2193*60ce86c7SWei Liu if (err < 0) { 2194*60ce86c7SWei Liu goto out; 2195*60ce86c7SWei Liu } 2196*60ce86c7SWei Liu err += offset; 2197*60ce86c7SWei Liu trace_v9fs_create_return(pdu->tag, pdu->id, 2198*60ce86c7SWei Liu qid.type, qid.version, qid.path, iounit); 2199*60ce86c7SWei Liu out: 2200*60ce86c7SWei Liu put_fid(pdu, fidp); 2201*60ce86c7SWei Liu out_nofid: 2202*60ce86c7SWei Liu pdu_complete(pdu, err); 2203*60ce86c7SWei Liu v9fs_string_free(&name); 2204*60ce86c7SWei Liu v9fs_string_free(&extension); 2205*60ce86c7SWei Liu v9fs_path_free(&path); 2206*60ce86c7SWei Liu } 2207*60ce86c7SWei Liu 2208*60ce86c7SWei Liu static void v9fs_symlink(void *opaque) 2209*60ce86c7SWei Liu { 2210*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 2211*60ce86c7SWei Liu V9fsString name; 2212*60ce86c7SWei Liu V9fsString symname; 2213*60ce86c7SWei Liu V9fsFidState *dfidp; 2214*60ce86c7SWei Liu V9fsQID qid; 2215*60ce86c7SWei Liu struct stat stbuf; 2216*60ce86c7SWei Liu int32_t dfid; 2217*60ce86c7SWei Liu int err = 0; 2218*60ce86c7SWei Liu gid_t gid; 2219*60ce86c7SWei Liu size_t offset = 7; 2220*60ce86c7SWei Liu 2221*60ce86c7SWei Liu v9fs_string_init(&name); 2222*60ce86c7SWei Liu v9fs_string_init(&symname); 2223*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid); 2224*60ce86c7SWei Liu if (err < 0) { 2225*60ce86c7SWei Liu goto out_nofid; 2226*60ce86c7SWei Liu } 2227*60ce86c7SWei Liu trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid); 2228*60ce86c7SWei Liu 2229*60ce86c7SWei Liu dfidp = get_fid(pdu, dfid); 2230*60ce86c7SWei Liu if (dfidp == NULL) { 2231*60ce86c7SWei Liu err = -EINVAL; 2232*60ce86c7SWei Liu goto out_nofid; 2233*60ce86c7SWei Liu } 2234*60ce86c7SWei Liu err = v9fs_co_symlink(pdu, dfidp, &name, symname.data, gid, &stbuf); 2235*60ce86c7SWei Liu if (err < 0) { 2236*60ce86c7SWei Liu goto out; 2237*60ce86c7SWei Liu } 2238*60ce86c7SWei Liu stat_to_qid(&stbuf, &qid); 2239*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "Q", &qid); 2240*60ce86c7SWei Liu if (err < 0) { 2241*60ce86c7SWei Liu goto out; 2242*60ce86c7SWei Liu } 2243*60ce86c7SWei Liu err += offset; 2244*60ce86c7SWei Liu trace_v9fs_symlink_return(pdu->tag, pdu->id, 2245*60ce86c7SWei Liu qid.type, qid.version, qid.path); 2246*60ce86c7SWei Liu out: 2247*60ce86c7SWei Liu put_fid(pdu, dfidp); 2248*60ce86c7SWei Liu out_nofid: 2249*60ce86c7SWei Liu pdu_complete(pdu, err); 2250*60ce86c7SWei Liu v9fs_string_free(&name); 2251*60ce86c7SWei Liu v9fs_string_free(&symname); 2252*60ce86c7SWei Liu } 2253*60ce86c7SWei Liu 2254*60ce86c7SWei Liu static void v9fs_flush(void *opaque) 2255*60ce86c7SWei Liu { 2256*60ce86c7SWei Liu ssize_t err; 2257*60ce86c7SWei Liu int16_t tag; 2258*60ce86c7SWei Liu size_t offset = 7; 2259*60ce86c7SWei Liu V9fsPDU *cancel_pdu; 2260*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 2261*60ce86c7SWei Liu V9fsState *s = pdu->s; 2262*60ce86c7SWei Liu 2263*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "w", &tag); 2264*60ce86c7SWei Liu if (err < 0) { 2265*60ce86c7SWei Liu pdu_complete(pdu, err); 2266*60ce86c7SWei Liu return; 2267*60ce86c7SWei Liu } 2268*60ce86c7SWei Liu trace_v9fs_flush(pdu->tag, pdu->id, tag); 2269*60ce86c7SWei Liu 2270*60ce86c7SWei Liu QLIST_FOREACH(cancel_pdu, &s->active_list, next) { 2271*60ce86c7SWei Liu if (cancel_pdu->tag == tag) { 2272*60ce86c7SWei Liu break; 2273*60ce86c7SWei Liu } 2274*60ce86c7SWei Liu } 2275*60ce86c7SWei Liu if (cancel_pdu) { 2276*60ce86c7SWei Liu cancel_pdu->cancelled = 1; 2277*60ce86c7SWei Liu /* 2278*60ce86c7SWei Liu * Wait for pdu to complete. 2279*60ce86c7SWei Liu */ 2280*60ce86c7SWei Liu qemu_co_queue_wait(&cancel_pdu->complete); 2281*60ce86c7SWei Liu cancel_pdu->cancelled = 0; 2282*60ce86c7SWei Liu pdu_free(cancel_pdu); 2283*60ce86c7SWei Liu } 2284*60ce86c7SWei Liu pdu_complete(pdu, 7); 2285*60ce86c7SWei Liu } 2286*60ce86c7SWei Liu 2287*60ce86c7SWei Liu static void v9fs_link(void *opaque) 2288*60ce86c7SWei Liu { 2289*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 2290*60ce86c7SWei Liu int32_t dfid, oldfid; 2291*60ce86c7SWei Liu V9fsFidState *dfidp, *oldfidp; 2292*60ce86c7SWei Liu V9fsString name; 2293*60ce86c7SWei Liu size_t offset = 7; 2294*60ce86c7SWei Liu int err = 0; 2295*60ce86c7SWei Liu 2296*60ce86c7SWei Liu v9fs_string_init(&name); 2297*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name); 2298*60ce86c7SWei Liu if (err < 0) { 2299*60ce86c7SWei Liu goto out_nofid; 2300*60ce86c7SWei Liu } 2301*60ce86c7SWei Liu trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data); 2302*60ce86c7SWei Liu 2303*60ce86c7SWei Liu dfidp = get_fid(pdu, dfid); 2304*60ce86c7SWei Liu if (dfidp == NULL) { 2305*60ce86c7SWei Liu err = -ENOENT; 2306*60ce86c7SWei Liu goto out_nofid; 2307*60ce86c7SWei Liu } 2308*60ce86c7SWei Liu 2309*60ce86c7SWei Liu oldfidp = get_fid(pdu, oldfid); 2310*60ce86c7SWei Liu if (oldfidp == NULL) { 2311*60ce86c7SWei Liu err = -ENOENT; 2312*60ce86c7SWei Liu goto out; 2313*60ce86c7SWei Liu } 2314*60ce86c7SWei Liu err = v9fs_co_link(pdu, oldfidp, dfidp, &name); 2315*60ce86c7SWei Liu if (!err) { 2316*60ce86c7SWei Liu err = offset; 2317*60ce86c7SWei Liu } 2318*60ce86c7SWei Liu out: 2319*60ce86c7SWei Liu put_fid(pdu, dfidp); 2320*60ce86c7SWei Liu out_nofid: 2321*60ce86c7SWei Liu v9fs_string_free(&name); 2322*60ce86c7SWei Liu pdu_complete(pdu, err); 2323*60ce86c7SWei Liu } 2324*60ce86c7SWei Liu 2325*60ce86c7SWei Liu /* Only works with path name based fid */ 2326*60ce86c7SWei Liu static void v9fs_remove(void *opaque) 2327*60ce86c7SWei Liu { 2328*60ce86c7SWei Liu int32_t fid; 2329*60ce86c7SWei Liu int err = 0; 2330*60ce86c7SWei Liu size_t offset = 7; 2331*60ce86c7SWei Liu V9fsFidState *fidp; 2332*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 2333*60ce86c7SWei Liu 2334*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "d", &fid); 2335*60ce86c7SWei Liu if (err < 0) { 2336*60ce86c7SWei Liu goto out_nofid; 2337*60ce86c7SWei Liu } 2338*60ce86c7SWei Liu trace_v9fs_remove(pdu->tag, pdu->id, fid); 2339*60ce86c7SWei Liu 2340*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 2341*60ce86c7SWei Liu if (fidp == NULL) { 2342*60ce86c7SWei Liu err = -EINVAL; 2343*60ce86c7SWei Liu goto out_nofid; 2344*60ce86c7SWei Liu } 2345*60ce86c7SWei Liu /* if fs driver is not path based, return EOPNOTSUPP */ 2346*60ce86c7SWei Liu if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) { 2347*60ce86c7SWei Liu err = -EOPNOTSUPP; 2348*60ce86c7SWei Liu goto out_err; 2349*60ce86c7SWei Liu } 2350*60ce86c7SWei Liu /* 2351*60ce86c7SWei Liu * IF the file is unlinked, we cannot reopen 2352*60ce86c7SWei Liu * the file later. So don't reclaim fd 2353*60ce86c7SWei Liu */ 2354*60ce86c7SWei Liu err = v9fs_mark_fids_unreclaim(pdu, &fidp->path); 2355*60ce86c7SWei Liu if (err < 0) { 2356*60ce86c7SWei Liu goto out_err; 2357*60ce86c7SWei Liu } 2358*60ce86c7SWei Liu err = v9fs_co_remove(pdu, &fidp->path); 2359*60ce86c7SWei Liu if (!err) { 2360*60ce86c7SWei Liu err = offset; 2361*60ce86c7SWei Liu } 2362*60ce86c7SWei Liu out_err: 2363*60ce86c7SWei Liu /* For TREMOVE we need to clunk the fid even on failed remove */ 2364*60ce86c7SWei Liu clunk_fid(pdu->s, fidp->fid); 2365*60ce86c7SWei Liu put_fid(pdu, fidp); 2366*60ce86c7SWei Liu out_nofid: 2367*60ce86c7SWei Liu pdu_complete(pdu, err); 2368*60ce86c7SWei Liu } 2369*60ce86c7SWei Liu 2370*60ce86c7SWei Liu static void v9fs_unlinkat(void *opaque) 2371*60ce86c7SWei Liu { 2372*60ce86c7SWei Liu int err = 0; 2373*60ce86c7SWei Liu V9fsString name; 2374*60ce86c7SWei Liu int32_t dfid, flags; 2375*60ce86c7SWei Liu size_t offset = 7; 2376*60ce86c7SWei Liu V9fsPath path; 2377*60ce86c7SWei Liu V9fsFidState *dfidp; 2378*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 2379*60ce86c7SWei Liu 2380*60ce86c7SWei Liu v9fs_string_init(&name); 2381*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags); 2382*60ce86c7SWei Liu if (err < 0) { 2383*60ce86c7SWei Liu goto out_nofid; 2384*60ce86c7SWei Liu } 2385*60ce86c7SWei Liu dfidp = get_fid(pdu, dfid); 2386*60ce86c7SWei Liu if (dfidp == NULL) { 2387*60ce86c7SWei Liu err = -EINVAL; 2388*60ce86c7SWei Liu goto out_nofid; 2389*60ce86c7SWei Liu } 2390*60ce86c7SWei Liu /* 2391*60ce86c7SWei Liu * IF the file is unlinked, we cannot reopen 2392*60ce86c7SWei Liu * the file later. So don't reclaim fd 2393*60ce86c7SWei Liu */ 2394*60ce86c7SWei Liu v9fs_path_init(&path); 2395*60ce86c7SWei Liu err = v9fs_co_name_to_path(pdu, &dfidp->path, name.data, &path); 2396*60ce86c7SWei Liu if (err < 0) { 2397*60ce86c7SWei Liu goto out_err; 2398*60ce86c7SWei Liu } 2399*60ce86c7SWei Liu err = v9fs_mark_fids_unreclaim(pdu, &path); 2400*60ce86c7SWei Liu if (err < 0) { 2401*60ce86c7SWei Liu goto out_err; 2402*60ce86c7SWei Liu } 2403*60ce86c7SWei Liu err = v9fs_co_unlinkat(pdu, &dfidp->path, &name, flags); 2404*60ce86c7SWei Liu if (!err) { 2405*60ce86c7SWei Liu err = offset; 2406*60ce86c7SWei Liu } 2407*60ce86c7SWei Liu out_err: 2408*60ce86c7SWei Liu put_fid(pdu, dfidp); 2409*60ce86c7SWei Liu v9fs_path_free(&path); 2410*60ce86c7SWei Liu out_nofid: 2411*60ce86c7SWei Liu pdu_complete(pdu, err); 2412*60ce86c7SWei Liu v9fs_string_free(&name); 2413*60ce86c7SWei Liu } 2414*60ce86c7SWei Liu 2415*60ce86c7SWei Liu 2416*60ce86c7SWei Liu /* Only works with path name based fid */ 2417*60ce86c7SWei Liu static int v9fs_complete_rename(V9fsPDU *pdu, V9fsFidState *fidp, 2418*60ce86c7SWei Liu int32_t newdirfid, V9fsString *name) 2419*60ce86c7SWei Liu { 2420*60ce86c7SWei Liu char *end; 2421*60ce86c7SWei Liu int err = 0; 2422*60ce86c7SWei Liu V9fsPath new_path; 2423*60ce86c7SWei Liu V9fsFidState *tfidp; 2424*60ce86c7SWei Liu V9fsState *s = pdu->s; 2425*60ce86c7SWei Liu V9fsFidState *dirfidp = NULL; 2426*60ce86c7SWei Liu char *old_name, *new_name; 2427*60ce86c7SWei Liu 2428*60ce86c7SWei Liu v9fs_path_init(&new_path); 2429*60ce86c7SWei Liu if (newdirfid != -1) { 2430*60ce86c7SWei Liu dirfidp = get_fid(pdu, newdirfid); 2431*60ce86c7SWei Liu if (dirfidp == NULL) { 2432*60ce86c7SWei Liu err = -ENOENT; 2433*60ce86c7SWei Liu goto out_nofid; 2434*60ce86c7SWei Liu } 2435*60ce86c7SWei Liu BUG_ON(dirfidp->fid_type != P9_FID_NONE); 2436*60ce86c7SWei Liu v9fs_co_name_to_path(pdu, &dirfidp->path, name->data, &new_path); 2437*60ce86c7SWei Liu } else { 2438*60ce86c7SWei Liu old_name = fidp->path.data; 2439*60ce86c7SWei Liu end = strrchr(old_name, '/'); 2440*60ce86c7SWei Liu if (end) { 2441*60ce86c7SWei Liu end++; 2442*60ce86c7SWei Liu } else { 2443*60ce86c7SWei Liu end = old_name; 2444*60ce86c7SWei Liu } 2445*60ce86c7SWei Liu new_name = g_malloc0(end - old_name + name->size + 1); 2446*60ce86c7SWei Liu strncat(new_name, old_name, end - old_name); 2447*60ce86c7SWei Liu strncat(new_name + (end - old_name), name->data, name->size); 2448*60ce86c7SWei Liu v9fs_co_name_to_path(pdu, NULL, new_name, &new_path); 2449*60ce86c7SWei Liu g_free(new_name); 2450*60ce86c7SWei Liu } 2451*60ce86c7SWei Liu err = v9fs_co_rename(pdu, &fidp->path, &new_path); 2452*60ce86c7SWei Liu if (err < 0) { 2453*60ce86c7SWei Liu goto out; 2454*60ce86c7SWei Liu } 2455*60ce86c7SWei Liu /* 2456*60ce86c7SWei Liu * Fixup fid's pointing to the old name to 2457*60ce86c7SWei Liu * start pointing to the new name 2458*60ce86c7SWei Liu */ 2459*60ce86c7SWei Liu for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) { 2460*60ce86c7SWei Liu if (v9fs_path_is_ancestor(&fidp->path, &tfidp->path)) { 2461*60ce86c7SWei Liu /* replace the name */ 2462*60ce86c7SWei Liu v9fs_fix_path(&tfidp->path, &new_path, strlen(fidp->path.data)); 2463*60ce86c7SWei Liu } 2464*60ce86c7SWei Liu } 2465*60ce86c7SWei Liu out: 2466*60ce86c7SWei Liu if (dirfidp) { 2467*60ce86c7SWei Liu put_fid(pdu, dirfidp); 2468*60ce86c7SWei Liu } 2469*60ce86c7SWei Liu v9fs_path_free(&new_path); 2470*60ce86c7SWei Liu out_nofid: 2471*60ce86c7SWei Liu return err; 2472*60ce86c7SWei Liu } 2473*60ce86c7SWei Liu 2474*60ce86c7SWei Liu /* Only works with path name based fid */ 2475*60ce86c7SWei Liu static void v9fs_rename(void *opaque) 2476*60ce86c7SWei Liu { 2477*60ce86c7SWei Liu int32_t fid; 2478*60ce86c7SWei Liu ssize_t err = 0; 2479*60ce86c7SWei Liu size_t offset = 7; 2480*60ce86c7SWei Liu V9fsString name; 2481*60ce86c7SWei Liu int32_t newdirfid; 2482*60ce86c7SWei Liu V9fsFidState *fidp; 2483*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 2484*60ce86c7SWei Liu V9fsState *s = pdu->s; 2485*60ce86c7SWei Liu 2486*60ce86c7SWei Liu v9fs_string_init(&name); 2487*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dds", &fid, &newdirfid, &name); 2488*60ce86c7SWei Liu if (err < 0) { 2489*60ce86c7SWei Liu goto out_nofid; 2490*60ce86c7SWei Liu } 2491*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 2492*60ce86c7SWei Liu if (fidp == NULL) { 2493*60ce86c7SWei Liu err = -ENOENT; 2494*60ce86c7SWei Liu goto out_nofid; 2495*60ce86c7SWei Liu } 2496*60ce86c7SWei Liu BUG_ON(fidp->fid_type != P9_FID_NONE); 2497*60ce86c7SWei Liu /* if fs driver is not path based, return EOPNOTSUPP */ 2498*60ce86c7SWei Liu if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) { 2499*60ce86c7SWei Liu err = -EOPNOTSUPP; 2500*60ce86c7SWei Liu goto out; 2501*60ce86c7SWei Liu } 2502*60ce86c7SWei Liu v9fs_path_write_lock(s); 2503*60ce86c7SWei Liu err = v9fs_complete_rename(pdu, fidp, newdirfid, &name); 2504*60ce86c7SWei Liu v9fs_path_unlock(s); 2505*60ce86c7SWei Liu if (!err) { 2506*60ce86c7SWei Liu err = offset; 2507*60ce86c7SWei Liu } 2508*60ce86c7SWei Liu out: 2509*60ce86c7SWei Liu put_fid(pdu, fidp); 2510*60ce86c7SWei Liu out_nofid: 2511*60ce86c7SWei Liu pdu_complete(pdu, err); 2512*60ce86c7SWei Liu v9fs_string_free(&name); 2513*60ce86c7SWei Liu } 2514*60ce86c7SWei Liu 2515*60ce86c7SWei Liu static void v9fs_fix_fid_paths(V9fsPDU *pdu, V9fsPath *olddir, 2516*60ce86c7SWei Liu V9fsString *old_name, V9fsPath *newdir, 2517*60ce86c7SWei Liu V9fsString *new_name) 2518*60ce86c7SWei Liu { 2519*60ce86c7SWei Liu V9fsFidState *tfidp; 2520*60ce86c7SWei Liu V9fsPath oldpath, newpath; 2521*60ce86c7SWei Liu V9fsState *s = pdu->s; 2522*60ce86c7SWei Liu 2523*60ce86c7SWei Liu 2524*60ce86c7SWei Liu v9fs_path_init(&oldpath); 2525*60ce86c7SWei Liu v9fs_path_init(&newpath); 2526*60ce86c7SWei Liu v9fs_co_name_to_path(pdu, olddir, old_name->data, &oldpath); 2527*60ce86c7SWei Liu v9fs_co_name_to_path(pdu, newdir, new_name->data, &newpath); 2528*60ce86c7SWei Liu 2529*60ce86c7SWei Liu /* 2530*60ce86c7SWei Liu * Fixup fid's pointing to the old name to 2531*60ce86c7SWei Liu * start pointing to the new name 2532*60ce86c7SWei Liu */ 2533*60ce86c7SWei Liu for (tfidp = s->fid_list; tfidp; tfidp = tfidp->next) { 2534*60ce86c7SWei Liu if (v9fs_path_is_ancestor(&oldpath, &tfidp->path)) { 2535*60ce86c7SWei Liu /* replace the name */ 2536*60ce86c7SWei Liu v9fs_fix_path(&tfidp->path, &newpath, strlen(oldpath.data)); 2537*60ce86c7SWei Liu } 2538*60ce86c7SWei Liu } 2539*60ce86c7SWei Liu v9fs_path_free(&oldpath); 2540*60ce86c7SWei Liu v9fs_path_free(&newpath); 2541*60ce86c7SWei Liu } 2542*60ce86c7SWei Liu 2543*60ce86c7SWei Liu static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid, 2544*60ce86c7SWei Liu V9fsString *old_name, int32_t newdirfid, 2545*60ce86c7SWei Liu V9fsString *new_name) 2546*60ce86c7SWei Liu { 2547*60ce86c7SWei Liu int err = 0; 2548*60ce86c7SWei Liu V9fsState *s = pdu->s; 2549*60ce86c7SWei Liu V9fsFidState *newdirfidp = NULL, *olddirfidp = NULL; 2550*60ce86c7SWei Liu 2551*60ce86c7SWei Liu olddirfidp = get_fid(pdu, olddirfid); 2552*60ce86c7SWei Liu if (olddirfidp == NULL) { 2553*60ce86c7SWei Liu err = -ENOENT; 2554*60ce86c7SWei Liu goto out; 2555*60ce86c7SWei Liu } 2556*60ce86c7SWei Liu if (newdirfid != -1) { 2557*60ce86c7SWei Liu newdirfidp = get_fid(pdu, newdirfid); 2558*60ce86c7SWei Liu if (newdirfidp == NULL) { 2559*60ce86c7SWei Liu err = -ENOENT; 2560*60ce86c7SWei Liu goto out; 2561*60ce86c7SWei Liu } 2562*60ce86c7SWei Liu } else { 2563*60ce86c7SWei Liu newdirfidp = get_fid(pdu, olddirfid); 2564*60ce86c7SWei Liu } 2565*60ce86c7SWei Liu 2566*60ce86c7SWei Liu err = v9fs_co_renameat(pdu, &olddirfidp->path, old_name, 2567*60ce86c7SWei Liu &newdirfidp->path, new_name); 2568*60ce86c7SWei Liu if (err < 0) { 2569*60ce86c7SWei Liu goto out; 2570*60ce86c7SWei Liu } 2571*60ce86c7SWei Liu if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { 2572*60ce86c7SWei Liu /* Only for path based fid we need to do the below fixup */ 2573*60ce86c7SWei Liu v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name, 2574*60ce86c7SWei Liu &newdirfidp->path, new_name); 2575*60ce86c7SWei Liu } 2576*60ce86c7SWei Liu out: 2577*60ce86c7SWei Liu if (olddirfidp) { 2578*60ce86c7SWei Liu put_fid(pdu, olddirfidp); 2579*60ce86c7SWei Liu } 2580*60ce86c7SWei Liu if (newdirfidp) { 2581*60ce86c7SWei Liu put_fid(pdu, newdirfidp); 2582*60ce86c7SWei Liu } 2583*60ce86c7SWei Liu return err; 2584*60ce86c7SWei Liu } 2585*60ce86c7SWei Liu 2586*60ce86c7SWei Liu static void v9fs_renameat(void *opaque) 2587*60ce86c7SWei Liu { 2588*60ce86c7SWei Liu ssize_t err = 0; 2589*60ce86c7SWei Liu size_t offset = 7; 2590*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 2591*60ce86c7SWei Liu V9fsState *s = pdu->s; 2592*60ce86c7SWei Liu int32_t olddirfid, newdirfid; 2593*60ce86c7SWei Liu V9fsString old_name, new_name; 2594*60ce86c7SWei Liu 2595*60ce86c7SWei Liu v9fs_string_init(&old_name); 2596*60ce86c7SWei Liu v9fs_string_init(&new_name); 2597*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dsds", &olddirfid, 2598*60ce86c7SWei Liu &old_name, &newdirfid, &new_name); 2599*60ce86c7SWei Liu if (err < 0) { 2600*60ce86c7SWei Liu goto out_err; 2601*60ce86c7SWei Liu } 2602*60ce86c7SWei Liu 2603*60ce86c7SWei Liu v9fs_path_write_lock(s); 2604*60ce86c7SWei Liu err = v9fs_complete_renameat(pdu, olddirfid, 2605*60ce86c7SWei Liu &old_name, newdirfid, &new_name); 2606*60ce86c7SWei Liu v9fs_path_unlock(s); 2607*60ce86c7SWei Liu if (!err) { 2608*60ce86c7SWei Liu err = offset; 2609*60ce86c7SWei Liu } 2610*60ce86c7SWei Liu 2611*60ce86c7SWei Liu out_err: 2612*60ce86c7SWei Liu pdu_complete(pdu, err); 2613*60ce86c7SWei Liu v9fs_string_free(&old_name); 2614*60ce86c7SWei Liu v9fs_string_free(&new_name); 2615*60ce86c7SWei Liu } 2616*60ce86c7SWei Liu 2617*60ce86c7SWei Liu static void v9fs_wstat(void *opaque) 2618*60ce86c7SWei Liu { 2619*60ce86c7SWei Liu int32_t fid; 2620*60ce86c7SWei Liu int err = 0; 2621*60ce86c7SWei Liu int16_t unused; 2622*60ce86c7SWei Liu V9fsStat v9stat; 2623*60ce86c7SWei Liu size_t offset = 7; 2624*60ce86c7SWei Liu struct stat stbuf; 2625*60ce86c7SWei Liu V9fsFidState *fidp; 2626*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 2627*60ce86c7SWei Liu 2628*60ce86c7SWei Liu v9fs_stat_init(&v9stat); 2629*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat); 2630*60ce86c7SWei Liu if (err < 0) { 2631*60ce86c7SWei Liu goto out_nofid; 2632*60ce86c7SWei Liu } 2633*60ce86c7SWei Liu trace_v9fs_wstat(pdu->tag, pdu->id, fid, 2634*60ce86c7SWei Liu v9stat.mode, v9stat.atime, v9stat.mtime); 2635*60ce86c7SWei Liu 2636*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 2637*60ce86c7SWei Liu if (fidp == NULL) { 2638*60ce86c7SWei Liu err = -EINVAL; 2639*60ce86c7SWei Liu goto out_nofid; 2640*60ce86c7SWei Liu } 2641*60ce86c7SWei Liu /* do we need to sync the file? */ 2642*60ce86c7SWei Liu if (donttouch_stat(&v9stat)) { 2643*60ce86c7SWei Liu err = v9fs_co_fsync(pdu, fidp, 0); 2644*60ce86c7SWei Liu goto out; 2645*60ce86c7SWei Liu } 2646*60ce86c7SWei Liu if (v9stat.mode != -1) { 2647*60ce86c7SWei Liu uint32_t v9_mode; 2648*60ce86c7SWei Liu err = v9fs_co_lstat(pdu, &fidp->path, &stbuf); 2649*60ce86c7SWei Liu if (err < 0) { 2650*60ce86c7SWei Liu goto out; 2651*60ce86c7SWei Liu } 2652*60ce86c7SWei Liu v9_mode = stat_to_v9mode(&stbuf); 2653*60ce86c7SWei Liu if ((v9stat.mode & P9_STAT_MODE_TYPE_BITS) != 2654*60ce86c7SWei Liu (v9_mode & P9_STAT_MODE_TYPE_BITS)) { 2655*60ce86c7SWei Liu /* Attempting to change the type */ 2656*60ce86c7SWei Liu err = -EIO; 2657*60ce86c7SWei Liu goto out; 2658*60ce86c7SWei Liu } 2659*60ce86c7SWei Liu err = v9fs_co_chmod(pdu, &fidp->path, 2660*60ce86c7SWei Liu v9mode_to_mode(v9stat.mode, 2661*60ce86c7SWei Liu &v9stat.extension)); 2662*60ce86c7SWei Liu if (err < 0) { 2663*60ce86c7SWei Liu goto out; 2664*60ce86c7SWei Liu } 2665*60ce86c7SWei Liu } 2666*60ce86c7SWei Liu if (v9stat.mtime != -1 || v9stat.atime != -1) { 2667*60ce86c7SWei Liu struct timespec times[2]; 2668*60ce86c7SWei Liu if (v9stat.atime != -1) { 2669*60ce86c7SWei Liu times[0].tv_sec = v9stat.atime; 2670*60ce86c7SWei Liu times[0].tv_nsec = 0; 2671*60ce86c7SWei Liu } else { 2672*60ce86c7SWei Liu times[0].tv_nsec = UTIME_OMIT; 2673*60ce86c7SWei Liu } 2674*60ce86c7SWei Liu if (v9stat.mtime != -1) { 2675*60ce86c7SWei Liu times[1].tv_sec = v9stat.mtime; 2676*60ce86c7SWei Liu times[1].tv_nsec = 0; 2677*60ce86c7SWei Liu } else { 2678*60ce86c7SWei Liu times[1].tv_nsec = UTIME_OMIT; 2679*60ce86c7SWei Liu } 2680*60ce86c7SWei Liu err = v9fs_co_utimensat(pdu, &fidp->path, times); 2681*60ce86c7SWei Liu if (err < 0) { 2682*60ce86c7SWei Liu goto out; 2683*60ce86c7SWei Liu } 2684*60ce86c7SWei Liu } 2685*60ce86c7SWei Liu if (v9stat.n_gid != -1 || v9stat.n_uid != -1) { 2686*60ce86c7SWei Liu err = v9fs_co_chown(pdu, &fidp->path, v9stat.n_uid, v9stat.n_gid); 2687*60ce86c7SWei Liu if (err < 0) { 2688*60ce86c7SWei Liu goto out; 2689*60ce86c7SWei Liu } 2690*60ce86c7SWei Liu } 2691*60ce86c7SWei Liu if (v9stat.name.size != 0) { 2692*60ce86c7SWei Liu err = v9fs_complete_rename(pdu, fidp, -1, &v9stat.name); 2693*60ce86c7SWei Liu if (err < 0) { 2694*60ce86c7SWei Liu goto out; 2695*60ce86c7SWei Liu } 2696*60ce86c7SWei Liu } 2697*60ce86c7SWei Liu if (v9stat.length != -1) { 2698*60ce86c7SWei Liu err = v9fs_co_truncate(pdu, &fidp->path, v9stat.length); 2699*60ce86c7SWei Liu if (err < 0) { 2700*60ce86c7SWei Liu goto out; 2701*60ce86c7SWei Liu } 2702*60ce86c7SWei Liu } 2703*60ce86c7SWei Liu err = offset; 2704*60ce86c7SWei Liu out: 2705*60ce86c7SWei Liu put_fid(pdu, fidp); 2706*60ce86c7SWei Liu out_nofid: 2707*60ce86c7SWei Liu v9fs_stat_free(&v9stat); 2708*60ce86c7SWei Liu pdu_complete(pdu, err); 2709*60ce86c7SWei Liu } 2710*60ce86c7SWei Liu 2711*60ce86c7SWei Liu static int v9fs_fill_statfs(V9fsState *s, V9fsPDU *pdu, struct statfs *stbuf) 2712*60ce86c7SWei Liu { 2713*60ce86c7SWei Liu uint32_t f_type; 2714*60ce86c7SWei Liu uint32_t f_bsize; 2715*60ce86c7SWei Liu uint64_t f_blocks; 2716*60ce86c7SWei Liu uint64_t f_bfree; 2717*60ce86c7SWei Liu uint64_t f_bavail; 2718*60ce86c7SWei Liu uint64_t f_files; 2719*60ce86c7SWei Liu uint64_t f_ffree; 2720*60ce86c7SWei Liu uint64_t fsid_val; 2721*60ce86c7SWei Liu uint32_t f_namelen; 2722*60ce86c7SWei Liu size_t offset = 7; 2723*60ce86c7SWei Liu int32_t bsize_factor; 2724*60ce86c7SWei Liu 2725*60ce86c7SWei Liu /* 2726*60ce86c7SWei Liu * compute bsize factor based on host file system block size 2727*60ce86c7SWei Liu * and client msize 2728*60ce86c7SWei Liu */ 2729*60ce86c7SWei Liu bsize_factor = (s->msize - P9_IOHDRSZ)/stbuf->f_bsize; 2730*60ce86c7SWei Liu if (!bsize_factor) { 2731*60ce86c7SWei Liu bsize_factor = 1; 2732*60ce86c7SWei Liu } 2733*60ce86c7SWei Liu f_type = stbuf->f_type; 2734*60ce86c7SWei Liu f_bsize = stbuf->f_bsize; 2735*60ce86c7SWei Liu f_bsize *= bsize_factor; 2736*60ce86c7SWei Liu /* 2737*60ce86c7SWei Liu * f_bsize is adjusted(multiplied) by bsize factor, so we need to 2738*60ce86c7SWei Liu * adjust(divide) the number of blocks, free blocks and available 2739*60ce86c7SWei Liu * blocks by bsize factor 2740*60ce86c7SWei Liu */ 2741*60ce86c7SWei Liu f_blocks = stbuf->f_blocks/bsize_factor; 2742*60ce86c7SWei Liu f_bfree = stbuf->f_bfree/bsize_factor; 2743*60ce86c7SWei Liu f_bavail = stbuf->f_bavail/bsize_factor; 2744*60ce86c7SWei Liu f_files = stbuf->f_files; 2745*60ce86c7SWei Liu f_ffree = stbuf->f_ffree; 2746*60ce86c7SWei Liu fsid_val = (unsigned int) stbuf->f_fsid.__val[0] | 2747*60ce86c7SWei Liu (unsigned long long)stbuf->f_fsid.__val[1] << 32; 2748*60ce86c7SWei Liu f_namelen = stbuf->f_namelen; 2749*60ce86c7SWei Liu 2750*60ce86c7SWei Liu return pdu_marshal(pdu, offset, "ddqqqqqqd", 2751*60ce86c7SWei Liu f_type, f_bsize, f_blocks, f_bfree, 2752*60ce86c7SWei Liu f_bavail, f_files, f_ffree, 2753*60ce86c7SWei Liu fsid_val, f_namelen); 2754*60ce86c7SWei Liu } 2755*60ce86c7SWei Liu 2756*60ce86c7SWei Liu static void v9fs_statfs(void *opaque) 2757*60ce86c7SWei Liu { 2758*60ce86c7SWei Liu int32_t fid; 2759*60ce86c7SWei Liu ssize_t retval = 0; 2760*60ce86c7SWei Liu size_t offset = 7; 2761*60ce86c7SWei Liu V9fsFidState *fidp; 2762*60ce86c7SWei Liu struct statfs stbuf; 2763*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 2764*60ce86c7SWei Liu V9fsState *s = pdu->s; 2765*60ce86c7SWei Liu 2766*60ce86c7SWei Liu retval = pdu_unmarshal(pdu, offset, "d", &fid); 2767*60ce86c7SWei Liu if (retval < 0) { 2768*60ce86c7SWei Liu goto out_nofid; 2769*60ce86c7SWei Liu } 2770*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 2771*60ce86c7SWei Liu if (fidp == NULL) { 2772*60ce86c7SWei Liu retval = -ENOENT; 2773*60ce86c7SWei Liu goto out_nofid; 2774*60ce86c7SWei Liu } 2775*60ce86c7SWei Liu retval = v9fs_co_statfs(pdu, &fidp->path, &stbuf); 2776*60ce86c7SWei Liu if (retval < 0) { 2777*60ce86c7SWei Liu goto out; 2778*60ce86c7SWei Liu } 2779*60ce86c7SWei Liu retval = v9fs_fill_statfs(s, pdu, &stbuf); 2780*60ce86c7SWei Liu if (retval < 0) { 2781*60ce86c7SWei Liu goto out; 2782*60ce86c7SWei Liu } 2783*60ce86c7SWei Liu retval += offset; 2784*60ce86c7SWei Liu out: 2785*60ce86c7SWei Liu put_fid(pdu, fidp); 2786*60ce86c7SWei Liu out_nofid: 2787*60ce86c7SWei Liu pdu_complete(pdu, retval); 2788*60ce86c7SWei Liu } 2789*60ce86c7SWei Liu 2790*60ce86c7SWei Liu static void v9fs_mknod(void *opaque) 2791*60ce86c7SWei Liu { 2792*60ce86c7SWei Liu 2793*60ce86c7SWei Liu int mode; 2794*60ce86c7SWei Liu gid_t gid; 2795*60ce86c7SWei Liu int32_t fid; 2796*60ce86c7SWei Liu V9fsQID qid; 2797*60ce86c7SWei Liu int err = 0; 2798*60ce86c7SWei Liu int major, minor; 2799*60ce86c7SWei Liu size_t offset = 7; 2800*60ce86c7SWei Liu V9fsString name; 2801*60ce86c7SWei Liu struct stat stbuf; 2802*60ce86c7SWei Liu V9fsFidState *fidp; 2803*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 2804*60ce86c7SWei Liu 2805*60ce86c7SWei Liu v9fs_string_init(&name); 2806*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode, 2807*60ce86c7SWei Liu &major, &minor, &gid); 2808*60ce86c7SWei Liu if (err < 0) { 2809*60ce86c7SWei Liu goto out_nofid; 2810*60ce86c7SWei Liu } 2811*60ce86c7SWei Liu trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor); 2812*60ce86c7SWei Liu 2813*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 2814*60ce86c7SWei Liu if (fidp == NULL) { 2815*60ce86c7SWei Liu err = -ENOENT; 2816*60ce86c7SWei Liu goto out_nofid; 2817*60ce86c7SWei Liu } 2818*60ce86c7SWei Liu err = v9fs_co_mknod(pdu, fidp, &name, fidp->uid, gid, 2819*60ce86c7SWei Liu makedev(major, minor), mode, &stbuf); 2820*60ce86c7SWei Liu if (err < 0) { 2821*60ce86c7SWei Liu goto out; 2822*60ce86c7SWei Liu } 2823*60ce86c7SWei Liu stat_to_qid(&stbuf, &qid); 2824*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "Q", &qid); 2825*60ce86c7SWei Liu if (err < 0) { 2826*60ce86c7SWei Liu goto out; 2827*60ce86c7SWei Liu } 2828*60ce86c7SWei Liu err += offset; 2829*60ce86c7SWei Liu trace_v9fs_mknod_return(pdu->tag, pdu->id, 2830*60ce86c7SWei Liu qid.type, qid.version, qid.path); 2831*60ce86c7SWei Liu out: 2832*60ce86c7SWei Liu put_fid(pdu, fidp); 2833*60ce86c7SWei Liu out_nofid: 2834*60ce86c7SWei Liu pdu_complete(pdu, err); 2835*60ce86c7SWei Liu v9fs_string_free(&name); 2836*60ce86c7SWei Liu } 2837*60ce86c7SWei Liu 2838*60ce86c7SWei Liu /* 2839*60ce86c7SWei Liu * Implement posix byte range locking code 2840*60ce86c7SWei Liu * Server side handling of locking code is very simple, because 9p server in 2841*60ce86c7SWei Liu * QEMU can handle only one client. And most of the lock handling 2842*60ce86c7SWei Liu * (like conflict, merging) etc is done by the VFS layer itself, so no need to 2843*60ce86c7SWei Liu * do any thing in * qemu 9p server side lock code path. 2844*60ce86c7SWei Liu * So when a TLOCK request comes, always return success 2845*60ce86c7SWei Liu */ 2846*60ce86c7SWei Liu static void v9fs_lock(void *opaque) 2847*60ce86c7SWei Liu { 2848*60ce86c7SWei Liu int8_t status; 2849*60ce86c7SWei Liu V9fsFlock flock; 2850*60ce86c7SWei Liu size_t offset = 7; 2851*60ce86c7SWei Liu struct stat stbuf; 2852*60ce86c7SWei Liu V9fsFidState *fidp; 2853*60ce86c7SWei Liu int32_t fid, err = 0; 2854*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 2855*60ce86c7SWei Liu 2856*60ce86c7SWei Liu status = P9_LOCK_ERROR; 2857*60ce86c7SWei Liu v9fs_string_init(&flock.client_id); 2858*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock.type, 2859*60ce86c7SWei Liu &flock.flags, &flock.start, &flock.length, 2860*60ce86c7SWei Liu &flock.proc_id, &flock.client_id); 2861*60ce86c7SWei Liu if (err < 0) { 2862*60ce86c7SWei Liu goto out_nofid; 2863*60ce86c7SWei Liu } 2864*60ce86c7SWei Liu trace_v9fs_lock(pdu->tag, pdu->id, fid, 2865*60ce86c7SWei Liu flock.type, flock.start, flock.length); 2866*60ce86c7SWei Liu 2867*60ce86c7SWei Liu 2868*60ce86c7SWei Liu /* We support only block flag now (that too ignored currently) */ 2869*60ce86c7SWei Liu if (flock.flags & ~P9_LOCK_FLAGS_BLOCK) { 2870*60ce86c7SWei Liu err = -EINVAL; 2871*60ce86c7SWei Liu goto out_nofid; 2872*60ce86c7SWei Liu } 2873*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 2874*60ce86c7SWei Liu if (fidp == NULL) { 2875*60ce86c7SWei Liu err = -ENOENT; 2876*60ce86c7SWei Liu goto out_nofid; 2877*60ce86c7SWei Liu } 2878*60ce86c7SWei Liu err = v9fs_co_fstat(pdu, fidp, &stbuf); 2879*60ce86c7SWei Liu if (err < 0) { 2880*60ce86c7SWei Liu goto out; 2881*60ce86c7SWei Liu } 2882*60ce86c7SWei Liu status = P9_LOCK_SUCCESS; 2883*60ce86c7SWei Liu out: 2884*60ce86c7SWei Liu put_fid(pdu, fidp); 2885*60ce86c7SWei Liu out_nofid: 2886*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "b", status); 2887*60ce86c7SWei Liu if (err > 0) { 2888*60ce86c7SWei Liu err += offset; 2889*60ce86c7SWei Liu } 2890*60ce86c7SWei Liu trace_v9fs_lock_return(pdu->tag, pdu->id, status); 2891*60ce86c7SWei Liu pdu_complete(pdu, err); 2892*60ce86c7SWei Liu v9fs_string_free(&flock.client_id); 2893*60ce86c7SWei Liu } 2894*60ce86c7SWei Liu 2895*60ce86c7SWei Liu /* 2896*60ce86c7SWei Liu * When a TGETLOCK request comes, always return success because all lock 2897*60ce86c7SWei Liu * handling is done by client's VFS layer. 2898*60ce86c7SWei Liu */ 2899*60ce86c7SWei Liu static void v9fs_getlock(void *opaque) 2900*60ce86c7SWei Liu { 2901*60ce86c7SWei Liu size_t offset = 7; 2902*60ce86c7SWei Liu struct stat stbuf; 2903*60ce86c7SWei Liu V9fsFidState *fidp; 2904*60ce86c7SWei Liu V9fsGetlock glock; 2905*60ce86c7SWei Liu int32_t fid, err = 0; 2906*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 2907*60ce86c7SWei Liu 2908*60ce86c7SWei Liu v9fs_string_init(&glock.client_id); 2909*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dbqqds", &fid, &glock.type, 2910*60ce86c7SWei Liu &glock.start, &glock.length, &glock.proc_id, 2911*60ce86c7SWei Liu &glock.client_id); 2912*60ce86c7SWei Liu if (err < 0) { 2913*60ce86c7SWei Liu goto out_nofid; 2914*60ce86c7SWei Liu } 2915*60ce86c7SWei Liu trace_v9fs_getlock(pdu->tag, pdu->id, fid, 2916*60ce86c7SWei Liu glock.type, glock.start, glock.length); 2917*60ce86c7SWei Liu 2918*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 2919*60ce86c7SWei Liu if (fidp == NULL) { 2920*60ce86c7SWei Liu err = -ENOENT; 2921*60ce86c7SWei Liu goto out_nofid; 2922*60ce86c7SWei Liu } 2923*60ce86c7SWei Liu err = v9fs_co_fstat(pdu, fidp, &stbuf); 2924*60ce86c7SWei Liu if (err < 0) { 2925*60ce86c7SWei Liu goto out; 2926*60ce86c7SWei Liu } 2927*60ce86c7SWei Liu glock.type = P9_LOCK_TYPE_UNLCK; 2928*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "bqqds", glock.type, 2929*60ce86c7SWei Liu glock.start, glock.length, glock.proc_id, 2930*60ce86c7SWei Liu &glock.client_id); 2931*60ce86c7SWei Liu if (err < 0) { 2932*60ce86c7SWei Liu goto out; 2933*60ce86c7SWei Liu } 2934*60ce86c7SWei Liu err += offset; 2935*60ce86c7SWei Liu trace_v9fs_getlock_return(pdu->tag, pdu->id, glock.type, glock.start, 2936*60ce86c7SWei Liu glock.length, glock.proc_id); 2937*60ce86c7SWei Liu out: 2938*60ce86c7SWei Liu put_fid(pdu, fidp); 2939*60ce86c7SWei Liu out_nofid: 2940*60ce86c7SWei Liu pdu_complete(pdu, err); 2941*60ce86c7SWei Liu v9fs_string_free(&glock.client_id); 2942*60ce86c7SWei Liu } 2943*60ce86c7SWei Liu 2944*60ce86c7SWei Liu static void v9fs_mkdir(void *opaque) 2945*60ce86c7SWei Liu { 2946*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 2947*60ce86c7SWei Liu size_t offset = 7; 2948*60ce86c7SWei Liu int32_t fid; 2949*60ce86c7SWei Liu struct stat stbuf; 2950*60ce86c7SWei Liu V9fsQID qid; 2951*60ce86c7SWei Liu V9fsString name; 2952*60ce86c7SWei Liu V9fsFidState *fidp; 2953*60ce86c7SWei Liu gid_t gid; 2954*60ce86c7SWei Liu int mode; 2955*60ce86c7SWei Liu int err = 0; 2956*60ce86c7SWei Liu 2957*60ce86c7SWei Liu v9fs_string_init(&name); 2958*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid); 2959*60ce86c7SWei Liu if (err < 0) { 2960*60ce86c7SWei Liu goto out_nofid; 2961*60ce86c7SWei Liu } 2962*60ce86c7SWei Liu trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid); 2963*60ce86c7SWei Liu 2964*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 2965*60ce86c7SWei Liu if (fidp == NULL) { 2966*60ce86c7SWei Liu err = -ENOENT; 2967*60ce86c7SWei Liu goto out_nofid; 2968*60ce86c7SWei Liu } 2969*60ce86c7SWei Liu err = v9fs_co_mkdir(pdu, fidp, &name, mode, fidp->uid, gid, &stbuf); 2970*60ce86c7SWei Liu if (err < 0) { 2971*60ce86c7SWei Liu goto out; 2972*60ce86c7SWei Liu } 2973*60ce86c7SWei Liu stat_to_qid(&stbuf, &qid); 2974*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "Q", &qid); 2975*60ce86c7SWei Liu if (err < 0) { 2976*60ce86c7SWei Liu goto out; 2977*60ce86c7SWei Liu } 2978*60ce86c7SWei Liu err += offset; 2979*60ce86c7SWei Liu trace_v9fs_mkdir_return(pdu->tag, pdu->id, 2980*60ce86c7SWei Liu qid.type, qid.version, qid.path, err); 2981*60ce86c7SWei Liu out: 2982*60ce86c7SWei Liu put_fid(pdu, fidp); 2983*60ce86c7SWei Liu out_nofid: 2984*60ce86c7SWei Liu pdu_complete(pdu, err); 2985*60ce86c7SWei Liu v9fs_string_free(&name); 2986*60ce86c7SWei Liu } 2987*60ce86c7SWei Liu 2988*60ce86c7SWei Liu static void v9fs_xattrwalk(void *opaque) 2989*60ce86c7SWei Liu { 2990*60ce86c7SWei Liu int64_t size; 2991*60ce86c7SWei Liu V9fsString name; 2992*60ce86c7SWei Liu ssize_t err = 0; 2993*60ce86c7SWei Liu size_t offset = 7; 2994*60ce86c7SWei Liu int32_t fid, newfid; 2995*60ce86c7SWei Liu V9fsFidState *file_fidp; 2996*60ce86c7SWei Liu V9fsFidState *xattr_fidp = NULL; 2997*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 2998*60ce86c7SWei Liu V9fsState *s = pdu->s; 2999*60ce86c7SWei Liu 3000*60ce86c7SWei Liu v9fs_string_init(&name); 3001*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name); 3002*60ce86c7SWei Liu if (err < 0) { 3003*60ce86c7SWei Liu goto out_nofid; 3004*60ce86c7SWei Liu } 3005*60ce86c7SWei Liu trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data); 3006*60ce86c7SWei Liu 3007*60ce86c7SWei Liu file_fidp = get_fid(pdu, fid); 3008*60ce86c7SWei Liu if (file_fidp == NULL) { 3009*60ce86c7SWei Liu err = -ENOENT; 3010*60ce86c7SWei Liu goto out_nofid; 3011*60ce86c7SWei Liu } 3012*60ce86c7SWei Liu xattr_fidp = alloc_fid(s, newfid); 3013*60ce86c7SWei Liu if (xattr_fidp == NULL) { 3014*60ce86c7SWei Liu err = -EINVAL; 3015*60ce86c7SWei Liu goto out; 3016*60ce86c7SWei Liu } 3017*60ce86c7SWei Liu v9fs_path_copy(&xattr_fidp->path, &file_fidp->path); 3018*60ce86c7SWei Liu if (name.data == NULL) { 3019*60ce86c7SWei Liu /* 3020*60ce86c7SWei Liu * listxattr request. Get the size first 3021*60ce86c7SWei Liu */ 3022*60ce86c7SWei Liu size = v9fs_co_llistxattr(pdu, &xattr_fidp->path, NULL, 0); 3023*60ce86c7SWei Liu if (size < 0) { 3024*60ce86c7SWei Liu err = size; 3025*60ce86c7SWei Liu clunk_fid(s, xattr_fidp->fid); 3026*60ce86c7SWei Liu goto out; 3027*60ce86c7SWei Liu } 3028*60ce86c7SWei Liu /* 3029*60ce86c7SWei Liu * Read the xattr value 3030*60ce86c7SWei Liu */ 3031*60ce86c7SWei Liu xattr_fidp->fs.xattr.len = size; 3032*60ce86c7SWei Liu xattr_fidp->fid_type = P9_FID_XATTR; 3033*60ce86c7SWei Liu xattr_fidp->fs.xattr.copied_len = -1; 3034*60ce86c7SWei Liu if (size) { 3035*60ce86c7SWei Liu xattr_fidp->fs.xattr.value = g_malloc(size); 3036*60ce86c7SWei Liu err = v9fs_co_llistxattr(pdu, &xattr_fidp->path, 3037*60ce86c7SWei Liu xattr_fidp->fs.xattr.value, 3038*60ce86c7SWei Liu xattr_fidp->fs.xattr.len); 3039*60ce86c7SWei Liu if (err < 0) { 3040*60ce86c7SWei Liu clunk_fid(s, xattr_fidp->fid); 3041*60ce86c7SWei Liu goto out; 3042*60ce86c7SWei Liu } 3043*60ce86c7SWei Liu } 3044*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "q", size); 3045*60ce86c7SWei Liu if (err < 0) { 3046*60ce86c7SWei Liu goto out; 3047*60ce86c7SWei Liu } 3048*60ce86c7SWei Liu err += offset; 3049*60ce86c7SWei Liu } else { 3050*60ce86c7SWei Liu /* 3051*60ce86c7SWei Liu * specific xattr fid. We check for xattr 3052*60ce86c7SWei Liu * presence also collect the xattr size 3053*60ce86c7SWei Liu */ 3054*60ce86c7SWei Liu size = v9fs_co_lgetxattr(pdu, &xattr_fidp->path, 3055*60ce86c7SWei Liu &name, NULL, 0); 3056*60ce86c7SWei Liu if (size < 0) { 3057*60ce86c7SWei Liu err = size; 3058*60ce86c7SWei Liu clunk_fid(s, xattr_fidp->fid); 3059*60ce86c7SWei Liu goto out; 3060*60ce86c7SWei Liu } 3061*60ce86c7SWei Liu /* 3062*60ce86c7SWei Liu * Read the xattr value 3063*60ce86c7SWei Liu */ 3064*60ce86c7SWei Liu xattr_fidp->fs.xattr.len = size; 3065*60ce86c7SWei Liu xattr_fidp->fid_type = P9_FID_XATTR; 3066*60ce86c7SWei Liu xattr_fidp->fs.xattr.copied_len = -1; 3067*60ce86c7SWei Liu if (size) { 3068*60ce86c7SWei Liu xattr_fidp->fs.xattr.value = g_malloc(size); 3069*60ce86c7SWei Liu err = v9fs_co_lgetxattr(pdu, &xattr_fidp->path, 3070*60ce86c7SWei Liu &name, xattr_fidp->fs.xattr.value, 3071*60ce86c7SWei Liu xattr_fidp->fs.xattr.len); 3072*60ce86c7SWei Liu if (err < 0) { 3073*60ce86c7SWei Liu clunk_fid(s, xattr_fidp->fid); 3074*60ce86c7SWei Liu goto out; 3075*60ce86c7SWei Liu } 3076*60ce86c7SWei Liu } 3077*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "q", size); 3078*60ce86c7SWei Liu if (err < 0) { 3079*60ce86c7SWei Liu goto out; 3080*60ce86c7SWei Liu } 3081*60ce86c7SWei Liu err += offset; 3082*60ce86c7SWei Liu } 3083*60ce86c7SWei Liu trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size); 3084*60ce86c7SWei Liu out: 3085*60ce86c7SWei Liu put_fid(pdu, file_fidp); 3086*60ce86c7SWei Liu if (xattr_fidp) { 3087*60ce86c7SWei Liu put_fid(pdu, xattr_fidp); 3088*60ce86c7SWei Liu } 3089*60ce86c7SWei Liu out_nofid: 3090*60ce86c7SWei Liu pdu_complete(pdu, err); 3091*60ce86c7SWei Liu v9fs_string_free(&name); 3092*60ce86c7SWei Liu } 3093*60ce86c7SWei Liu 3094*60ce86c7SWei Liu static void v9fs_xattrcreate(void *opaque) 3095*60ce86c7SWei Liu { 3096*60ce86c7SWei Liu int flags; 3097*60ce86c7SWei Liu int32_t fid; 3098*60ce86c7SWei Liu int64_t size; 3099*60ce86c7SWei Liu ssize_t err = 0; 3100*60ce86c7SWei Liu V9fsString name; 3101*60ce86c7SWei Liu size_t offset = 7; 3102*60ce86c7SWei Liu V9fsFidState *file_fidp; 3103*60ce86c7SWei Liu V9fsFidState *xattr_fidp; 3104*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 3105*60ce86c7SWei Liu 3106*60ce86c7SWei Liu v9fs_string_init(&name); 3107*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "dsqd", &fid, &name, &size, &flags); 3108*60ce86c7SWei Liu if (err < 0) { 3109*60ce86c7SWei Liu goto out_nofid; 3110*60ce86c7SWei Liu } 3111*60ce86c7SWei Liu trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags); 3112*60ce86c7SWei Liu 3113*60ce86c7SWei Liu file_fidp = get_fid(pdu, fid); 3114*60ce86c7SWei Liu if (file_fidp == NULL) { 3115*60ce86c7SWei Liu err = -EINVAL; 3116*60ce86c7SWei Liu goto out_nofid; 3117*60ce86c7SWei Liu } 3118*60ce86c7SWei Liu /* Make the file fid point to xattr */ 3119*60ce86c7SWei Liu xattr_fidp = file_fidp; 3120*60ce86c7SWei Liu xattr_fidp->fid_type = P9_FID_XATTR; 3121*60ce86c7SWei Liu xattr_fidp->fs.xattr.copied_len = 0; 3122*60ce86c7SWei Liu xattr_fidp->fs.xattr.len = size; 3123*60ce86c7SWei Liu xattr_fidp->fs.xattr.flags = flags; 3124*60ce86c7SWei Liu v9fs_string_init(&xattr_fidp->fs.xattr.name); 3125*60ce86c7SWei Liu v9fs_string_copy(&xattr_fidp->fs.xattr.name, &name); 3126*60ce86c7SWei Liu xattr_fidp->fs.xattr.value = g_malloc(size); 3127*60ce86c7SWei Liu err = offset; 3128*60ce86c7SWei Liu put_fid(pdu, file_fidp); 3129*60ce86c7SWei Liu out_nofid: 3130*60ce86c7SWei Liu pdu_complete(pdu, err); 3131*60ce86c7SWei Liu v9fs_string_free(&name); 3132*60ce86c7SWei Liu } 3133*60ce86c7SWei Liu 3134*60ce86c7SWei Liu static void v9fs_readlink(void *opaque) 3135*60ce86c7SWei Liu { 3136*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 3137*60ce86c7SWei Liu size_t offset = 7; 3138*60ce86c7SWei Liu V9fsString target; 3139*60ce86c7SWei Liu int32_t fid; 3140*60ce86c7SWei Liu int err = 0; 3141*60ce86c7SWei Liu V9fsFidState *fidp; 3142*60ce86c7SWei Liu 3143*60ce86c7SWei Liu err = pdu_unmarshal(pdu, offset, "d", &fid); 3144*60ce86c7SWei Liu if (err < 0) { 3145*60ce86c7SWei Liu goto out_nofid; 3146*60ce86c7SWei Liu } 3147*60ce86c7SWei Liu trace_v9fs_readlink(pdu->tag, pdu->id, fid); 3148*60ce86c7SWei Liu fidp = get_fid(pdu, fid); 3149*60ce86c7SWei Liu if (fidp == NULL) { 3150*60ce86c7SWei Liu err = -ENOENT; 3151*60ce86c7SWei Liu goto out_nofid; 3152*60ce86c7SWei Liu } 3153*60ce86c7SWei Liu 3154*60ce86c7SWei Liu v9fs_string_init(&target); 3155*60ce86c7SWei Liu err = v9fs_co_readlink(pdu, &fidp->path, &target); 3156*60ce86c7SWei Liu if (err < 0) { 3157*60ce86c7SWei Liu goto out; 3158*60ce86c7SWei Liu } 3159*60ce86c7SWei Liu err = pdu_marshal(pdu, offset, "s", &target); 3160*60ce86c7SWei Liu if (err < 0) { 3161*60ce86c7SWei Liu v9fs_string_free(&target); 3162*60ce86c7SWei Liu goto out; 3163*60ce86c7SWei Liu } 3164*60ce86c7SWei Liu err += offset; 3165*60ce86c7SWei Liu trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data); 3166*60ce86c7SWei Liu v9fs_string_free(&target); 3167*60ce86c7SWei Liu out: 3168*60ce86c7SWei Liu put_fid(pdu, fidp); 3169*60ce86c7SWei Liu out_nofid: 3170*60ce86c7SWei Liu pdu_complete(pdu, err); 3171*60ce86c7SWei Liu } 3172*60ce86c7SWei Liu 3173*60ce86c7SWei Liu static CoroutineEntry *pdu_co_handlers[] = { 3174*60ce86c7SWei Liu [P9_TREADDIR] = v9fs_readdir, 3175*60ce86c7SWei Liu [P9_TSTATFS] = v9fs_statfs, 3176*60ce86c7SWei Liu [P9_TGETATTR] = v9fs_getattr, 3177*60ce86c7SWei Liu [P9_TSETATTR] = v9fs_setattr, 3178*60ce86c7SWei Liu [P9_TXATTRWALK] = v9fs_xattrwalk, 3179*60ce86c7SWei Liu [P9_TXATTRCREATE] = v9fs_xattrcreate, 3180*60ce86c7SWei Liu [P9_TMKNOD] = v9fs_mknod, 3181*60ce86c7SWei Liu [P9_TRENAME] = v9fs_rename, 3182*60ce86c7SWei Liu [P9_TLOCK] = v9fs_lock, 3183*60ce86c7SWei Liu [P9_TGETLOCK] = v9fs_getlock, 3184*60ce86c7SWei Liu [P9_TRENAMEAT] = v9fs_renameat, 3185*60ce86c7SWei Liu [P9_TREADLINK] = v9fs_readlink, 3186*60ce86c7SWei Liu [P9_TUNLINKAT] = v9fs_unlinkat, 3187*60ce86c7SWei Liu [P9_TMKDIR] = v9fs_mkdir, 3188*60ce86c7SWei Liu [P9_TVERSION] = v9fs_version, 3189*60ce86c7SWei Liu [P9_TLOPEN] = v9fs_open, 3190*60ce86c7SWei Liu [P9_TATTACH] = v9fs_attach, 3191*60ce86c7SWei Liu [P9_TSTAT] = v9fs_stat, 3192*60ce86c7SWei Liu [P9_TWALK] = v9fs_walk, 3193*60ce86c7SWei Liu [P9_TCLUNK] = v9fs_clunk, 3194*60ce86c7SWei Liu [P9_TFSYNC] = v9fs_fsync, 3195*60ce86c7SWei Liu [P9_TOPEN] = v9fs_open, 3196*60ce86c7SWei Liu [P9_TREAD] = v9fs_read, 3197*60ce86c7SWei Liu #if 0 3198*60ce86c7SWei Liu [P9_TAUTH] = v9fs_auth, 3199*60ce86c7SWei Liu #endif 3200*60ce86c7SWei Liu [P9_TFLUSH] = v9fs_flush, 3201*60ce86c7SWei Liu [P9_TLINK] = v9fs_link, 3202*60ce86c7SWei Liu [P9_TSYMLINK] = v9fs_symlink, 3203*60ce86c7SWei Liu [P9_TCREATE] = v9fs_create, 3204*60ce86c7SWei Liu [P9_TLCREATE] = v9fs_lcreate, 3205*60ce86c7SWei Liu [P9_TWRITE] = v9fs_write, 3206*60ce86c7SWei Liu [P9_TWSTAT] = v9fs_wstat, 3207*60ce86c7SWei Liu [P9_TREMOVE] = v9fs_remove, 3208*60ce86c7SWei Liu }; 3209*60ce86c7SWei Liu 3210*60ce86c7SWei Liu static void v9fs_op_not_supp(void *opaque) 3211*60ce86c7SWei Liu { 3212*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 3213*60ce86c7SWei Liu pdu_complete(pdu, -EOPNOTSUPP); 3214*60ce86c7SWei Liu } 3215*60ce86c7SWei Liu 3216*60ce86c7SWei Liu static void v9fs_fs_ro(void *opaque) 3217*60ce86c7SWei Liu { 3218*60ce86c7SWei Liu V9fsPDU *pdu = opaque; 3219*60ce86c7SWei Liu pdu_complete(pdu, -EROFS); 3220*60ce86c7SWei Liu } 3221*60ce86c7SWei Liu 3222*60ce86c7SWei Liu static inline bool is_read_only_op(V9fsPDU *pdu) 3223*60ce86c7SWei Liu { 3224*60ce86c7SWei Liu switch (pdu->id) { 3225*60ce86c7SWei Liu case P9_TREADDIR: 3226*60ce86c7SWei Liu case P9_TSTATFS: 3227*60ce86c7SWei Liu case P9_TGETATTR: 3228*60ce86c7SWei Liu case P9_TXATTRWALK: 3229*60ce86c7SWei Liu case P9_TLOCK: 3230*60ce86c7SWei Liu case P9_TGETLOCK: 3231*60ce86c7SWei Liu case P9_TREADLINK: 3232*60ce86c7SWei Liu case P9_TVERSION: 3233*60ce86c7SWei Liu case P9_TLOPEN: 3234*60ce86c7SWei Liu case P9_TATTACH: 3235*60ce86c7SWei Liu case P9_TSTAT: 3236*60ce86c7SWei Liu case P9_TWALK: 3237*60ce86c7SWei Liu case P9_TCLUNK: 3238*60ce86c7SWei Liu case P9_TFSYNC: 3239*60ce86c7SWei Liu case P9_TOPEN: 3240*60ce86c7SWei Liu case P9_TREAD: 3241*60ce86c7SWei Liu case P9_TAUTH: 3242*60ce86c7SWei Liu case P9_TFLUSH: 3243*60ce86c7SWei Liu return 1; 3244*60ce86c7SWei Liu default: 3245*60ce86c7SWei Liu return 0; 3246*60ce86c7SWei Liu } 3247*60ce86c7SWei Liu } 3248*60ce86c7SWei Liu 3249*60ce86c7SWei Liu void pdu_submit(V9fsPDU *pdu) 3250*60ce86c7SWei Liu { 3251*60ce86c7SWei Liu Coroutine *co; 3252*60ce86c7SWei Liu CoroutineEntry *handler; 3253*60ce86c7SWei Liu V9fsState *s = pdu->s; 3254*60ce86c7SWei Liu 3255*60ce86c7SWei Liu if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) || 3256*60ce86c7SWei Liu (pdu_co_handlers[pdu->id] == NULL)) { 3257*60ce86c7SWei Liu handler = v9fs_op_not_supp; 3258*60ce86c7SWei Liu } else { 3259*60ce86c7SWei Liu handler = pdu_co_handlers[pdu->id]; 3260*60ce86c7SWei Liu } 3261*60ce86c7SWei Liu 3262*60ce86c7SWei Liu if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) { 3263*60ce86c7SWei Liu handler = v9fs_fs_ro; 3264*60ce86c7SWei Liu } 3265*60ce86c7SWei Liu co = qemu_coroutine_create(handler); 3266*60ce86c7SWei Liu qemu_coroutine_enter(co, pdu); 3267*60ce86c7SWei Liu } 3268*60ce86c7SWei Liu 3269*60ce86c7SWei Liu static void __attribute__((__constructor__)) v9fs_set_fd_limit(void) 3270*60ce86c7SWei Liu { 3271*60ce86c7SWei Liu struct rlimit rlim; 3272*60ce86c7SWei Liu if (getrlimit(RLIMIT_NOFILE, &rlim) < 0) { 3273*60ce86c7SWei Liu fprintf(stderr, "Failed to get the resource limit\n"); 3274*60ce86c7SWei Liu exit(1); 3275*60ce86c7SWei Liu } 3276*60ce86c7SWei Liu open_fd_hw = rlim.rlim_cur - MIN(400, rlim.rlim_cur/3); 3277*60ce86c7SWei Liu open_fd_rc = rlim.rlim_cur/2; 3278*60ce86c7SWei Liu } 3279