11c7850f9SSasha Levin #include "kvm/virtio-pci-dev.h" 21c7850f9SSasha Levin #include "kvm/ioport.h" 31c7850f9SSasha Levin #include "kvm/util.h" 41c7850f9SSasha Levin #include "kvm/threadpool.h" 5bfc15268SAneesh Kumar K.V #include "kvm/irq.h" 6bfc15268SAneesh Kumar K.V #include "kvm/virtio-9p.h" 7e59662b3SSasha Levin #include "kvm/guest_compat.h" 8cac9e8fdSSasha Levin #include "kvm/builtin-setup.h" 91c7850f9SSasha Levin 10bfc15268SAneesh Kumar K.V #include <stdio.h> 11bfc15268SAneesh Kumar K.V #include <stdlib.h> 121c7850f9SSasha Levin #include <fcntl.h> 131c7850f9SSasha Levin #include <sys/stat.h> 14c0a98553SJeremy Linton #include <sys/sysmacros.h> 15bfc15268SAneesh Kumar K.V #include <unistd.h> 16bfc15268SAneesh Kumar K.V #include <string.h> 17bfc15268SAneesh Kumar K.V #include <errno.h> 18c797b6c6SAneesh Kumar K.V #include <sys/vfs.h> 191c7850f9SSasha Levin 202daa28d4SAneesh Kumar K.V #include <linux/virtio_ring.h> 212daa28d4SAneesh Kumar K.V #include <linux/virtio_9p.h> 22c6cb7c75SAndre Przywara #include <linux/9p.h> 232daa28d4SAneesh Kumar K.V 24c7838fbdSSasha Levin static LIST_HEAD(devs); 25312c62d1SSasha Levin static int compat_id = -1; 26c7838fbdSSasha Levin 27e2341580SSasha Levin static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid); 28e2341580SSasha Levin static struct p9_fid *find_or_create_fid(struct p9_dev *dev, u32 fid) 29e2341580SSasha Levin { 30e2341580SSasha Levin struct rb_node *node = dev->fids.rb_node; 31e2341580SSasha Levin struct p9_fid *pfid = NULL; 32e277a1b4SG. Campana size_t len; 33e2341580SSasha Levin 34e2341580SSasha Levin while (node) { 35e2341580SSasha Levin struct p9_fid *cur = rb_entry(node, struct p9_fid, node); 36e2341580SSasha Levin 37e2341580SSasha Levin if (fid < cur->fid) { 38e2341580SSasha Levin node = node->rb_left; 39e2341580SSasha Levin } else if (fid > cur->fid) { 40e2341580SSasha Levin node = node->rb_right; 41e2341580SSasha Levin } else { 42e2341580SSasha Levin return cur; 43e2341580SSasha Levin } 44e2341580SSasha Levin } 45e2341580SSasha Levin 46e2341580SSasha Levin pfid = calloc(sizeof(*pfid), 1); 47e2341580SSasha Levin if (!pfid) 48e2341580SSasha Levin return NULL; 49e2341580SSasha Levin 50e277a1b4SG. Campana len = strlen(dev->root_dir); 51e277a1b4SG. Campana if (len >= sizeof(pfid->abs_path)) { 52e277a1b4SG. Campana free(pfid); 53e277a1b4SG. Campana return NULL; 54e277a1b4SG. Campana } 55e277a1b4SG. Campana 56e2341580SSasha Levin pfid->fid = fid; 57e2341580SSasha Levin strcpy(pfid->abs_path, dev->root_dir); 58e277a1b4SG. Campana pfid->path = pfid->abs_path + strlen(pfid->abs_path); 59e2341580SSasha Levin 60e2341580SSasha Levin insert_new_fid(dev, pfid); 61e2341580SSasha Levin 62e2341580SSasha Levin return pfid; 63e2341580SSasha Levin } 64e2341580SSasha Levin 65e2341580SSasha Levin static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid) 66e2341580SSasha Levin { 67e2341580SSasha Levin struct rb_node **node = &(dev->fids.rb_node), *parent = NULL; 68e2341580SSasha Levin 69e2341580SSasha Levin while (*node) { 70e2341580SSasha Levin int result = fid->fid - rb_entry(*node, struct p9_fid, node)->fid; 71e2341580SSasha Levin 72e2341580SSasha Levin parent = *node; 73e2341580SSasha Levin if (result < 0) 74e2341580SSasha Levin node = &((*node)->rb_left); 75e2341580SSasha Levin else if (result > 0) 76e2341580SSasha Levin node = &((*node)->rb_right); 77e2341580SSasha Levin else 78e2341580SSasha Levin return -EEXIST; 79e2341580SSasha Levin } 80e2341580SSasha Levin 81e2341580SSasha Levin rb_link_node(&fid->node, parent, node); 82e2341580SSasha Levin rb_insert_color(&fid->node, &dev->fids); 83e2341580SSasha Levin return 0; 84e2341580SSasha Levin } 85e2341580SSasha Levin 8631a6fb8dSSasha Levin static struct p9_fid *get_fid(struct p9_dev *p9dev, int fid) 8731a6fb8dSSasha Levin { 88e2341580SSasha Levin struct p9_fid *new; 8931a6fb8dSSasha Levin 90e2341580SSasha Levin new = find_or_create_fid(p9dev, fid); 91e2341580SSasha Levin 92e2341580SSasha Levin return new; 9331a6fb8dSSasha Levin } 9431a6fb8dSSasha Levin 95c797b6c6SAneesh Kumar K.V static void stat2qid(struct stat *st, struct p9_qid *qid) 961c7850f9SSasha Levin { 971c7850f9SSasha Levin *qid = (struct p9_qid) { 981c7850f9SSasha Levin .path = st->st_ino, 991c7850f9SSasha Levin .version = st->st_mtime, 1001c7850f9SSasha Levin }; 1011c7850f9SSasha Levin 1021c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) 1031c7850f9SSasha Levin qid->type |= P9_QTDIR; 1041c7850f9SSasha Levin } 1051c7850f9SSasha Levin 106b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid) 1071c7850f9SSasha Levin { 108e2341580SSasha Levin struct p9_fid *pfid = get_fid(p9dev, fid); 109e2341580SSasha Levin 110e2341580SSasha Levin if (pfid->fd > 0) 111e2341580SSasha Levin close(pfid->fd); 112e2341580SSasha Levin 113e2341580SSasha Levin if (pfid->dir) 114e2341580SSasha Levin closedir(pfid->dir); 115e2341580SSasha Levin 116e2341580SSasha Levin rb_erase(&pfid->node, &p9dev->fids); 117e2341580SSasha Levin free(pfid); 1181c7850f9SSasha Levin } 119e2341580SSasha Levin 120bfc15268SAneesh Kumar K.V static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size) 1211c7850f9SSasha Levin { 122bfc15268SAneesh Kumar K.V u8 cmd; 123bfc15268SAneesh Kumar K.V u16 tag; 124bfc15268SAneesh Kumar K.V 125bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32); 126bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag); 127bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 128bfc15268SAneesh Kumar K.V /* cmd + 1 is the reply message */ 129bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag); 1301c7850f9SSasha Levin } 1311c7850f9SSasha Levin 1326b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt) 1336b163a87SAneesh Kumar K.V { 1346b163a87SAneesh Kumar K.V int i; 1356b163a87SAneesh Kumar K.V u32 total = 0; 1366b163a87SAneesh Kumar K.V for (i = 0; (i < iov_cnt) && (total < count); i++) { 1376b163a87SAneesh Kumar K.V if (total + iov[i].iov_len > count) { 1386b163a87SAneesh Kumar K.V /* we don't need this iov fully */ 1396b163a87SAneesh Kumar K.V iov[i].iov_len -= ((total + iov[i].iov_len) - count); 1406b163a87SAneesh Kumar K.V i++; 1416b163a87SAneesh Kumar K.V break; 1426b163a87SAneesh Kumar K.V } 1436b163a87SAneesh Kumar K.V total += iov[i].iov_len; 1446b163a87SAneesh Kumar K.V } 1456b163a87SAneesh Kumar K.V return i; 1466b163a87SAneesh Kumar K.V } 1476b163a87SAneesh Kumar K.V 148eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev, 149eee1ba8eSAneesh Kumar K.V struct p9_pdu *pdu, int err, u32 *outlen) 150eee1ba8eSAneesh Kumar K.V { 151bfc15268SAneesh Kumar K.V u16 tag; 152eee1ba8eSAneesh Kumar K.V 1539c2e1d1aSSuzuki K. Poulose /* EMFILE at server implies ENFILE for the VM */ 1549c2e1d1aSSuzuki K. Poulose if (err == EMFILE) 1559c2e1d1aSSuzuki K. Poulose err = ENFILE; 1569c2e1d1aSSuzuki K. Poulose 1575529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 158c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", err); 159bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 160eee1ba8eSAneesh Kumar K.V 161c797b6c6SAneesh Kumar K.V /* read the tag from input */ 162bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32) + sizeof(u8); 163bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "w", &tag); 164bfc15268SAneesh Kumar K.V 165c797b6c6SAneesh Kumar K.V /* Update the header */ 166bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 167c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RLERROR, tag); 168eee1ba8eSAneesh Kumar K.V } 169eee1ba8eSAneesh Kumar K.V 170ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev, 171af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1721c7850f9SSasha Levin { 173c797b6c6SAneesh Kumar K.V u32 msize; 174c797b6c6SAneesh Kumar K.V char *version; 175c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ds", &msize, &version); 176c797b6c6SAneesh Kumar K.V /* 177c797b6c6SAneesh Kumar K.V * reply with the same msize the client sent us 178c797b6c6SAneesh Kumar K.V * Error out if the request is not for 9P2000.L 179c797b6c6SAneesh Kumar K.V */ 1805529bcd7SAsias He if (!strcmp(version, VIRTIO_9P_VERSION_DOTL)) 181c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, version); 182c797b6c6SAneesh Kumar K.V else 183c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, "unknown"); 1841c7850f9SSasha Levin 185bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 186bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 187c797b6c6SAneesh Kumar K.V free(version); 188ead43b01SAneesh Kumar K.V return; 1891c7850f9SSasha Levin } 1901c7850f9SSasha Levin 191ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev, 192af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1931c7850f9SSasha Levin { 194bfc15268SAneesh Kumar K.V u32 fid; 1951c7850f9SSasha Levin 196bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid); 197bfc15268SAneesh Kumar K.V close_fid(p9dev, fid); 1981c7850f9SSasha Levin 199bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 200bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 201ead43b01SAneesh Kumar K.V return; 2021c7850f9SSasha Levin } 2031c7850f9SSasha Levin 204c797b6c6SAneesh Kumar K.V /* 205c797b6c6SAneesh Kumar K.V * FIXME!! Need to map to protocol independent value. Upstream 206c797b6c6SAneesh Kumar K.V * 9p also have the same BUG 207c797b6c6SAneesh Kumar K.V */ 208c797b6c6SAneesh Kumar K.V static int virtio_p9_openflags(int flags) 209c797b6c6SAneesh Kumar K.V { 210c797b6c6SAneesh Kumar K.V flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT | O_DIRECT); 211c797b6c6SAneesh Kumar K.V flags |= O_NOFOLLOW; 212c797b6c6SAneesh Kumar K.V return flags; 213c797b6c6SAneesh Kumar K.V } 214c797b6c6SAneesh Kumar K.V 21532585666SSasha Levin static bool is_dir(struct p9_fid *fid) 21632585666SSasha Levin { 21732585666SSasha Levin struct stat st; 21832585666SSasha Levin 21932585666SSasha Levin stat(fid->abs_path, &st); 22032585666SSasha Levin 22132585666SSasha Levin return S_ISDIR(st.st_mode); 22232585666SSasha Levin } 22332585666SSasha Levin 2249bb99a82SG. Campana /* path is always absolute */ 2259bb99a82SG. Campana static bool path_is_illegal(const char *path) 2269bb99a82SG. Campana { 2279bb99a82SG. Campana size_t len; 2289bb99a82SG. Campana 2299bb99a82SG. Campana if (strstr(path, "/../") != NULL) 2309bb99a82SG. Campana return true; 2319bb99a82SG. Campana 2329bb99a82SG. Campana len = strlen(path); 2339bb99a82SG. Campana if (len >= 3 && strcmp(path + len - 3, "/..") == 0) 2349bb99a82SG. Campana return true; 2359bb99a82SG. Campana 2369bb99a82SG. Campana return false; 2379bb99a82SG. Campana } 2389bb99a82SG. Campana 239d4727f2bSG. Campana static int get_full_path_helper(char *full_path, size_t size, 240d4727f2bSG. Campana const char *dirname, const char *name) 241d4727f2bSG. Campana { 242d4727f2bSG. Campana int ret; 243d4727f2bSG. Campana 244d4727f2bSG. Campana ret = snprintf(full_path, size, "%s/%s", dirname, name); 245716b2944SG. Campana if (ret >= (int)size) { 246d4727f2bSG. Campana errno = ENAMETOOLONG; 247d4727f2bSG. Campana return -1; 248d4727f2bSG. Campana } 249d4727f2bSG. Campana 250d4727f2bSG. Campana if (path_is_illegal(full_path)) { 251d4727f2bSG. Campana errno = EACCES; 252d4727f2bSG. Campana return -1; 253d4727f2bSG. Campana } 254d4727f2bSG. Campana 255d4727f2bSG. Campana return 0; 256d4727f2bSG. Campana } 257d4727f2bSG. Campana 258d4727f2bSG. Campana static int get_full_path(char *full_path, size_t size, struct p9_fid *fid, 259d4727f2bSG. Campana const char *name) 260d4727f2bSG. Campana { 261d4727f2bSG. Campana return get_full_path_helper(full_path, size, fid->abs_path, name); 262d4727f2bSG. Campana } 263d4727f2bSG. Campana 264b0922422SG. Campana static int stat_rel(struct p9_dev *p9dev, const char *path, struct stat *st) 265b0922422SG. Campana { 266b0922422SG. Campana char full_path[PATH_MAX]; 267b0922422SG. Campana 268b0922422SG. Campana if (get_full_path_helper(full_path, sizeof(full_path), p9dev->root_dir, path) != 0) 269b0922422SG. Campana return -1; 270b0922422SG. Campana 271b0922422SG. Campana if (lstat(full_path, st) != 0) 272b0922422SG. Campana return -1; 273b0922422SG. Campana 274b0922422SG. Campana return 0; 275b0922422SG. Campana } 276b0922422SG. Campana 277ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev, 278af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2791c7850f9SSasha Levin { 280c797b6c6SAneesh Kumar K.V u32 fid, flags; 2811c7850f9SSasha Levin struct stat st; 282bfc15268SAneesh Kumar K.V struct p9_qid qid; 283bfc15268SAneesh Kumar K.V struct p9_fid *new_fid; 284bfc15268SAneesh Kumar K.V 285c797b6c6SAneesh Kumar K.V 286c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid, &flags); 28731a6fb8dSSasha Levin new_fid = get_fid(p9dev, fid); 2881c7850f9SSasha Levin 28930204a77SAneesh Kumar K.V if (lstat(new_fid->abs_path, &st) < 0) 290eee1ba8eSAneesh Kumar K.V goto err_out; 2911c7850f9SSasha Levin 292c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 2931c7850f9SSasha Levin 29432585666SSasha Levin if (is_dir(new_fid)) { 2951c7850f9SSasha Levin new_fid->dir = opendir(new_fid->abs_path); 296eee1ba8eSAneesh Kumar K.V if (!new_fid->dir) 297eee1ba8eSAneesh Kumar K.V goto err_out; 298eee1ba8eSAneesh Kumar K.V } else { 299eee1ba8eSAneesh Kumar K.V new_fid->fd = open(new_fid->abs_path, 300c797b6c6SAneesh Kumar K.V virtio_p9_openflags(flags)); 301eee1ba8eSAneesh Kumar K.V if (new_fid->fd < 0) 302eee1ba8eSAneesh Kumar K.V goto err_out; 303eee1ba8eSAneesh Kumar K.V } 304c797b6c6SAneesh Kumar K.V /* FIXME!! need ot send proper iounit */ 305bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 306bfc15268SAneesh Kumar K.V 307bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 308bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 309ead43b01SAneesh Kumar K.V return; 310eee1ba8eSAneesh Kumar K.V err_out: 311eee1ba8eSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 312ead43b01SAneesh Kumar K.V return; 3131c7850f9SSasha Levin } 3141c7850f9SSasha Levin 315ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev, 316af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 3171c7850f9SSasha Levin { 318c797b6c6SAneesh Kumar K.V int fd, ret; 319bfc15268SAneesh Kumar K.V char *name; 32032832dd1SG. Campana size_t size; 321af045e53SAneesh Kumar K.V struct stat st; 322bfc15268SAneesh Kumar K.V struct p9_qid qid; 323c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 3244bc9734aSAneesh Kumar K.V char full_path[PATH_MAX]; 32504d604b6SAnisse Astier char *tmp_path; 326c797b6c6SAneesh Kumar K.V u32 dfid_val, flags, mode, gid; 327af045e53SAneesh Kumar K.V 328c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsddd", &dfid_val, 329c797b6c6SAneesh Kumar K.V &name, &flags, &mode, &gid); 33031a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 3311c7850f9SSasha Levin 332d4727f2bSG. Campana if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0) 33332832dd1SG. Campana goto err_out; 3349bb99a82SG. Campana 33532832dd1SG. Campana size = sizeof(dfid->abs_path) - (dfid->path - dfid->abs_path); 33604d604b6SAnisse Astier 33704d604b6SAnisse Astier tmp_path = strdup(dfid->path); 33804d604b6SAnisse Astier if (!tmp_path) 33904d604b6SAnisse Astier goto err_out; 34004d604b6SAnisse Astier 34104d604b6SAnisse Astier ret = snprintf(dfid->path, size, "%s/%s", tmp_path, name); 34204d604b6SAnisse Astier free(tmp_path); 34332832dd1SG. Campana if (ret >= (int)size) { 34432832dd1SG. Campana errno = ENAMETOOLONG; 34532832dd1SG. Campana if (size > 0) 34632832dd1SG. Campana dfid->path[size] = '\x00'; 34732832dd1SG. Campana goto err_out; 34832832dd1SG. Campana } 34932832dd1SG. Campana 350d4727f2bSG. Campana flags = virtio_p9_openflags(flags); 351d4727f2bSG. Campana 352c797b6c6SAneesh Kumar K.V fd = open(full_path, flags | O_CREAT, mode); 3534bc9734aSAneesh Kumar K.V if (fd < 0) 3544bc9734aSAneesh Kumar K.V goto err_out; 355c797b6c6SAneesh Kumar K.V dfid->fd = fd; 356c797b6c6SAneesh Kumar K.V 3574bc9734aSAneesh Kumar K.V if (lstat(full_path, &st) < 0) 3586c8ca053SAneesh Kumar K.V goto err_out; 3591c7850f9SSasha Levin 360c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 361c797b6c6SAneesh Kumar K.V if (ret < 0) 362c797b6c6SAneesh Kumar K.V goto err_out; 363c797b6c6SAneesh Kumar K.V 364c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 365bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 366bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 367bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 3685f900f6dSSasha Levin free(name); 3696c8ca053SAneesh Kumar K.V return; 3706c8ca053SAneesh Kumar K.V err_out: 3715f900f6dSSasha Levin free(name); 372c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 373c797b6c6SAneesh Kumar K.V return; 374c797b6c6SAneesh Kumar K.V } 375c797b6c6SAneesh Kumar K.V 376c797b6c6SAneesh Kumar K.V static void virtio_p9_mkdir(struct p9_dev *p9dev, 377c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 378c797b6c6SAneesh Kumar K.V { 379c797b6c6SAneesh Kumar K.V int ret; 380c797b6c6SAneesh Kumar K.V char *name; 381c797b6c6SAneesh Kumar K.V struct stat st; 382c797b6c6SAneesh Kumar K.V struct p9_qid qid; 383c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 384c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 385c797b6c6SAneesh Kumar K.V u32 dfid_val, mode, gid; 386c797b6c6SAneesh Kumar K.V 387c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdd", &dfid_val, 388c797b6c6SAneesh Kumar K.V &name, &mode, &gid); 38931a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 390c797b6c6SAneesh Kumar K.V 391d4727f2bSG. Campana if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0) 39232832dd1SG. Campana goto err_out; 3939bb99a82SG. Campana 394c797b6c6SAneesh Kumar K.V ret = mkdir(full_path, mode); 395c797b6c6SAneesh Kumar K.V if (ret < 0) 396c797b6c6SAneesh Kumar K.V goto err_out; 397c797b6c6SAneesh Kumar K.V 398c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0) 399c797b6c6SAneesh Kumar K.V goto err_out; 400c797b6c6SAneesh Kumar K.V 401c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 402c797b6c6SAneesh Kumar K.V if (ret < 0) 403c797b6c6SAneesh Kumar K.V goto err_out; 404c797b6c6SAneesh Kumar K.V 405c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 406c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 407c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 408c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 409c797b6c6SAneesh Kumar K.V free(name); 410c797b6c6SAneesh Kumar K.V return; 411c797b6c6SAneesh Kumar K.V err_out: 412c797b6c6SAneesh Kumar K.V free(name); 413c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 414ead43b01SAneesh Kumar K.V return; 4151c7850f9SSasha Levin } 4161c7850f9SSasha Levin 417e277a1b4SG. Campana static int join_path(struct p9_fid *fid, const char *name) 418e277a1b4SG. Campana { 419e277a1b4SG. Campana size_t len, size; 420e277a1b4SG. Campana 421e277a1b4SG. Campana size = sizeof(fid->abs_path) - (fid->path - fid->abs_path); 422e277a1b4SG. Campana len = strlen(name); 423e277a1b4SG. Campana if (len >= size) 424e277a1b4SG. Campana return -1; 425e277a1b4SG. Campana 426e277a1b4SG. Campana strncpy(fid->path, name, size); 427e277a1b4SG. Campana return 0; 428e277a1b4SG. Campana } 429e277a1b4SG. Campana 430ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev, 431af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4321c7850f9SSasha Levin { 433af045e53SAneesh Kumar K.V u8 i; 434bfc15268SAneesh Kumar K.V u16 nwqid; 435bfc15268SAneesh Kumar K.V u16 nwname; 436bfc15268SAneesh Kumar K.V struct p9_qid wqid; 437e2341580SSasha Levin struct p9_fid *new_fid, *old_fid; 438c797b6c6SAneesh Kumar K.V u32 fid_val, newfid_val; 439c797b6c6SAneesh Kumar K.V 4401c7850f9SSasha Levin 441bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname); 44231a6fb8dSSasha Levin new_fid = get_fid(p9dev, newfid_val); 4431c7850f9SSasha Levin 444bfc15268SAneesh Kumar K.V nwqid = 0; 445bfc15268SAneesh Kumar K.V if (nwname) { 44631a6fb8dSSasha Levin struct p9_fid *fid = get_fid(p9dev, fid_val); 447bfc15268SAneesh Kumar K.V 448e277a1b4SG. Campana if (join_path(new_fid, fid->path) != 0) { 449e277a1b4SG. Campana errno = ENAMETOOLONG; 450e277a1b4SG. Campana goto err_out; 451e277a1b4SG. Campana } 452e277a1b4SG. Campana 453bfc15268SAneesh Kumar K.V /* skip the space for count */ 454bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 455bfc15268SAneesh Kumar K.V for (i = 0; i < nwname; i++) { 456bfc15268SAneesh Kumar K.V struct stat st; 4571c7850f9SSasha Levin char tmp[PATH_MAX] = {0}; 458e55ed135SPekka Enberg char *str; 45932832dd1SG. Campana int ret; 460bfc15268SAneesh Kumar K.V 461bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "s", &str); 4621c7850f9SSasha Levin 4631c7850f9SSasha Levin /* Format the new path we're 'walk'ing into */ 46432832dd1SG. Campana ret = snprintf(tmp, sizeof(tmp), "%s/%s", new_fid->path, str); 46532832dd1SG. Campana if (ret >= (int)sizeof(tmp)) { 46632832dd1SG. Campana errno = ENAMETOOLONG; 46732832dd1SG. Campana goto err_out; 46832832dd1SG. Campana } 469e55ed135SPekka Enberg 470e55ed135SPekka Enberg free(str); 471e55ed135SPekka Enberg 472b0922422SG. Campana if (stat_rel(p9dev, tmp, &st) != 0) 4736c8ca053SAneesh Kumar K.V goto err_out; 4741c7850f9SSasha Levin 475c797b6c6SAneesh Kumar K.V stat2qid(&st, &wqid); 476e277a1b4SG. Campana if (join_path(new_fid, tmp) != 0) { 477e277a1b4SG. Campana errno = ENAMETOOLONG; 478e277a1b4SG. Campana goto err_out; 479e277a1b4SG. Campana } 480c797b6c6SAneesh Kumar K.V new_fid->uid = fid->uid; 481bfc15268SAneesh Kumar K.V nwqid++; 482bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &wqid); 4831c7850f9SSasha Levin } 4841c7850f9SSasha Levin } else { 485bfc15268SAneesh Kumar K.V /* 486bfc15268SAneesh Kumar K.V * update write_offset so our outlen get correct value 487bfc15268SAneesh Kumar K.V */ 488bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 489e2341580SSasha Levin old_fid = get_fid(p9dev, fid_val); 490e277a1b4SG. Campana if (join_path(new_fid, old_fid->path) != 0) { 491e277a1b4SG. Campana errno = ENAMETOOLONG; 492e277a1b4SG. Campana goto err_out; 493e277a1b4SG. Campana } 494e2341580SSasha Levin new_fid->uid = old_fid->uid; 4951c7850f9SSasha Levin } 496bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 4975529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 498bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", nwqid); 499bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 5006c8ca053SAneesh Kumar K.V return; 5016c8ca053SAneesh Kumar K.V err_out: 5026c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 503ead43b01SAneesh Kumar K.V return; 5041c7850f9SSasha Levin } 5051c7850f9SSasha Levin 506ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev, 507af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5081c7850f9SSasha Levin { 509bfc15268SAneesh Kumar K.V char *uname; 510bfc15268SAneesh Kumar K.V char *aname; 5111c7850f9SSasha Levin struct stat st; 512bfc15268SAneesh Kumar K.V struct p9_qid qid; 5131c7850f9SSasha Levin struct p9_fid *fid; 514c797b6c6SAneesh Kumar K.V u32 fid_val, afid, uid; 515bfc15268SAneesh Kumar K.V 516c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddssd", &fid_val, &afid, 517c797b6c6SAneesh Kumar K.V &uname, &aname, &uid); 5181c7850f9SSasha Levin 51939257180SPekka Enberg free(uname); 52039257180SPekka Enberg free(aname); 52139257180SPekka Enberg 52230204a77SAneesh Kumar K.V if (lstat(p9dev->root_dir, &st) < 0) 5236c8ca053SAneesh Kumar K.V goto err_out; 5241c7850f9SSasha Levin 525c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 5261c7850f9SSasha Levin 52731a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 528c797b6c6SAneesh Kumar K.V fid->uid = uid; 529e277a1b4SG. Campana if (join_path(fid, "/") != 0) { 530e277a1b4SG. Campana errno = ENAMETOOLONG; 531e277a1b4SG. Campana goto err_out; 532e277a1b4SG. Campana } 5331c7850f9SSasha Levin 534bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 535bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 536bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 5376c8ca053SAneesh Kumar K.V return; 5386c8ca053SAneesh Kumar K.V err_out: 5396c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 540ead43b01SAneesh Kumar K.V return; 5411c7850f9SSasha Levin } 5421c7850f9SSasha Levin 543c797b6c6SAneesh Kumar K.V static void virtio_p9_fill_stat(struct p9_dev *p9dev, 544c797b6c6SAneesh Kumar K.V struct stat *st, struct p9_stat_dotl *statl) 5455f900f6dSSasha Levin { 546c797b6c6SAneesh Kumar K.V memset(statl, 0, sizeof(*statl)); 547c797b6c6SAneesh Kumar K.V statl->st_mode = st->st_mode; 548c797b6c6SAneesh Kumar K.V statl->st_nlink = st->st_nlink; 549506fd90bSSasha Levin statl->st_uid = KUIDT_INIT(st->st_uid); 550506fd90bSSasha Levin statl->st_gid = KGIDT_INIT(st->st_gid); 551c797b6c6SAneesh Kumar K.V statl->st_rdev = st->st_rdev; 552c797b6c6SAneesh Kumar K.V statl->st_size = st->st_size; 553c797b6c6SAneesh Kumar K.V statl->st_blksize = st->st_blksize; 554c797b6c6SAneesh Kumar K.V statl->st_blocks = st->st_blocks; 555c797b6c6SAneesh Kumar K.V statl->st_atime_sec = st->st_atime; 556c797b6c6SAneesh Kumar K.V statl->st_atime_nsec = st->st_atim.tv_nsec; 557c797b6c6SAneesh Kumar K.V statl->st_mtime_sec = st->st_mtime; 558c797b6c6SAneesh Kumar K.V statl->st_mtime_nsec = st->st_mtim.tv_nsec; 559c797b6c6SAneesh Kumar K.V statl->st_ctime_sec = st->st_ctime; 560c797b6c6SAneesh Kumar K.V statl->st_ctime_nsec = st->st_ctim.tv_nsec; 561c797b6c6SAneesh Kumar K.V /* Currently we only support BASIC fields in stat */ 562c797b6c6SAneesh Kumar K.V statl->st_result_mask = P9_STATS_BASIC; 563c797b6c6SAneesh Kumar K.V stat2qid(st, &statl->qid); 5641c7850f9SSasha Levin } 5651c7850f9SSasha Levin 566ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev, 567af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5681c7850f9SSasha Levin { 569bfc15268SAneesh Kumar K.V u64 offset; 570bfc15268SAneesh Kumar K.V u32 fid_val; 571c797b6c6SAneesh Kumar K.V u16 iov_cnt; 572c797b6c6SAneesh Kumar K.V void *iov_base; 573c797b6c6SAneesh Kumar K.V size_t iov_len; 574bfc15268SAneesh Kumar K.V u32 count, rcount; 575bfc15268SAneesh Kumar K.V struct p9_fid *fid; 576c797b6c6SAneesh Kumar K.V 5771c7850f9SSasha Levin 578bfc15268SAneesh Kumar K.V rcount = 0; 579bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 58031a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 58150c479e0SAneesh Kumar K.V 58250c479e0SAneesh Kumar K.V iov_base = pdu->in_iov[0].iov_base; 58350c479e0SAneesh Kumar K.V iov_len = pdu->in_iov[0].iov_len; 58450c479e0SAneesh Kumar K.V iov_cnt = pdu->in_iov_cnt; 5855529bcd7SAsias He pdu->in_iov[0].iov_base += VIRTIO_9P_HDR_LEN + sizeof(u32); 5865529bcd7SAsias He pdu->in_iov[0].iov_len -= VIRTIO_9P_HDR_LEN + sizeof(u32); 5876b163a87SAneesh Kumar K.V pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov, 588bfc15268SAneesh Kumar K.V count, 5896b163a87SAneesh Kumar K.V pdu->in_iov_cnt); 590bfc15268SAneesh Kumar K.V rcount = preadv(fid->fd, pdu->in_iov, 591bfc15268SAneesh Kumar K.V pdu->in_iov_cnt, offset); 592bfc15268SAneesh Kumar K.V if (rcount > count) 593bfc15268SAneesh Kumar K.V rcount = count; 594bfc15268SAneesh Kumar K.V /* 595bfc15268SAneesh Kumar K.V * Update the iov_base back, so that rest of 596bfc15268SAneesh Kumar K.V * pdu_writef works correctly. 597bfc15268SAneesh Kumar K.V */ 59850c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_base = iov_base; 59950c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_len = iov_len; 60050c479e0SAneesh Kumar K.V pdu->in_iov_cnt = iov_cnt; 601c797b6c6SAneesh Kumar K.V 6025529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 603bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 604bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 605bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 606ead43b01SAneesh Kumar K.V return; 6071c7850f9SSasha Levin } 6081c7850f9SSasha Levin 609c797b6c6SAneesh Kumar K.V static int virtio_p9_dentry_size(struct dirent *dent) 610c797b6c6SAneesh Kumar K.V { 611c797b6c6SAneesh Kumar K.V /* 612c797b6c6SAneesh Kumar K.V * Size of each dirent: 613c797b6c6SAneesh Kumar K.V * qid(13) + offset(8) + type(1) + name_len(2) + name 614c797b6c6SAneesh Kumar K.V */ 615c797b6c6SAneesh Kumar K.V return 24 + strlen(dent->d_name); 616c797b6c6SAneesh Kumar K.V } 617c797b6c6SAneesh Kumar K.V 618c797b6c6SAneesh Kumar K.V static void virtio_p9_readdir(struct p9_dev *p9dev, 619c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 620c797b6c6SAneesh Kumar K.V { 621c797b6c6SAneesh Kumar K.V u32 fid_val; 622c797b6c6SAneesh Kumar K.V u32 count, rcount; 623c797b6c6SAneesh Kumar K.V struct stat st; 624c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 625c797b6c6SAneesh Kumar K.V struct dirent *dent; 626c797b6c6SAneesh Kumar K.V u64 offset, old_offset; 627c797b6c6SAneesh Kumar K.V 628c797b6c6SAneesh Kumar K.V rcount = 0; 629c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 63031a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 631c797b6c6SAneesh Kumar K.V 63232585666SSasha Levin if (!is_dir(fid)) { 63369bb4278SSasha Levin errno = EINVAL; 634c797b6c6SAneesh Kumar K.V goto err_out; 635c797b6c6SAneesh Kumar K.V } 636c797b6c6SAneesh Kumar K.V 637c797b6c6SAneesh Kumar K.V /* Move the offset specified */ 638c797b6c6SAneesh Kumar K.V seekdir(fid->dir, offset); 639c797b6c6SAneesh Kumar K.V 640c797b6c6SAneesh Kumar K.V old_offset = offset; 641c797b6c6SAneesh Kumar K.V /* If reading a dir, fill the buffer with p9_stat entries */ 642c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir); 643c797b6c6SAneesh Kumar K.V 644c797b6c6SAneesh Kumar K.V /* Skip the space for writing count */ 645c797b6c6SAneesh Kumar K.V pdu->write_offset += sizeof(u32); 646c797b6c6SAneesh Kumar K.V while (dent) { 647c797b6c6SAneesh Kumar K.V u32 read; 648c797b6c6SAneesh Kumar K.V struct p9_qid qid; 649c797b6c6SAneesh Kumar K.V 650c797b6c6SAneesh Kumar K.V if ((rcount + virtio_p9_dentry_size(dent)) > count) { 651c797b6c6SAneesh Kumar K.V /* seek to the previous offset and return */ 652c797b6c6SAneesh Kumar K.V seekdir(fid->dir, old_offset); 653c797b6c6SAneesh Kumar K.V break; 654c797b6c6SAneesh Kumar K.V } 655c797b6c6SAneesh Kumar K.V old_offset = dent->d_off; 656b0922422SG. Campana if (stat_rel(p9dev, dent->d_name, &st) != 0) 657b0922422SG. Campana memset(&st, -1, sizeof(st)); 658c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 659c797b6c6SAneesh Kumar K.V read = pdu->write_offset; 660c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qqbs", &qid, dent->d_off, 661c797b6c6SAneesh Kumar K.V dent->d_type, dent->d_name); 662c797b6c6SAneesh Kumar K.V rcount += pdu->write_offset - read; 663c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir); 664c797b6c6SAneesh Kumar K.V } 665c797b6c6SAneesh Kumar K.V 6665529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 667c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 668c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 669c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 670c797b6c6SAneesh Kumar K.V return; 671c797b6c6SAneesh Kumar K.V err_out: 672c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 673c797b6c6SAneesh Kumar K.V return; 674c797b6c6SAneesh Kumar K.V } 675c797b6c6SAneesh Kumar K.V 676c797b6c6SAneesh Kumar K.V 677c797b6c6SAneesh Kumar K.V static void virtio_p9_getattr(struct p9_dev *p9dev, 678af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 6791c7850f9SSasha Levin { 680bfc15268SAneesh Kumar K.V u32 fid_val; 681af045e53SAneesh Kumar K.V struct stat st; 682c797b6c6SAneesh Kumar K.V u64 request_mask; 683bfc15268SAneesh Kumar K.V struct p9_fid *fid; 684c797b6c6SAneesh Kumar K.V struct p9_stat_dotl statl; 6851c7850f9SSasha Levin 686c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dq", &fid_val, &request_mask); 68731a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 68830204a77SAneesh Kumar K.V if (lstat(fid->abs_path, &st) < 0) 6896c8ca053SAneesh Kumar K.V goto err_out; 6901c7850f9SSasha Levin 691c797b6c6SAneesh Kumar K.V virtio_p9_fill_stat(p9dev, &st, &statl); 692c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "A", &statl); 693bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 694bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 695ead43b01SAneesh Kumar K.V return; 6966c8ca053SAneesh Kumar K.V err_out: 6976c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 6986c8ca053SAneesh Kumar K.V return; 6991c7850f9SSasha Levin } 7001c7850f9SSasha Levin 701c797b6c6SAneesh Kumar K.V /* FIXME!! from linux/fs.h */ 702c797b6c6SAneesh Kumar K.V /* 703c797b6c6SAneesh Kumar K.V * Attribute flags. These should be or-ed together to figure out what 704c797b6c6SAneesh Kumar K.V * has been changed! 705c797b6c6SAneesh Kumar K.V */ 706c797b6c6SAneesh Kumar K.V #define ATTR_MODE (1 << 0) 707c797b6c6SAneesh Kumar K.V #define ATTR_UID (1 << 1) 708c797b6c6SAneesh Kumar K.V #define ATTR_GID (1 << 2) 709c797b6c6SAneesh Kumar K.V #define ATTR_SIZE (1 << 3) 710c797b6c6SAneesh Kumar K.V #define ATTR_ATIME (1 << 4) 711c797b6c6SAneesh Kumar K.V #define ATTR_MTIME (1 << 5) 712c797b6c6SAneesh Kumar K.V #define ATTR_CTIME (1 << 6) 713c797b6c6SAneesh Kumar K.V #define ATTR_ATIME_SET (1 << 7) 714c797b6c6SAneesh Kumar K.V #define ATTR_MTIME_SET (1 << 8) 715c797b6c6SAneesh Kumar K.V #define ATTR_FORCE (1 << 9) /* Not a change, but a change it */ 716c797b6c6SAneesh Kumar K.V #define ATTR_ATTR_FLAG (1 << 10) 717c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SUID (1 << 11) 718c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SGID (1 << 12) 719c797b6c6SAneesh Kumar K.V #define ATTR_FILE (1 << 13) 720c797b6c6SAneesh Kumar K.V #define ATTR_KILL_PRIV (1 << 14) 721c797b6c6SAneesh Kumar K.V #define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ 722c797b6c6SAneesh Kumar K.V #define ATTR_TIMES_SET (1 << 16) 723c797b6c6SAneesh Kumar K.V 724c797b6c6SAneesh Kumar K.V #define ATTR_MASK 127 725c797b6c6SAneesh Kumar K.V 726c797b6c6SAneesh Kumar K.V static void virtio_p9_setattr(struct p9_dev *p9dev, 727af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 7281c7850f9SSasha Levin { 729c797b6c6SAneesh Kumar K.V int ret = 0; 730bfc15268SAneesh Kumar K.V u32 fid_val; 731bfc15268SAneesh Kumar K.V struct p9_fid *fid; 732c797b6c6SAneesh Kumar K.V struct p9_iattr_dotl p9attr; 7331c7850f9SSasha Levin 734c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dI", &fid_val, &p9attr); 73531a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 7361c7850f9SSasha Levin 737c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MODE) { 738c797b6c6SAneesh Kumar K.V ret = chmod(fid->abs_path, p9attr.mode); 739c797b6c6SAneesh Kumar K.V if (ret < 0) 740c797b6c6SAneesh Kumar K.V goto err_out; 741c797b6c6SAneesh Kumar K.V } 742c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_ATIME | ATTR_MTIME)) { 743c797b6c6SAneesh Kumar K.V struct timespec times[2]; 744c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME) { 745c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME_SET) { 746c797b6c6SAneesh Kumar K.V times[0].tv_sec = p9attr.atime_sec; 747c797b6c6SAneesh Kumar K.V times[0].tv_nsec = p9attr.atime_nsec; 748c797b6c6SAneesh Kumar K.V } else { 749c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_NOW; 750c797b6c6SAneesh Kumar K.V } 751c797b6c6SAneesh Kumar K.V } else { 752c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_OMIT; 753c797b6c6SAneesh Kumar K.V } 754c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME) { 755c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME_SET) { 756c797b6c6SAneesh Kumar K.V times[1].tv_sec = p9attr.mtime_sec; 757c797b6c6SAneesh Kumar K.V times[1].tv_nsec = p9attr.mtime_nsec; 758c797b6c6SAneesh Kumar K.V } else { 759c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_NOW; 760c797b6c6SAneesh Kumar K.V } 761c797b6c6SAneesh Kumar K.V } else 762c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_OMIT; 763c797b6c6SAneesh Kumar K.V 764c797b6c6SAneesh Kumar K.V ret = utimensat(-1, fid->abs_path, times, AT_SYMLINK_NOFOLLOW); 765c797b6c6SAneesh Kumar K.V if (ret < 0) 766c797b6c6SAneesh Kumar K.V goto err_out; 767c797b6c6SAneesh Kumar K.V } 768c797b6c6SAneesh Kumar K.V /* 769c797b6c6SAneesh Kumar K.V * If the only valid entry in iattr is ctime we can call 770c797b6c6SAneesh Kumar K.V * chown(-1,-1) to update the ctime of the file 771c797b6c6SAneesh Kumar K.V */ 772c797b6c6SAneesh Kumar K.V if ((p9attr.valid & (ATTR_UID | ATTR_GID)) || 773c797b6c6SAneesh Kumar K.V ((p9attr.valid & ATTR_CTIME) 774c797b6c6SAneesh Kumar K.V && !((p9attr.valid & ATTR_MASK) & ~ATTR_CTIME))) { 775c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_UID)) 776506fd90bSSasha Levin p9attr.uid = KUIDT_INIT(-1); 777c797b6c6SAneesh Kumar K.V 778c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_GID)) 779506fd90bSSasha Levin p9attr.gid = KGIDT_INIT(-1); 780c797b6c6SAneesh Kumar K.V 781506fd90bSSasha Levin ret = lchown(fid->abs_path, __kuid_val(p9attr.uid), 782506fd90bSSasha Levin __kgid_val(p9attr.gid)); 783c797b6c6SAneesh Kumar K.V if (ret < 0) 784c797b6c6SAneesh Kumar K.V goto err_out; 785c797b6c6SAneesh Kumar K.V } 786c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_SIZE)) { 787c797b6c6SAneesh Kumar K.V ret = truncate(fid->abs_path, p9attr.size); 788c797b6c6SAneesh Kumar K.V if (ret < 0) 789c797b6c6SAneesh Kumar K.V goto err_out; 790c797b6c6SAneesh Kumar K.V } 7915529bcd7SAsias He *outlen = VIRTIO_9P_HDR_LEN; 792bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 793ead43b01SAneesh Kumar K.V return; 7944bc9734aSAneesh Kumar K.V err_out: 7954bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 7964bc9734aSAneesh Kumar K.V return; 7971c7850f9SSasha Levin } 7981c7850f9SSasha Levin 799ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev, 800af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 8011c7850f9SSasha Levin { 8024bc9734aSAneesh Kumar K.V 803bfc15268SAneesh Kumar K.V u64 offset; 804bfc15268SAneesh Kumar K.V u32 fid_val; 8054bc9734aSAneesh Kumar K.V u32 count; 8064bc9734aSAneesh Kumar K.V ssize_t res; 80750c479e0SAneesh Kumar K.V u16 iov_cnt; 80850c479e0SAneesh Kumar K.V void *iov_base; 80950c479e0SAneesh Kumar K.V size_t iov_len; 810bfc15268SAneesh Kumar K.V struct p9_fid *fid; 811b064b05aSAneesh Kumar K.V /* u32 fid + u64 offset + u32 count */ 812b064b05aSAneesh Kumar K.V int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32); 8131c7850f9SSasha Levin 814bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 81531a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 816af045e53SAneesh Kumar K.V 81750c479e0SAneesh Kumar K.V iov_base = pdu->out_iov[0].iov_base; 81850c479e0SAneesh Kumar K.V iov_len = pdu->out_iov[0].iov_len; 81950c479e0SAneesh Kumar K.V iov_cnt = pdu->out_iov_cnt; 82050c479e0SAneesh Kumar K.V 821bfc15268SAneesh Kumar K.V /* Adjust the iovec to skip the header and meta data */ 822b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size); 823b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_len -= (sizeof(struct p9_msg) + twrite_size); 824bfc15268SAneesh Kumar K.V pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count, 8256b163a87SAneesh Kumar K.V pdu->out_iov_cnt); 8264bc9734aSAneesh Kumar K.V res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset); 82750c479e0SAneesh Kumar K.V /* 82850c479e0SAneesh Kumar K.V * Update the iov_base back, so that rest of 82950c479e0SAneesh Kumar K.V * pdu_readf works correctly. 83050c479e0SAneesh Kumar K.V */ 83150c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_base = iov_base; 83250c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_len = iov_len; 83350c479e0SAneesh Kumar K.V pdu->out_iov_cnt = iov_cnt; 834c797b6c6SAneesh Kumar K.V 8354bc9734aSAneesh Kumar K.V if (res < 0) 8364bc9734aSAneesh Kumar K.V goto err_out; 8374bc9734aSAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", res); 838bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 839bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 840ead43b01SAneesh Kumar K.V return; 8414bc9734aSAneesh Kumar K.V err_out: 8424bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 8434bc9734aSAneesh Kumar K.V return; 8441c7850f9SSasha Levin } 8451c7850f9SSasha Levin 8466fc5cd9bSSasha Levin static void virtio_p9_remove(struct p9_dev *p9dev, 8476fc5cd9bSSasha Levin struct p9_pdu *pdu, u32 *outlen) 8486fc5cd9bSSasha Levin { 8496fc5cd9bSSasha Levin int ret; 8506fc5cd9bSSasha Levin u32 fid_val; 8516fc5cd9bSSasha Levin struct p9_fid *fid; 8526fc5cd9bSSasha Levin 8536fc5cd9bSSasha Levin virtio_p9_pdu_readf(pdu, "d", &fid_val); 85431a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 8556fc5cd9bSSasha Levin 8569b604a9cSSasha Levin ret = remove(fid->abs_path); 8576fc5cd9bSSasha Levin if (ret < 0) 8586fc5cd9bSSasha Levin goto err_out; 8596fc5cd9bSSasha Levin *outlen = pdu->write_offset; 8606fc5cd9bSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 8616fc5cd9bSSasha Levin return; 8626fc5cd9bSSasha Levin 8636fc5cd9bSSasha Levin err_out: 8646fc5cd9bSSasha Levin virtio_p9_error_reply(p9dev, pdu, errno, outlen); 8656fc5cd9bSSasha Levin return; 8666fc5cd9bSSasha Levin } 8676fc5cd9bSSasha Levin 868f161f28bSSasha Levin static void virtio_p9_rename(struct p9_dev *p9dev, 869f161f28bSSasha Levin struct p9_pdu *pdu, u32 *outlen) 870f161f28bSSasha Levin { 871f161f28bSSasha Levin int ret; 872f161f28bSSasha Levin u32 fid_val, new_fid_val; 873f161f28bSSasha Levin struct p9_fid *fid, *new_fid; 874f161f28bSSasha Levin char full_path[PATH_MAX], *new_name; 875f161f28bSSasha Levin 876f161f28bSSasha Levin virtio_p9_pdu_readf(pdu, "dds", &fid_val, &new_fid_val, &new_name); 87731a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 87831a6fb8dSSasha Levin new_fid = get_fid(p9dev, new_fid_val); 879f161f28bSSasha Levin 880d4727f2bSG. Campana if (get_full_path(full_path, sizeof(full_path), new_fid, new_name) != 0) 88132832dd1SG. Campana goto err_out; 8829bb99a82SG. Campana 883f161f28bSSasha Levin ret = rename(fid->abs_path, full_path); 884f161f28bSSasha Levin if (ret < 0) 885f161f28bSSasha Levin goto err_out; 886f161f28bSSasha Levin *outlen = pdu->write_offset; 887f161f28bSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 888f161f28bSSasha Levin return; 889f161f28bSSasha Levin 890f161f28bSSasha Levin err_out: 891f161f28bSSasha Levin virtio_p9_error_reply(p9dev, pdu, errno, outlen); 892f161f28bSSasha Levin return; 893f161f28bSSasha Levin } 894f161f28bSSasha Levin 895c797b6c6SAneesh Kumar K.V static void virtio_p9_readlink(struct p9_dev *p9dev, 896c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 897c797b6c6SAneesh Kumar K.V { 898c797b6c6SAneesh Kumar K.V int ret; 899c797b6c6SAneesh Kumar K.V u32 fid_val; 900c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 901c797b6c6SAneesh Kumar K.V char target_path[PATH_MAX]; 902c797b6c6SAneesh Kumar K.V 903c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 90431a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 905c797b6c6SAneesh Kumar K.V 906c797b6c6SAneesh Kumar K.V memset(target_path, 0, PATH_MAX); 907c797b6c6SAneesh Kumar K.V ret = readlink(fid->abs_path, target_path, PATH_MAX - 1); 908c797b6c6SAneesh Kumar K.V if (ret < 0) 909c797b6c6SAneesh Kumar K.V goto err_out; 910c797b6c6SAneesh Kumar K.V 911c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "s", target_path); 912c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 913c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 914c797b6c6SAneesh Kumar K.V return; 915c797b6c6SAneesh Kumar K.V err_out: 916c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 917c797b6c6SAneesh Kumar K.V return; 918c797b6c6SAneesh Kumar K.V } 919c797b6c6SAneesh Kumar K.V 920c797b6c6SAneesh Kumar K.V static void virtio_p9_statfs(struct p9_dev *p9dev, 921c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 922c797b6c6SAneesh Kumar K.V { 923c797b6c6SAneesh Kumar K.V int ret; 924c797b6c6SAneesh Kumar K.V u64 fsid; 925c797b6c6SAneesh Kumar K.V u32 fid_val; 926c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 927c797b6c6SAneesh Kumar K.V struct statfs stat_buf; 928c797b6c6SAneesh Kumar K.V 929c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 93031a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 931c797b6c6SAneesh Kumar K.V 932c797b6c6SAneesh Kumar K.V ret = statfs(fid->abs_path, &stat_buf); 933c797b6c6SAneesh Kumar K.V if (ret < 0) 934c797b6c6SAneesh Kumar K.V goto err_out; 935c797b6c6SAneesh Kumar K.V /* FIXME!! f_blocks needs update based on client msize */ 936c797b6c6SAneesh Kumar K.V fsid = (unsigned int) stat_buf.f_fsid.__val[0] | 937c797b6c6SAneesh Kumar K.V (unsigned long long)stat_buf.f_fsid.__val[1] << 32; 938c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ddqqqqqqd", stat_buf.f_type, 939c797b6c6SAneesh Kumar K.V stat_buf.f_bsize, stat_buf.f_blocks, 940c797b6c6SAneesh Kumar K.V stat_buf.f_bfree, stat_buf.f_bavail, 941c797b6c6SAneesh Kumar K.V stat_buf.f_files, stat_buf.f_ffree, 942c797b6c6SAneesh Kumar K.V fsid, stat_buf.f_namelen); 943c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 944c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 945c797b6c6SAneesh Kumar K.V return; 946c797b6c6SAneesh Kumar K.V err_out: 947c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 948c797b6c6SAneesh Kumar K.V return; 949c797b6c6SAneesh Kumar K.V } 950c797b6c6SAneesh Kumar K.V 951c797b6c6SAneesh Kumar K.V static void virtio_p9_mknod(struct p9_dev *p9dev, 952c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 953c797b6c6SAneesh Kumar K.V { 954c797b6c6SAneesh Kumar K.V int ret; 955c797b6c6SAneesh Kumar K.V char *name; 956c797b6c6SAneesh Kumar K.V struct stat st; 957c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 958c797b6c6SAneesh Kumar K.V struct p9_qid qid; 959c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 960c797b6c6SAneesh Kumar K.V u32 fid_val, mode, major, minor, gid; 961c797b6c6SAneesh Kumar K.V 962c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdddd", &fid_val, &name, &mode, 963c797b6c6SAneesh Kumar K.V &major, &minor, &gid); 964c797b6c6SAneesh Kumar K.V 96531a6fb8dSSasha Levin dfid = get_fid(p9dev, fid_val); 96632832dd1SG. Campana 967d4727f2bSG. Campana if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0) 9689bb99a82SG. Campana goto err_out; 9699bb99a82SG. Campana 970c797b6c6SAneesh Kumar K.V ret = mknod(full_path, mode, makedev(major, minor)); 971c797b6c6SAneesh Kumar K.V if (ret < 0) 972c797b6c6SAneesh Kumar K.V goto err_out; 973c797b6c6SAneesh Kumar K.V 974c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0) 975c797b6c6SAneesh Kumar K.V goto err_out; 976c797b6c6SAneesh Kumar K.V 977c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 978c797b6c6SAneesh Kumar K.V if (ret < 0) 979c797b6c6SAneesh Kumar K.V goto err_out; 980c797b6c6SAneesh Kumar K.V 981c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 982c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 983c797b6c6SAneesh Kumar K.V free(name); 984c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 985c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 986c797b6c6SAneesh Kumar K.V return; 987c797b6c6SAneesh Kumar K.V err_out: 988c797b6c6SAneesh Kumar K.V free(name); 989c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 990c797b6c6SAneesh Kumar K.V return; 991c797b6c6SAneesh Kumar K.V } 992c797b6c6SAneesh Kumar K.V 993c797b6c6SAneesh Kumar K.V static void virtio_p9_fsync(struct p9_dev *p9dev, 994c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 995c797b6c6SAneesh Kumar K.V { 996644140efSRussell King int ret, fd; 997c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 998c797b6c6SAneesh Kumar K.V u32 fid_val, datasync; 999c797b6c6SAneesh Kumar K.V 1000c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid_val, &datasync); 100131a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 1002c797b6c6SAneesh Kumar K.V 1003644140efSRussell King if (fid->dir) 1004644140efSRussell King fd = dirfd(fid->dir); 1005c797b6c6SAneesh Kumar K.V else 1006644140efSRussell King fd = fid->fd; 1007644140efSRussell King 1008644140efSRussell King if (datasync) 1009644140efSRussell King ret = fdatasync(fd); 1010644140efSRussell King else 1011644140efSRussell King ret = fsync(fd); 1012c797b6c6SAneesh Kumar K.V if (ret < 0) 1013c797b6c6SAneesh Kumar K.V goto err_out; 1014c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1015c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1016c797b6c6SAneesh Kumar K.V return; 1017c797b6c6SAneesh Kumar K.V err_out: 1018c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1019c797b6c6SAneesh Kumar K.V return; 1020c797b6c6SAneesh Kumar K.V } 1021c797b6c6SAneesh Kumar K.V 1022c797b6c6SAneesh Kumar K.V static void virtio_p9_symlink(struct p9_dev *p9dev, 1023c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1024c797b6c6SAneesh Kumar K.V { 1025c797b6c6SAneesh Kumar K.V int ret; 1026c797b6c6SAneesh Kumar K.V struct stat st; 1027c797b6c6SAneesh Kumar K.V u32 fid_val, gid; 1028c797b6c6SAneesh Kumar K.V struct p9_qid qid; 1029c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 1030c797b6c6SAneesh Kumar K.V char new_name[PATH_MAX]; 1031c797b6c6SAneesh Kumar K.V char *old_path, *name; 1032c797b6c6SAneesh Kumar K.V 1033c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dssd", &fid_val, &name, &old_path, &gid); 1034c797b6c6SAneesh Kumar K.V 103531a6fb8dSSasha Levin dfid = get_fid(p9dev, fid_val); 103632832dd1SG. Campana 1037d4727f2bSG. Campana if (get_full_path(new_name, sizeof(new_name), dfid, name) != 0) 10389bb99a82SG. Campana goto err_out; 10399bb99a82SG. Campana 1040c797b6c6SAneesh Kumar K.V ret = symlink(old_path, new_name); 1041c797b6c6SAneesh Kumar K.V if (ret < 0) 1042c797b6c6SAneesh Kumar K.V goto err_out; 1043c797b6c6SAneesh Kumar K.V 1044c797b6c6SAneesh Kumar K.V if (lstat(new_name, &st) < 0) 1045c797b6c6SAneesh Kumar K.V goto err_out; 1046c797b6c6SAneesh Kumar K.V 1047c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 1048c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 1049c797b6c6SAneesh Kumar K.V free(name); 1050c797b6c6SAneesh Kumar K.V free(old_path); 1051c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1052c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1053c797b6c6SAneesh Kumar K.V return; 1054c797b6c6SAneesh Kumar K.V err_out: 1055c797b6c6SAneesh Kumar K.V free(name); 1056c797b6c6SAneesh Kumar K.V free(old_path); 1057c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1058c797b6c6SAneesh Kumar K.V return; 1059c797b6c6SAneesh Kumar K.V } 1060c797b6c6SAneesh Kumar K.V 1061c797b6c6SAneesh Kumar K.V static void virtio_p9_link(struct p9_dev *p9dev, 1062c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1063c797b6c6SAneesh Kumar K.V { 1064c797b6c6SAneesh Kumar K.V int ret; 1065c797b6c6SAneesh Kumar K.V char *name; 1066c797b6c6SAneesh Kumar K.V u32 fid_val, dfid_val; 1067c797b6c6SAneesh Kumar K.V struct p9_fid *dfid, *fid; 1068c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 1069c797b6c6SAneesh Kumar K.V 1070c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dds", &dfid_val, &fid_val, &name); 1071c797b6c6SAneesh Kumar K.V 107231a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 107331a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 107432832dd1SG. Campana 1075d4727f2bSG. Campana if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0) 10769bb99a82SG. Campana goto err_out; 10779bb99a82SG. Campana 1078c797b6c6SAneesh Kumar K.V ret = link(fid->abs_path, full_path); 1079c797b6c6SAneesh Kumar K.V if (ret < 0) 1080c797b6c6SAneesh Kumar K.V goto err_out; 1081c797b6c6SAneesh Kumar K.V free(name); 1082c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1083c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1084c797b6c6SAneesh Kumar K.V return; 1085c797b6c6SAneesh Kumar K.V err_out: 1086c797b6c6SAneesh Kumar K.V free(name); 1087c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1088c797b6c6SAneesh Kumar K.V return; 1089c797b6c6SAneesh Kumar K.V 1090c797b6c6SAneesh Kumar K.V } 1091c797b6c6SAneesh Kumar K.V 1092c797b6c6SAneesh Kumar K.V static void virtio_p9_lock(struct p9_dev *p9dev, 1093c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1094c797b6c6SAneesh Kumar K.V { 1095c797b6c6SAneesh Kumar K.V u8 ret; 1096c797b6c6SAneesh Kumar K.V u32 fid_val; 1097c797b6c6SAneesh Kumar K.V struct p9_flock flock; 1098c797b6c6SAneesh Kumar K.V 1099c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbdqqds", &fid_val, &flock.type, 1100c797b6c6SAneesh Kumar K.V &flock.flags, &flock.start, &flock.length, 1101c797b6c6SAneesh Kumar K.V &flock.proc_id, &flock.client_id); 1102c797b6c6SAneesh Kumar K.V 1103c797b6c6SAneesh Kumar K.V /* Just return success */ 1104c797b6c6SAneesh Kumar K.V ret = P9_LOCK_SUCCESS; 1105c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", ret); 1106c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1107c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1108c797b6c6SAneesh Kumar K.V free(flock.client_id); 1109c797b6c6SAneesh Kumar K.V return; 1110c797b6c6SAneesh Kumar K.V } 1111c797b6c6SAneesh Kumar K.V 1112c797b6c6SAneesh Kumar K.V static void virtio_p9_getlock(struct p9_dev *p9dev, 1113c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1114c797b6c6SAneesh Kumar K.V { 1115c797b6c6SAneesh Kumar K.V u32 fid_val; 1116c797b6c6SAneesh Kumar K.V struct p9_getlock glock; 1117c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbqqds", &fid_val, &glock.type, 1118c797b6c6SAneesh Kumar K.V &glock.start, &glock.length, &glock.proc_id, 1119c797b6c6SAneesh Kumar K.V &glock.client_id); 1120c797b6c6SAneesh Kumar K.V 1121c797b6c6SAneesh Kumar K.V /* Just return success */ 1122c797b6c6SAneesh Kumar K.V glock.type = F_UNLCK; 1123c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "bqqds", glock.type, 1124c797b6c6SAneesh Kumar K.V glock.start, glock.length, glock.proc_id, 1125c797b6c6SAneesh Kumar K.V glock.client_id); 1126c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1127c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1128c797b6c6SAneesh Kumar K.V free(glock.client_id); 1129c797b6c6SAneesh Kumar K.V return; 1130c797b6c6SAneesh Kumar K.V } 1131c797b6c6SAneesh Kumar K.V 1132c797b6c6SAneesh Kumar K.V static int virtio_p9_ancestor(char *path, char *ancestor) 1133c797b6c6SAneesh Kumar K.V { 1134c797b6c6SAneesh Kumar K.V int size = strlen(ancestor); 1135c797b6c6SAneesh Kumar K.V if (!strncmp(path, ancestor, size)) { 1136c797b6c6SAneesh Kumar K.V /* 1137c797b6c6SAneesh Kumar K.V * Now check whether ancestor is a full name or 1138c797b6c6SAneesh Kumar K.V * or directory component and not just part 1139c797b6c6SAneesh Kumar K.V * of a name. 1140c797b6c6SAneesh Kumar K.V */ 1141c797b6c6SAneesh Kumar K.V if (path[size] == '\0' || path[size] == '/') 1142c797b6c6SAneesh Kumar K.V return 1; 1143c797b6c6SAneesh Kumar K.V } 1144c797b6c6SAneesh Kumar K.V return 0; 1145c797b6c6SAneesh Kumar K.V } 1146c797b6c6SAneesh Kumar K.V 1147e277a1b4SG. Campana static int virtio_p9_fix_path(struct p9_fid *fid, char *old_name, char *new_name) 1148c797b6c6SAneesh Kumar K.V { 1149e277a1b4SG. Campana int ret; 1150e277a1b4SG. Campana char *p, tmp_name[PATH_MAX]; 1151c797b6c6SAneesh Kumar K.V size_t rp_sz = strlen(old_name); 1152c797b6c6SAneesh Kumar K.V 1153e277a1b4SG. Campana if (rp_sz == strlen(fid->path)) { 1154c797b6c6SAneesh Kumar K.V /* replace the full name */ 1155e277a1b4SG. Campana p = new_name; 1156e277a1b4SG. Campana } else { 1157c797b6c6SAneesh Kumar K.V /* save the trailing path details */ 1158e277a1b4SG. Campana ret = snprintf(tmp_name, sizeof(tmp_name), "%s%s", new_name, fid->path + rp_sz); 1159e277a1b4SG. Campana if (ret >= (int)sizeof(tmp_name)) 1160e277a1b4SG. Campana return -1; 1161e277a1b4SG. Campana p = tmp_name; 1162e277a1b4SG. Campana } 1163e277a1b4SG. Campana 1164e277a1b4SG. Campana return join_path(fid, p); 1165c797b6c6SAneesh Kumar K.V } 1166c797b6c6SAneesh Kumar K.V 1167e2341580SSasha Levin static void rename_fids(struct p9_dev *p9dev, char *old_name, char *new_name) 1168e2341580SSasha Levin { 1169e2341580SSasha Levin struct rb_node *node = rb_first(&p9dev->fids); 1170e2341580SSasha Levin 1171e2341580SSasha Levin while (node) { 1172e2341580SSasha Levin struct p9_fid *fid = rb_entry(node, struct p9_fid, node); 1173e2341580SSasha Levin 1174e2341580SSasha Levin if (fid->fid != P9_NOFID && virtio_p9_ancestor(fid->path, old_name)) { 1175e277a1b4SG. Campana virtio_p9_fix_path(fid, old_name, new_name); 1176e2341580SSasha Levin } 1177e2341580SSasha Levin node = rb_next(node); 1178e2341580SSasha Levin } 1179e2341580SSasha Levin } 1180e2341580SSasha Levin 1181c797b6c6SAneesh Kumar K.V static void virtio_p9_renameat(struct p9_dev *p9dev, 1182c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1183c797b6c6SAneesh Kumar K.V { 1184e2341580SSasha Levin int ret; 1185c797b6c6SAneesh Kumar K.V char *old_name, *new_name; 1186c797b6c6SAneesh Kumar K.V u32 old_dfid_val, new_dfid_val; 1187c797b6c6SAneesh Kumar K.V struct p9_fid *old_dfid, *new_dfid; 1188c797b6c6SAneesh Kumar K.V char old_full_path[PATH_MAX], new_full_path[PATH_MAX]; 1189c797b6c6SAneesh Kumar K.V 1190c797b6c6SAneesh Kumar K.V 1191c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsds", &old_dfid_val, &old_name, 1192c797b6c6SAneesh Kumar K.V &new_dfid_val, &new_name); 1193c797b6c6SAneesh Kumar K.V 119431a6fb8dSSasha Levin old_dfid = get_fid(p9dev, old_dfid_val); 119531a6fb8dSSasha Levin new_dfid = get_fid(p9dev, new_dfid_val); 1196c797b6c6SAneesh Kumar K.V 1197d4727f2bSG. Campana if (get_full_path(old_full_path, sizeof(old_full_path), old_dfid, old_name) != 0) 119832832dd1SG. Campana goto err_out; 119932832dd1SG. Campana 1200d4727f2bSG. Campana if (get_full_path(new_full_path, sizeof(new_full_path), new_dfid, new_name) != 0) 120132832dd1SG. Campana goto err_out; 12029bb99a82SG. Campana 1203c797b6c6SAneesh Kumar K.V ret = rename(old_full_path, new_full_path); 1204c797b6c6SAneesh Kumar K.V if (ret < 0) 1205c797b6c6SAneesh Kumar K.V goto err_out; 1206c797b6c6SAneesh Kumar K.V /* 1207c797b6c6SAneesh Kumar K.V * Now fix path in other fids, if the renamed path is part of 1208c797b6c6SAneesh Kumar K.V * that. 1209c797b6c6SAneesh Kumar K.V */ 1210e2341580SSasha Levin rename_fids(p9dev, old_name, new_name); 1211c797b6c6SAneesh Kumar K.V free(old_name); 1212c797b6c6SAneesh Kumar K.V free(new_name); 1213c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1214c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1215c797b6c6SAneesh Kumar K.V return; 1216c797b6c6SAneesh Kumar K.V err_out: 1217c797b6c6SAneesh Kumar K.V free(old_name); 1218c797b6c6SAneesh Kumar K.V free(new_name); 1219c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1220c797b6c6SAneesh Kumar K.V return; 1221c797b6c6SAneesh Kumar K.V } 1222c797b6c6SAneesh Kumar K.V 1223c797b6c6SAneesh Kumar K.V static void virtio_p9_unlinkat(struct p9_dev *p9dev, 1224c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1225c797b6c6SAneesh Kumar K.V { 1226c797b6c6SAneesh Kumar K.V int ret; 1227c797b6c6SAneesh Kumar K.V char *name; 1228c797b6c6SAneesh Kumar K.V u32 fid_val, flags; 1229c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 1230c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 1231c797b6c6SAneesh Kumar K.V 1232c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsd", &fid_val, &name, &flags); 123331a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 1234c797b6c6SAneesh Kumar K.V 1235d4727f2bSG. Campana if (get_full_path(full_path, sizeof(full_path), fid, name) != 0) 123632832dd1SG. Campana goto err_out; 12379bb99a82SG. Campana 1238c797b6c6SAneesh Kumar K.V ret = remove(full_path); 1239c797b6c6SAneesh Kumar K.V if (ret < 0) 1240c797b6c6SAneesh Kumar K.V goto err_out; 1241c797b6c6SAneesh Kumar K.V free(name); 1242c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1243c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1244c797b6c6SAneesh Kumar K.V return; 1245c797b6c6SAneesh Kumar K.V err_out: 1246c797b6c6SAneesh Kumar K.V free(name); 1247c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1248c797b6c6SAneesh Kumar K.V return; 1249c797b6c6SAneesh Kumar K.V } 1250c797b6c6SAneesh Kumar K.V 12515cc808aaSSasha Levin static void virtio_p9_flush(struct p9_dev *p9dev, 12525cc808aaSSasha Levin struct p9_pdu *pdu, u32 *outlen) 12535cc808aaSSasha Levin { 12545cc808aaSSasha Levin u16 tag, oldtag; 12555cc808aaSSasha Levin 12565cc808aaSSasha Levin virtio_p9_pdu_readf(pdu, "ww", &tag, &oldtag); 12575cc808aaSSasha Levin virtio_p9_pdu_writef(pdu, "w", tag); 12585cc808aaSSasha Levin *outlen = pdu->write_offset; 12595cc808aaSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 12605cc808aaSSasha Levin 12615cc808aaSSasha Levin return; 12625cc808aaSSasha Levin } 12635cc808aaSSasha Levin 1264c797b6c6SAneesh Kumar K.V static void virtio_p9_eopnotsupp(struct p9_dev *p9dev, 1265c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1266c797b6c6SAneesh Kumar K.V { 1267c797b6c6SAneesh Kumar K.V return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen); 1268c797b6c6SAneesh Kumar K.V } 1269c797b6c6SAneesh Kumar K.V 1270ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev, 1271af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen); 1272b4422bf3SAneesh Kumar K.V 1273c797b6c6SAneesh Kumar K.V /* FIXME should be removed when merging with latest linus tree */ 1274c797b6c6SAneesh Kumar K.V #define P9_TRENAMEAT 74 1275c797b6c6SAneesh Kumar K.V #define P9_TUNLINKAT 76 1276c797b6c6SAneesh Kumar K.V 1277c797b6c6SAneesh Kumar K.V static p9_handler *virtio_9p_dotl_handler [] = { 1278c797b6c6SAneesh Kumar K.V [P9_TREADDIR] = virtio_p9_readdir, 1279c797b6c6SAneesh Kumar K.V [P9_TSTATFS] = virtio_p9_statfs, 1280c797b6c6SAneesh Kumar K.V [P9_TGETATTR] = virtio_p9_getattr, 1281c797b6c6SAneesh Kumar K.V [P9_TSETATTR] = virtio_p9_setattr, 1282c797b6c6SAneesh Kumar K.V [P9_TXATTRWALK] = virtio_p9_eopnotsupp, 1283c797b6c6SAneesh Kumar K.V [P9_TXATTRCREATE] = virtio_p9_eopnotsupp, 1284c797b6c6SAneesh Kumar K.V [P9_TMKNOD] = virtio_p9_mknod, 1285c797b6c6SAneesh Kumar K.V [P9_TLOCK] = virtio_p9_lock, 1286c797b6c6SAneesh Kumar K.V [P9_TGETLOCK] = virtio_p9_getlock, 1287c797b6c6SAneesh Kumar K.V [P9_TRENAMEAT] = virtio_p9_renameat, 1288c797b6c6SAneesh Kumar K.V [P9_TREADLINK] = virtio_p9_readlink, 1289c797b6c6SAneesh Kumar K.V [P9_TUNLINKAT] = virtio_p9_unlinkat, 1290c797b6c6SAneesh Kumar K.V [P9_TMKDIR] = virtio_p9_mkdir, 1291b4422bf3SAneesh Kumar K.V [P9_TVERSION] = virtio_p9_version, 1292c797b6c6SAneesh Kumar K.V [P9_TLOPEN] = virtio_p9_open, 1293b4422bf3SAneesh Kumar K.V [P9_TATTACH] = virtio_p9_attach, 1294b4422bf3SAneesh Kumar K.V [P9_TWALK] = virtio_p9_walk, 1295c797b6c6SAneesh Kumar K.V [P9_TCLUNK] = virtio_p9_clunk, 1296c797b6c6SAneesh Kumar K.V [P9_TFSYNC] = virtio_p9_fsync, 1297b4422bf3SAneesh Kumar K.V [P9_TREAD] = virtio_p9_read, 12985cc808aaSSasha Levin [P9_TFLUSH] = virtio_p9_flush, 1299c797b6c6SAneesh Kumar K.V [P9_TLINK] = virtio_p9_link, 1300c797b6c6SAneesh Kumar K.V [P9_TSYMLINK] = virtio_p9_symlink, 1301c797b6c6SAneesh Kumar K.V [P9_TLCREATE] = virtio_p9_create, 1302b4422bf3SAneesh Kumar K.V [P9_TWRITE] = virtio_p9_write, 13036fc5cd9bSSasha Levin [P9_TREMOVE] = virtio_p9_remove, 1304f161f28bSSasha Levin [P9_TRENAME] = virtio_p9_rename, 1305b4422bf3SAneesh Kumar K.V }; 1306b4422bf3SAneesh Kumar K.V 1307af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq) 1308af045e53SAneesh Kumar K.V { 1309af045e53SAneesh Kumar K.V struct p9_pdu *pdu = calloc(1, sizeof(*pdu)); 1310af045e53SAneesh Kumar K.V if (!pdu) 1311af045e53SAneesh Kumar K.V return NULL; 1312af045e53SAneesh Kumar K.V 1313bfc15268SAneesh Kumar K.V /* skip the pdu header p9_msg */ 13145529bcd7SAsias He pdu->read_offset = VIRTIO_9P_HDR_LEN; 13155529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 1316af045e53SAneesh Kumar K.V pdu->queue_head = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov, 1317a8a44649SAsias He pdu->out_iov, &pdu->in_iov_cnt, &pdu->out_iov_cnt); 1318af045e53SAneesh Kumar K.V return pdu; 1319af045e53SAneesh Kumar K.V } 1320af045e53SAneesh Kumar K.V 1321af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu) 1322af045e53SAneesh Kumar K.V { 1323af045e53SAneesh Kumar K.V struct p9_msg *msg; 1324af045e53SAneesh Kumar K.V /* 1325af045e53SAneesh Kumar K.V * we can peek directly into pdu for a u8 1326af045e53SAneesh Kumar K.V * value. The host endianess won't be an issue 1327af045e53SAneesh Kumar K.V */ 1328af045e53SAneesh Kumar K.V msg = pdu->out_iov[0].iov_base; 1329af045e53SAneesh Kumar K.V return msg->cmd; 1330af045e53SAneesh Kumar K.V } 1331af045e53SAneesh Kumar K.V 1332b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job) 13331c7850f9SSasha Levin { 1334af045e53SAneesh Kumar K.V u8 cmd; 1335b4422bf3SAneesh Kumar K.V u32 len = 0; 1336b4422bf3SAneesh Kumar K.V p9_handler *handler; 1337b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 1338af045e53SAneesh Kumar K.V struct virt_queue *vq; 1339af045e53SAneesh Kumar K.V struct p9_pdu *p9pdu; 13401c7850f9SSasha Levin 1341b4422bf3SAneesh Kumar K.V vq = job->vq; 1342b4422bf3SAneesh Kumar K.V p9dev = job->p9dev; 13431c7850f9SSasha Levin 1344af045e53SAneesh Kumar K.V p9pdu = virtio_p9_pdu_init(kvm, vq); 1345af045e53SAneesh Kumar K.V cmd = virtio_p9_get_cmd(p9pdu); 1346af045e53SAneesh Kumar K.V 1347c797b6c6SAneesh Kumar K.V if ((cmd >= ARRAY_SIZE(virtio_9p_dotl_handler)) || 1348c797b6c6SAneesh Kumar K.V !virtio_9p_dotl_handler[cmd]) 134997b408afSAneesh Kumar K.V handler = virtio_p9_eopnotsupp; 1350dd78d9eaSAneesh Kumar K.V else 1351c797b6c6SAneesh Kumar K.V handler = virtio_9p_dotl_handler[cmd]; 1352c797b6c6SAneesh Kumar K.V 1353af045e53SAneesh Kumar K.V handler(p9dev, p9pdu, &len); 1354af045e53SAneesh Kumar K.V virt_queue__set_used_elem(vq, p9pdu->queue_head, len); 1355af045e53SAneesh Kumar K.V free(p9pdu); 13561c7850f9SSasha Levin return true; 13571c7850f9SSasha Levin } 13581c7850f9SSasha Levin 13591c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param) 13601c7850f9SSasha Levin { 1361b4422bf3SAneesh Kumar K.V struct p9_dev_job *job = (struct p9_dev_job *)param; 1362b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = job->p9dev; 1363b4422bf3SAneesh Kumar K.V struct virt_queue *vq = job->vq; 13641c7850f9SSasha Levin 13651c7850f9SSasha Levin while (virt_queue__available(vq)) { 1366b4422bf3SAneesh Kumar K.V virtio_p9_do_io_request(kvm, job); 136702eca50cSAsias He p9dev->vdev.ops->signal_vq(kvm, &p9dev->vdev, vq - p9dev->vqs); 13681c7850f9SSasha Levin } 13691c7850f9SSasha Levin } 13701c7850f9SSasha Levin 1371c5ae742bSSasha Levin static u8 *get_config(struct kvm *kvm, void *dev) 13721c7850f9SSasha Levin { 1373c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 13741c7850f9SSasha Levin 1375c5ae742bSSasha Levin return ((u8 *)(p9dev->config)); 1376c7838fbdSSasha Levin } 1377c7838fbdSSasha Levin 1378e4730284SMartin Radev static size_t get_config_size(struct kvm *kvm, void *dev) 1379e4730284SMartin Radev { 1380e4730284SMartin Radev struct p9_dev *p9dev = dev; 1381e4730284SMartin Radev 1382e4730284SMartin Radev return p9dev->config_size; 1383e4730284SMartin Radev } 1384e4730284SMartin Radev 1385c7838fbdSSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev) 1386c7838fbdSSasha Levin { 1387c7838fbdSSasha Levin return 1 << VIRTIO_9P_MOUNT_TAG; 1388c7838fbdSSasha Levin } 1389c7838fbdSSasha Levin 1390c7838fbdSSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features) 1391c7838fbdSSasha Levin { 1392c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1393c7838fbdSSasha Levin 1394c7838fbdSSasha Levin p9dev->features = features; 1395c7838fbdSSasha Levin } 1396c7838fbdSSasha Levin 139795242e44SJean-Philippe Brucker static void notify_status(struct kvm *kvm, void *dev, u32 status) 139895242e44SJean-Philippe Brucker { 13998003ede4SJean-Philippe Brucker struct p9_dev *p9dev = dev; 14008003ede4SJean-Philippe Brucker struct p9_fid *pfid, *next; 14018003ede4SJean-Philippe Brucker 1402*867b15ccSJean-Philippe Brucker if (status & VIRTIO__STATUS_CONFIG) 1403*867b15ccSJean-Philippe Brucker p9dev->config->tag_len = virtio_host_to_guest_u16(&p9dev->vdev, 1404*867b15ccSJean-Philippe Brucker p9dev->tag_len); 1405*867b15ccSJean-Philippe Brucker 14068003ede4SJean-Philippe Brucker if (!(status & VIRTIO__STATUS_STOP)) 14078003ede4SJean-Philippe Brucker return; 14088003ede4SJean-Philippe Brucker 14098003ede4SJean-Philippe Brucker rbtree_postorder_for_each_entry_safe(pfid, next, &p9dev->fids, node) 14108003ede4SJean-Philippe Brucker close_fid(p9dev, pfid->fid); 141195242e44SJean-Philippe Brucker } 141295242e44SJean-Philippe Brucker 1413609ee906SJean-Philippe Brucker static int init_vq(struct kvm *kvm, void *dev, u32 vq) 1414c7838fbdSSasha Levin { 1415c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1416b4422bf3SAneesh Kumar K.V struct p9_dev_job *job; 1417b4422bf3SAneesh Kumar K.V struct virt_queue *queue; 14181c7850f9SSasha Levin 1419312c62d1SSasha Levin compat__remove_message(compat_id); 1420e59662b3SSasha Levin 1421c7838fbdSSasha Levin queue = &p9dev->vqs[vq]; 1422c7838fbdSSasha Levin job = &p9dev->jobs[vq]; 14231c7850f9SSasha Levin 1424609ee906SJean-Philippe Brucker virtio_init_device_vq(kvm, &p9dev->vdev, queue, VIRTQUEUE_NUM); 14251c7850f9SSasha Levin 1426b4422bf3SAneesh Kumar K.V *job = (struct p9_dev_job) { 1427b4422bf3SAneesh Kumar K.V .vq = queue, 1428b4422bf3SAneesh Kumar K.V .p9dev = p9dev, 1429b4422bf3SAneesh Kumar K.V }; 1430df0c7f57SSasha Levin thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job); 143160eb42d5SSasha Levin 1432c7838fbdSSasha Levin return 0; 14331c7850f9SSasha Levin } 14341c7850f9SSasha Levin 14358003ede4SJean-Philippe Brucker static void exit_vq(struct kvm *kvm, void *dev, u32 vq) 14368003ede4SJean-Philippe Brucker { 14378003ede4SJean-Philippe Brucker struct p9_dev *p9dev = dev; 14388003ede4SJean-Philippe Brucker 14398003ede4SJean-Philippe Brucker thread_pool__cancel_job(&p9dev->jobs[vq].job_id); 14408003ede4SJean-Philippe Brucker } 14418003ede4SJean-Philippe Brucker 1442c7838fbdSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 1443c7838fbdSSasha Levin { 1444c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 14451c7850f9SSasha Levin 1446c7838fbdSSasha Levin thread_pool__do_job(&p9dev->jobs[vq].job_id); 1447c7838fbdSSasha Levin 1448c7838fbdSSasha Levin return 0; 1449c7838fbdSSasha Levin } 1450c7838fbdSSasha Levin 145153fbb17bSJean-Philippe Brucker static struct virt_queue *get_vq(struct kvm *kvm, void *dev, u32 vq) 1452c7838fbdSSasha Levin { 1453c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1454c7838fbdSSasha Levin 145553fbb17bSJean-Philippe Brucker return &p9dev->vqs[vq]; 1456c7838fbdSSasha Levin } 1457c7838fbdSSasha Levin 1458c7838fbdSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 1459c7838fbdSSasha Levin { 1460c7838fbdSSasha Levin return VIRTQUEUE_NUM; 1461c7838fbdSSasha Levin } 1462c7838fbdSSasha Levin 14637aba29c1SWill Deacon static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size) 14647aba29c1SWill Deacon { 14657aba29c1SWill Deacon /* FIXME: dynamic */ 14667aba29c1SWill Deacon return size; 14677aba29c1SWill Deacon } 14687aba29c1SWill Deacon 146931e0eaccSMartin Radev static unsigned int get_vq_count(struct kvm *kvm, void *dev) 1470b98ac591SJean-Philippe Brucker { 1471b98ac591SJean-Philippe Brucker return NUM_VIRT_QUEUES; 1472b98ac591SJean-Philippe Brucker } 1473b98ac591SJean-Philippe Brucker 147415542babSAndre Przywara struct virtio_ops p9_dev_virtio_ops = { 1475c7838fbdSSasha Levin .get_config = get_config, 1476e4730284SMartin Radev .get_config_size = get_config_size, 1477c7838fbdSSasha Levin .get_host_features = get_host_features, 1478c7838fbdSSasha Levin .set_guest_features = set_guest_features, 1479c7838fbdSSasha Levin .init_vq = init_vq, 14808003ede4SJean-Philippe Brucker .exit_vq = exit_vq, 148195242e44SJean-Philippe Brucker .notify_status = notify_status, 1482c7838fbdSSasha Levin .notify_vq = notify_vq, 148353fbb17bSJean-Philippe Brucker .get_vq = get_vq, 1484c7838fbdSSasha Levin .get_size_vq = get_size_vq, 14857aba29c1SWill Deacon .set_size_vq = set_size_vq, 1486b98ac591SJean-Philippe Brucker .get_vq_count = get_vq_count, 1487c7838fbdSSasha Levin }; 14881c47ce69SSasha Levin 1489cac9e8fdSSasha Levin int virtio_9p_rootdir_parser(const struct option *opt, const char *arg, int unset) 1490cac9e8fdSSasha Levin { 1491cac9e8fdSSasha Levin char *tag_name; 1492cac9e8fdSSasha Levin char tmp[PATH_MAX]; 1493cac9e8fdSSasha Levin struct kvm *kvm = opt->ptr; 1494cac9e8fdSSasha Levin 1495cac9e8fdSSasha Levin /* 1496cac9e8fdSSasha Levin * 9p dir can be of the form dirname,tag_name or 1497cac9e8fdSSasha Levin * just dirname. In the later case we use the 1498cac9e8fdSSasha Levin * default tag name 1499cac9e8fdSSasha Levin */ 1500cac9e8fdSSasha Levin tag_name = strstr(arg, ","); 1501cac9e8fdSSasha Levin if (tag_name) { 1502cac9e8fdSSasha Levin *tag_name = '\0'; 1503cac9e8fdSSasha Levin tag_name++; 1504cac9e8fdSSasha Levin } 1505cac9e8fdSSasha Levin if (realpath(arg, tmp)) { 1506cac9e8fdSSasha Levin if (virtio_9p__register(kvm, tmp, tag_name) < 0) 1507cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1508cac9e8fdSSasha Levin } else 1509cac9e8fdSSasha Levin die("Failed resolving 9p path"); 1510cac9e8fdSSasha Levin return 0; 1511cac9e8fdSSasha Levin } 1512cac9e8fdSSasha Levin 1513cac9e8fdSSasha Levin int virtio_9p_img_name_parser(const struct option *opt, const char *arg, int unset) 1514cac9e8fdSSasha Levin { 1515cac9e8fdSSasha Levin char path[PATH_MAX]; 1516cac9e8fdSSasha Levin struct stat st; 1517cac9e8fdSSasha Levin struct kvm *kvm = opt->ptr; 1518cac9e8fdSSasha Levin 1519cac9e8fdSSasha Levin if (stat(arg, &st) == 0 && 1520cac9e8fdSSasha Levin S_ISDIR(st.st_mode)) { 1521cac9e8fdSSasha Levin char tmp[PATH_MAX]; 1522cac9e8fdSSasha Levin 1523cac9e8fdSSasha Levin if (kvm->cfg.using_rootfs) 1524cac9e8fdSSasha Levin die("Please use only one rootfs directory atmost"); 1525cac9e8fdSSasha Levin 1526cac9e8fdSSasha Levin if (realpath(arg, tmp) == 0 || 1527cac9e8fdSSasha Levin virtio_9p__register(kvm, tmp, "/dev/root") < 0) 1528cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1529cac9e8fdSSasha Levin kvm->cfg.using_rootfs = 1; 1530cac9e8fdSSasha Levin return 0; 1531cac9e8fdSSasha Levin } 1532cac9e8fdSSasha Levin 1533cac9e8fdSSasha Levin snprintf(path, PATH_MAX, "%s%s", kvm__get_dir(), arg); 1534cac9e8fdSSasha Levin 1535cac9e8fdSSasha Levin if (stat(path, &st) == 0 && 1536cac9e8fdSSasha Levin S_ISDIR(st.st_mode)) { 1537cac9e8fdSSasha Levin char tmp[PATH_MAX]; 1538cac9e8fdSSasha Levin 1539cac9e8fdSSasha Levin if (kvm->cfg.using_rootfs) 1540cac9e8fdSSasha Levin die("Please use only one rootfs directory atmost"); 1541cac9e8fdSSasha Levin 1542cac9e8fdSSasha Levin if (realpath(path, tmp) == 0 || 1543cac9e8fdSSasha Levin virtio_9p__register(kvm, tmp, "/dev/root") < 0) 1544cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1545cac9e8fdSSasha Levin if (virtio_9p__register(kvm, "/", "hostfs") < 0) 1546cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1547cac9e8fdSSasha Levin kvm_setup_resolv(arg); 1548cac9e8fdSSasha Levin kvm->cfg.using_rootfs = kvm->cfg.custom_rootfs = 1; 1549cac9e8fdSSasha Levin kvm->cfg.custom_rootfs_name = arg; 1550cac9e8fdSSasha Levin return 0; 1551cac9e8fdSSasha Levin } 1552cac9e8fdSSasha Levin 1553cac9e8fdSSasha Levin return -1; 1554cac9e8fdSSasha Levin } 1555cac9e8fdSSasha Levin 15561c47ce69SSasha Levin int virtio_9p__init(struct kvm *kvm) 15571c47ce69SSasha Levin { 15581c47ce69SSasha Levin struct p9_dev *p9dev; 1559db927775SAlexandru Elisei int r; 15601c47ce69SSasha Levin 15611c47ce69SSasha Levin list_for_each_entry(p9dev, &devs, list) { 1562db927775SAlexandru Elisei r = virtio_init(kvm, p9dev, &p9dev->vdev, &p9_dev_virtio_ops, 1563d97dadecSWill Deacon VIRTIO_DEFAULT_TRANS(kvm), PCI_DEVICE_ID_VIRTIO_9P, 1564ae06ce71SWill Deacon VIRTIO_ID_9P, PCI_CLASS_9P); 1565db927775SAlexandru Elisei if (r < 0) 1566db927775SAlexandru Elisei return r; 1567c7838fbdSSasha Levin } 1568c7838fbdSSasha Levin 1569c7838fbdSSasha Levin return 0; 1570c7838fbdSSasha Levin } 157149a8afd1SSasha Levin virtio_dev_init(virtio_9p__init); 1572c7838fbdSSasha Levin 1573c7838fbdSSasha Levin int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name) 1574c7838fbdSSasha Levin { 1575c7838fbdSSasha Levin struct p9_dev *p9dev; 1576e4730284SMartin Radev size_t tag_length; 1577e4730284SMartin Radev size_t config_size; 1578e4730284SMartin Radev int err; 15791c7850f9SSasha Levin 1580b4422bf3SAneesh Kumar K.V p9dev = calloc(1, sizeof(*p9dev)); 1581b4422bf3SAneesh Kumar K.V if (!p9dev) 158254f6802dSPekka Enberg return -ENOMEM; 158354f6802dSPekka Enberg 1584b4422bf3SAneesh Kumar K.V if (!tag_name) 15855529bcd7SAsias He tag_name = VIRTIO_9P_DEFAULT_TAG; 158654f6802dSPekka Enberg 1587e4730284SMartin Radev tag_length = strlen(tag_name); 1588e4730284SMartin Radev /* The tag_name zero byte is intentionally excluded */ 1589e4730284SMartin Radev config_size = sizeof(*p9dev->config) + tag_length; 1590e4730284SMartin Radev 1591e4730284SMartin Radev p9dev->config = calloc(1, config_size); 159254f6802dSPekka Enberg if (p9dev->config == NULL) { 159354f6802dSPekka Enberg err = -ENOMEM; 1594b4422bf3SAneesh Kumar K.V goto free_p9dev; 159554f6802dSPekka Enberg } 1596e4730284SMartin Radev p9dev->config_size = config_size; 15971c7850f9SSasha Levin 1598e277a1b4SG. Campana strncpy(p9dev->root_dir, root, sizeof(p9dev->root_dir)); 1599e277a1b4SG. Campana p9dev->root_dir[sizeof(p9dev->root_dir)-1] = '\x00'; 1600e277a1b4SG. Campana 1601*867b15ccSJean-Philippe Brucker p9dev->tag_len = tag_length; 1602*867b15ccSJean-Philippe Brucker if (p9dev->tag_len > MAX_TAG_LEN) { 160354f6802dSPekka Enberg err = -EINVAL; 1604b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 160554f6802dSPekka Enberg } 16061c7850f9SSasha Levin 1607e4730284SMartin Radev memcpy(&p9dev->config->tag, tag_name, tag_length); 16081c7850f9SSasha Levin 1609c7838fbdSSasha Levin list_add(&p9dev->list, &devs); 1610b4422bf3SAneesh Kumar K.V 1611d278197dSAsias He if (compat_id == -1) 161252f34d2cSAsias He compat_id = virtio_compat_add_message("virtio-9p", "CONFIG_NET_9P_VIRTIO"); 1613e59662b3SSasha Levin 1614e4730284SMartin Radev return 0; 161554f6802dSPekka Enberg 1616b4422bf3SAneesh Kumar K.V free_p9dev_config: 1617b4422bf3SAneesh Kumar K.V free(p9dev->config); 1618b4422bf3SAneesh Kumar K.V free_p9dev: 1619b4422bf3SAneesh Kumar K.V free(p9dev); 162054f6802dSPekka Enberg return err; 16211c7850f9SSasha Levin } 1622