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> 14bfc15268SAneesh Kumar K.V #include <unistd.h> 15bfc15268SAneesh Kumar K.V #include <string.h> 16bfc15268SAneesh Kumar K.V #include <errno.h> 17c797b6c6SAneesh Kumar K.V #include <sys/vfs.h> 181c7850f9SSasha Levin 192daa28d4SAneesh Kumar K.V #include <linux/virtio_ring.h> 202daa28d4SAneesh Kumar K.V #include <linux/virtio_9p.h> 21c6cb7c75SAndre Przywara #include <linux/9p.h> 222daa28d4SAneesh Kumar K.V 23c7838fbdSSasha Levin static LIST_HEAD(devs); 24312c62d1SSasha Levin static int compat_id = -1; 25c7838fbdSSasha Levin 26e2341580SSasha Levin static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid); 27e2341580SSasha Levin static struct p9_fid *find_or_create_fid(struct p9_dev *dev, u32 fid) 28e2341580SSasha Levin { 29e2341580SSasha Levin struct rb_node *node = dev->fids.rb_node; 30e2341580SSasha Levin struct p9_fid *pfid = NULL; 31*e277a1b4SG. Campana size_t len; 32e2341580SSasha Levin 33e2341580SSasha Levin while (node) { 34e2341580SSasha Levin struct p9_fid *cur = rb_entry(node, struct p9_fid, node); 35e2341580SSasha Levin 36e2341580SSasha Levin if (fid < cur->fid) { 37e2341580SSasha Levin node = node->rb_left; 38e2341580SSasha Levin } else if (fid > cur->fid) { 39e2341580SSasha Levin node = node->rb_right; 40e2341580SSasha Levin } else { 41e2341580SSasha Levin return cur; 42e2341580SSasha Levin } 43e2341580SSasha Levin } 44e2341580SSasha Levin 45e2341580SSasha Levin pfid = calloc(sizeof(*pfid), 1); 46e2341580SSasha Levin if (!pfid) 47e2341580SSasha Levin return NULL; 48e2341580SSasha Levin 49*e277a1b4SG. Campana len = strlen(dev->root_dir); 50*e277a1b4SG. Campana if (len >= sizeof(pfid->abs_path)) { 51*e277a1b4SG. Campana free(pfid); 52*e277a1b4SG. Campana return NULL; 53*e277a1b4SG. Campana } 54*e277a1b4SG. Campana 55e2341580SSasha Levin pfid->fid = fid; 56e2341580SSasha Levin strcpy(pfid->abs_path, dev->root_dir); 57*e277a1b4SG. Campana pfid->path = pfid->abs_path + strlen(pfid->abs_path); 58e2341580SSasha Levin 59e2341580SSasha Levin insert_new_fid(dev, pfid); 60e2341580SSasha Levin 61e2341580SSasha Levin return pfid; 62e2341580SSasha Levin } 63e2341580SSasha Levin 64e2341580SSasha Levin static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid) 65e2341580SSasha Levin { 66e2341580SSasha Levin struct rb_node **node = &(dev->fids.rb_node), *parent = NULL; 67e2341580SSasha Levin 68e2341580SSasha Levin while (*node) { 69e2341580SSasha Levin int result = fid->fid - rb_entry(*node, struct p9_fid, node)->fid; 70e2341580SSasha Levin 71e2341580SSasha Levin parent = *node; 72e2341580SSasha Levin if (result < 0) 73e2341580SSasha Levin node = &((*node)->rb_left); 74e2341580SSasha Levin else if (result > 0) 75e2341580SSasha Levin node = &((*node)->rb_right); 76e2341580SSasha Levin else 77e2341580SSasha Levin return -EEXIST; 78e2341580SSasha Levin } 79e2341580SSasha Levin 80e2341580SSasha Levin rb_link_node(&fid->node, parent, node); 81e2341580SSasha Levin rb_insert_color(&fid->node, &dev->fids); 82e2341580SSasha Levin return 0; 83e2341580SSasha Levin } 84e2341580SSasha Levin 8531a6fb8dSSasha Levin static struct p9_fid *get_fid(struct p9_dev *p9dev, int fid) 8631a6fb8dSSasha Levin { 87e2341580SSasha Levin struct p9_fid *new; 8831a6fb8dSSasha Levin 89e2341580SSasha Levin new = find_or_create_fid(p9dev, fid); 90e2341580SSasha Levin 91e2341580SSasha Levin return new; 9231a6fb8dSSasha Levin } 9331a6fb8dSSasha Levin 941c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */ 95b4422bf3SAneesh Kumar K.V static const char *rel_to_abs(struct p9_dev *p9dev, 96b4422bf3SAneesh Kumar K.V const char *path, char *abs_path) 971c7850f9SSasha Levin { 98b4422bf3SAneesh Kumar K.V sprintf(abs_path, "%s/%s", p9dev->root_dir, path); 991c7850f9SSasha Levin 1001c7850f9SSasha Levin return abs_path; 1011c7850f9SSasha Levin } 1021c7850f9SSasha Levin 103c797b6c6SAneesh Kumar K.V static void stat2qid(struct stat *st, struct p9_qid *qid) 1041c7850f9SSasha Levin { 1051c7850f9SSasha Levin *qid = (struct p9_qid) { 1061c7850f9SSasha Levin .path = st->st_ino, 1071c7850f9SSasha Levin .version = st->st_mtime, 1081c7850f9SSasha Levin }; 1091c7850f9SSasha Levin 1101c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) 1111c7850f9SSasha Levin qid->type |= P9_QTDIR; 1121c7850f9SSasha Levin } 1131c7850f9SSasha Levin 114b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid) 1151c7850f9SSasha Levin { 116e2341580SSasha Levin struct p9_fid *pfid = get_fid(p9dev, fid); 117e2341580SSasha Levin 118e2341580SSasha Levin if (pfid->fd > 0) 119e2341580SSasha Levin close(pfid->fd); 120e2341580SSasha Levin 121e2341580SSasha Levin if (pfid->dir) 122e2341580SSasha Levin closedir(pfid->dir); 123e2341580SSasha Levin 124e2341580SSasha Levin rb_erase(&pfid->node, &p9dev->fids); 125e2341580SSasha Levin free(pfid); 1261c7850f9SSasha Levin } 127e2341580SSasha Levin 128bfc15268SAneesh Kumar K.V static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size) 1291c7850f9SSasha Levin { 130bfc15268SAneesh Kumar K.V u8 cmd; 131bfc15268SAneesh Kumar K.V u16 tag; 132bfc15268SAneesh Kumar K.V 133bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32); 134bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag); 135bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 136bfc15268SAneesh Kumar K.V /* cmd + 1 is the reply message */ 137bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag); 1381c7850f9SSasha Levin } 1391c7850f9SSasha Levin 1406b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt) 1416b163a87SAneesh Kumar K.V { 1426b163a87SAneesh Kumar K.V int i; 1436b163a87SAneesh Kumar K.V u32 total = 0; 1446b163a87SAneesh Kumar K.V for (i = 0; (i < iov_cnt) && (total < count); i++) { 1456b163a87SAneesh Kumar K.V if (total + iov[i].iov_len > count) { 1466b163a87SAneesh Kumar K.V /* we don't need this iov fully */ 1476b163a87SAneesh Kumar K.V iov[i].iov_len -= ((total + iov[i].iov_len) - count); 1486b163a87SAneesh Kumar K.V i++; 1496b163a87SAneesh Kumar K.V break; 1506b163a87SAneesh Kumar K.V } 1516b163a87SAneesh Kumar K.V total += iov[i].iov_len; 1526b163a87SAneesh Kumar K.V } 1536b163a87SAneesh Kumar K.V return i; 1546b163a87SAneesh Kumar K.V } 1556b163a87SAneesh Kumar K.V 156eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev, 157eee1ba8eSAneesh Kumar K.V struct p9_pdu *pdu, int err, u32 *outlen) 158eee1ba8eSAneesh Kumar K.V { 159bfc15268SAneesh Kumar K.V u16 tag; 160eee1ba8eSAneesh Kumar K.V 1619c2e1d1aSSuzuki K. Poulose /* EMFILE at server implies ENFILE for the VM */ 1629c2e1d1aSSuzuki K. Poulose if (err == EMFILE) 1639c2e1d1aSSuzuki K. Poulose err = ENFILE; 1649c2e1d1aSSuzuki K. Poulose 1655529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 166c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", err); 167bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 168eee1ba8eSAneesh Kumar K.V 169c797b6c6SAneesh Kumar K.V /* read the tag from input */ 170bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32) + sizeof(u8); 171bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "w", &tag); 172bfc15268SAneesh Kumar K.V 173c797b6c6SAneesh Kumar K.V /* Update the header */ 174bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 175c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RLERROR, tag); 176eee1ba8eSAneesh Kumar K.V } 177eee1ba8eSAneesh Kumar K.V 178ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev, 179af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1801c7850f9SSasha Levin { 181c797b6c6SAneesh Kumar K.V u32 msize; 182c797b6c6SAneesh Kumar K.V char *version; 183c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ds", &msize, &version); 184c797b6c6SAneesh Kumar K.V /* 185c797b6c6SAneesh Kumar K.V * reply with the same msize the client sent us 186c797b6c6SAneesh Kumar K.V * Error out if the request is not for 9P2000.L 187c797b6c6SAneesh Kumar K.V */ 1885529bcd7SAsias He if (!strcmp(version, VIRTIO_9P_VERSION_DOTL)) 189c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, version); 190c797b6c6SAneesh Kumar K.V else 191c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, "unknown"); 1921c7850f9SSasha Levin 193bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 194bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 195c797b6c6SAneesh Kumar K.V free(version); 196ead43b01SAneesh Kumar K.V return; 1971c7850f9SSasha Levin } 1981c7850f9SSasha Levin 199ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev, 200af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2011c7850f9SSasha Levin { 202bfc15268SAneesh Kumar K.V u32 fid; 2031c7850f9SSasha Levin 204bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid); 205bfc15268SAneesh Kumar K.V close_fid(p9dev, fid); 2061c7850f9SSasha Levin 207bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 208bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 209ead43b01SAneesh Kumar K.V return; 2101c7850f9SSasha Levin } 2111c7850f9SSasha Levin 212c797b6c6SAneesh Kumar K.V /* 213c797b6c6SAneesh Kumar K.V * FIXME!! Need to map to protocol independent value. Upstream 214c797b6c6SAneesh Kumar K.V * 9p also have the same BUG 215c797b6c6SAneesh Kumar K.V */ 216c797b6c6SAneesh Kumar K.V static int virtio_p9_openflags(int flags) 217c797b6c6SAneesh Kumar K.V { 218c797b6c6SAneesh Kumar K.V flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT | O_DIRECT); 219c797b6c6SAneesh Kumar K.V flags |= O_NOFOLLOW; 220c797b6c6SAneesh Kumar K.V return flags; 221c797b6c6SAneesh Kumar K.V } 222c797b6c6SAneesh Kumar K.V 22332585666SSasha Levin static bool is_dir(struct p9_fid *fid) 22432585666SSasha Levin { 22532585666SSasha Levin struct stat st; 22632585666SSasha Levin 22732585666SSasha Levin stat(fid->abs_path, &st); 22832585666SSasha Levin 22932585666SSasha Levin return S_ISDIR(st.st_mode); 23032585666SSasha Levin } 23132585666SSasha Levin 2329bb99a82SG. Campana /* path is always absolute */ 2339bb99a82SG. Campana static bool path_is_illegal(const char *path) 2349bb99a82SG. Campana { 2359bb99a82SG. Campana size_t len; 2369bb99a82SG. Campana 2379bb99a82SG. Campana if (strstr(path, "/../") != NULL) 2389bb99a82SG. Campana return true; 2399bb99a82SG. Campana 2409bb99a82SG. Campana len = strlen(path); 2419bb99a82SG. Campana if (len >= 3 && strcmp(path + len - 3, "/..") == 0) 2429bb99a82SG. Campana return true; 2439bb99a82SG. Campana 2449bb99a82SG. Campana return false; 2459bb99a82SG. Campana } 2469bb99a82SG. Campana 247ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev, 248af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2491c7850f9SSasha Levin { 250c797b6c6SAneesh Kumar K.V u32 fid, flags; 2511c7850f9SSasha Levin struct stat st; 252bfc15268SAneesh Kumar K.V struct p9_qid qid; 253bfc15268SAneesh Kumar K.V struct p9_fid *new_fid; 254bfc15268SAneesh Kumar K.V 255c797b6c6SAneesh Kumar K.V 256c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid, &flags); 25731a6fb8dSSasha Levin new_fid = get_fid(p9dev, fid); 2581c7850f9SSasha Levin 25930204a77SAneesh Kumar K.V if (lstat(new_fid->abs_path, &st) < 0) 260eee1ba8eSAneesh Kumar K.V goto err_out; 2611c7850f9SSasha Levin 262c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 2631c7850f9SSasha Levin 26432585666SSasha Levin if (is_dir(new_fid)) { 2651c7850f9SSasha Levin new_fid->dir = opendir(new_fid->abs_path); 266eee1ba8eSAneesh Kumar K.V if (!new_fid->dir) 267eee1ba8eSAneesh Kumar K.V goto err_out; 268eee1ba8eSAneesh Kumar K.V } else { 269eee1ba8eSAneesh Kumar K.V new_fid->fd = open(new_fid->abs_path, 270c797b6c6SAneesh Kumar K.V virtio_p9_openflags(flags)); 271eee1ba8eSAneesh Kumar K.V if (new_fid->fd < 0) 272eee1ba8eSAneesh Kumar K.V goto err_out; 273eee1ba8eSAneesh Kumar K.V } 274c797b6c6SAneesh Kumar K.V /* FIXME!! need ot send proper iounit */ 275bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 276bfc15268SAneesh Kumar K.V 277bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 278bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 279ead43b01SAneesh Kumar K.V return; 280eee1ba8eSAneesh Kumar K.V err_out: 281eee1ba8eSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 282ead43b01SAneesh Kumar K.V return; 2831c7850f9SSasha Levin } 2841c7850f9SSasha Levin 285ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev, 286af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2871c7850f9SSasha Levin { 288c797b6c6SAneesh Kumar K.V int fd, ret; 289bfc15268SAneesh Kumar K.V char *name; 29032832dd1SG. Campana size_t size; 291af045e53SAneesh Kumar K.V struct stat st; 292bfc15268SAneesh Kumar K.V struct p9_qid qid; 293c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 2944bc9734aSAneesh Kumar K.V char full_path[PATH_MAX]; 295c797b6c6SAneesh Kumar K.V u32 dfid_val, flags, mode, gid; 296af045e53SAneesh Kumar K.V 297c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsddd", &dfid_val, 298c797b6c6SAneesh Kumar K.V &name, &flags, &mode, &gid); 29931a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 3001c7850f9SSasha Levin 301c797b6c6SAneesh Kumar K.V flags = virtio_p9_openflags(flags); 3025f900f6dSSasha Levin 30332832dd1SG. Campana ret = snprintf(full_path, sizeof(full_path), "%s/%s", dfid->abs_path, name); 30432832dd1SG. Campana if (ret >= (int)sizeof(full_path)) { 30532832dd1SG. Campana errno = ENAMETOOLONG; 30632832dd1SG. Campana goto err_out; 30732832dd1SG. Campana } 30832832dd1SG. Campana 3099bb99a82SG. Campana if (path_is_illegal(full_path)) { 3109bb99a82SG. Campana errno = EACCES; 3119bb99a82SG. Campana goto err_out; 3129bb99a82SG. Campana } 3139bb99a82SG. Campana 31432832dd1SG. Campana size = sizeof(dfid->abs_path) - (dfid->path - dfid->abs_path); 31532832dd1SG. Campana ret = snprintf(dfid->path, size, "%s/%s", dfid->path, name); 31632832dd1SG. Campana if (ret >= (int)size) { 31732832dd1SG. Campana errno = ENAMETOOLONG; 31832832dd1SG. Campana if (size > 0) 31932832dd1SG. Campana dfid->path[size] = '\x00'; 32032832dd1SG. Campana goto err_out; 32132832dd1SG. Campana } 32232832dd1SG. Campana 323c797b6c6SAneesh Kumar K.V fd = open(full_path, flags | O_CREAT, mode); 3244bc9734aSAneesh Kumar K.V if (fd < 0) 3254bc9734aSAneesh Kumar K.V goto err_out; 326c797b6c6SAneesh Kumar K.V dfid->fd = fd; 327c797b6c6SAneesh Kumar K.V 3284bc9734aSAneesh Kumar K.V if (lstat(full_path, &st) < 0) 3296c8ca053SAneesh Kumar K.V goto err_out; 3301c7850f9SSasha Levin 331c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 332c797b6c6SAneesh Kumar K.V if (ret < 0) 333c797b6c6SAneesh Kumar K.V goto err_out; 334c797b6c6SAneesh Kumar K.V 335c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 336bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 337bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 338bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 3395f900f6dSSasha Levin free(name); 3406c8ca053SAneesh Kumar K.V return; 3416c8ca053SAneesh Kumar K.V err_out: 3425f900f6dSSasha Levin free(name); 343c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 344c797b6c6SAneesh Kumar K.V return; 345c797b6c6SAneesh Kumar K.V } 346c797b6c6SAneesh Kumar K.V 347c797b6c6SAneesh Kumar K.V static void virtio_p9_mkdir(struct p9_dev *p9dev, 348c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 349c797b6c6SAneesh Kumar K.V { 350c797b6c6SAneesh Kumar K.V int ret; 351c797b6c6SAneesh Kumar K.V char *name; 352c797b6c6SAneesh Kumar K.V struct stat st; 353c797b6c6SAneesh Kumar K.V struct p9_qid qid; 354c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 355c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 356c797b6c6SAneesh Kumar K.V u32 dfid_val, mode, gid; 357c797b6c6SAneesh Kumar K.V 358c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdd", &dfid_val, 359c797b6c6SAneesh Kumar K.V &name, &mode, &gid); 36031a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 361c797b6c6SAneesh Kumar K.V 36232832dd1SG. Campana ret = snprintf(full_path, sizeof(full_path), "%s/%s", dfid->abs_path, name); 36332832dd1SG. Campana if (ret >= (int)sizeof(full_path)) { 36432832dd1SG. Campana errno = ENAMETOOLONG; 36532832dd1SG. Campana goto err_out; 36632832dd1SG. Campana } 36732832dd1SG. Campana 3689bb99a82SG. Campana if (path_is_illegal(full_path)) { 3699bb99a82SG. Campana errno = EACCES; 3709bb99a82SG. Campana goto err_out; 3719bb99a82SG. Campana } 3729bb99a82SG. Campana 373c797b6c6SAneesh Kumar K.V ret = mkdir(full_path, mode); 374c797b6c6SAneesh Kumar K.V if (ret < 0) 375c797b6c6SAneesh Kumar K.V goto err_out; 376c797b6c6SAneesh Kumar K.V 377c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0) 378c797b6c6SAneesh Kumar K.V goto err_out; 379c797b6c6SAneesh Kumar K.V 380c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 381c797b6c6SAneesh Kumar K.V if (ret < 0) 382c797b6c6SAneesh Kumar K.V goto err_out; 383c797b6c6SAneesh Kumar K.V 384c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 385c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 386c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 387c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 388c797b6c6SAneesh Kumar K.V free(name); 389c797b6c6SAneesh Kumar K.V return; 390c797b6c6SAneesh Kumar K.V err_out: 391c797b6c6SAneesh Kumar K.V free(name); 392c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 393ead43b01SAneesh Kumar K.V return; 3941c7850f9SSasha Levin } 3951c7850f9SSasha Levin 396*e277a1b4SG. Campana static int join_path(struct p9_fid *fid, const char *name) 397*e277a1b4SG. Campana { 398*e277a1b4SG. Campana size_t len, size; 399*e277a1b4SG. Campana 400*e277a1b4SG. Campana size = sizeof(fid->abs_path) - (fid->path - fid->abs_path); 401*e277a1b4SG. Campana len = strlen(name); 402*e277a1b4SG. Campana if (len >= size) 403*e277a1b4SG. Campana return -1; 404*e277a1b4SG. Campana 405*e277a1b4SG. Campana strncpy(fid->path, name, size); 406*e277a1b4SG. Campana return 0; 407*e277a1b4SG. Campana } 408*e277a1b4SG. Campana 409ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev, 410af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4111c7850f9SSasha Levin { 412af045e53SAneesh Kumar K.V u8 i; 413bfc15268SAneesh Kumar K.V u16 nwqid; 414bfc15268SAneesh Kumar K.V u16 nwname; 415bfc15268SAneesh Kumar K.V struct p9_qid wqid; 416e2341580SSasha Levin struct p9_fid *new_fid, *old_fid; 417c797b6c6SAneesh Kumar K.V u32 fid_val, newfid_val; 418c797b6c6SAneesh Kumar K.V 4191c7850f9SSasha Levin 420bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname); 42131a6fb8dSSasha Levin new_fid = get_fid(p9dev, newfid_val); 4221c7850f9SSasha Levin 423bfc15268SAneesh Kumar K.V nwqid = 0; 424bfc15268SAneesh Kumar K.V if (nwname) { 42531a6fb8dSSasha Levin struct p9_fid *fid = get_fid(p9dev, fid_val); 426bfc15268SAneesh Kumar K.V 427*e277a1b4SG. Campana if (join_path(new_fid, fid->path) != 0) { 428*e277a1b4SG. Campana errno = ENAMETOOLONG; 429*e277a1b4SG. Campana goto err_out; 430*e277a1b4SG. Campana } 431*e277a1b4SG. Campana 432bfc15268SAneesh Kumar K.V /* skip the space for count */ 433bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 434bfc15268SAneesh Kumar K.V for (i = 0; i < nwname; i++) { 435bfc15268SAneesh Kumar K.V struct stat st; 4361c7850f9SSasha Levin char tmp[PATH_MAX] = {0}; 4371c7850f9SSasha Levin char full_path[PATH_MAX]; 438e55ed135SPekka Enberg char *str; 43932832dd1SG. Campana int ret; 440bfc15268SAneesh Kumar K.V 441bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "s", &str); 4421c7850f9SSasha Levin 4431c7850f9SSasha Levin /* Format the new path we're 'walk'ing into */ 44432832dd1SG. Campana ret = snprintf(tmp, sizeof(tmp), "%s/%s", new_fid->path, str); 44532832dd1SG. Campana if (ret >= (int)sizeof(tmp)) { 44632832dd1SG. Campana errno = ENAMETOOLONG; 44732832dd1SG. Campana goto err_out; 44832832dd1SG. Campana } 449e55ed135SPekka Enberg 450e55ed135SPekka Enberg free(str); 451e55ed135SPekka Enberg 452c797b6c6SAneesh Kumar K.V if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0) 4536c8ca053SAneesh Kumar K.V goto err_out; 4541c7850f9SSasha Levin 455c797b6c6SAneesh Kumar K.V stat2qid(&st, &wqid); 456*e277a1b4SG. Campana if (join_path(new_fid, tmp) != 0) { 457*e277a1b4SG. Campana errno = ENAMETOOLONG; 458*e277a1b4SG. Campana goto err_out; 459*e277a1b4SG. Campana } 460c797b6c6SAneesh Kumar K.V new_fid->uid = fid->uid; 461bfc15268SAneesh Kumar K.V nwqid++; 462bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &wqid); 4631c7850f9SSasha Levin } 4641c7850f9SSasha Levin } else { 465bfc15268SAneesh Kumar K.V /* 466bfc15268SAneesh Kumar K.V * update write_offset so our outlen get correct value 467bfc15268SAneesh Kumar K.V */ 468bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 469e2341580SSasha Levin old_fid = get_fid(p9dev, fid_val); 470*e277a1b4SG. Campana if (join_path(new_fid, old_fid->path) != 0) { 471*e277a1b4SG. Campana errno = ENAMETOOLONG; 472*e277a1b4SG. Campana goto err_out; 473*e277a1b4SG. Campana } 474e2341580SSasha Levin new_fid->uid = old_fid->uid; 4751c7850f9SSasha Levin } 476bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 4775529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 478bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", nwqid); 479bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 4806c8ca053SAneesh Kumar K.V return; 4816c8ca053SAneesh Kumar K.V err_out: 4826c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 483ead43b01SAneesh Kumar K.V return; 4841c7850f9SSasha Levin } 4851c7850f9SSasha Levin 486ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev, 487af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4881c7850f9SSasha Levin { 489bfc15268SAneesh Kumar K.V char *uname; 490bfc15268SAneesh Kumar K.V char *aname; 4911c7850f9SSasha Levin struct stat st; 492bfc15268SAneesh Kumar K.V struct p9_qid qid; 4931c7850f9SSasha Levin struct p9_fid *fid; 494c797b6c6SAneesh Kumar K.V u32 fid_val, afid, uid; 495bfc15268SAneesh Kumar K.V 496c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddssd", &fid_val, &afid, 497c797b6c6SAneesh Kumar K.V &uname, &aname, &uid); 4981c7850f9SSasha Levin 49939257180SPekka Enberg free(uname); 50039257180SPekka Enberg free(aname); 50139257180SPekka Enberg 50230204a77SAneesh Kumar K.V if (lstat(p9dev->root_dir, &st) < 0) 5036c8ca053SAneesh Kumar K.V goto err_out; 5041c7850f9SSasha Levin 505c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 5061c7850f9SSasha Levin 50731a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 508c797b6c6SAneesh Kumar K.V fid->uid = uid; 509*e277a1b4SG. Campana if (join_path(fid, "/") != 0) { 510*e277a1b4SG. Campana errno = ENAMETOOLONG; 511*e277a1b4SG. Campana goto err_out; 512*e277a1b4SG. Campana } 5131c7850f9SSasha Levin 514bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 515bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 516bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 5176c8ca053SAneesh Kumar K.V return; 5186c8ca053SAneesh Kumar K.V err_out: 5196c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 520ead43b01SAneesh Kumar K.V return; 5211c7850f9SSasha Levin } 5221c7850f9SSasha Levin 523c797b6c6SAneesh Kumar K.V static void virtio_p9_fill_stat(struct p9_dev *p9dev, 524c797b6c6SAneesh Kumar K.V struct stat *st, struct p9_stat_dotl *statl) 5255f900f6dSSasha Levin { 526c797b6c6SAneesh Kumar K.V memset(statl, 0, sizeof(*statl)); 527c797b6c6SAneesh Kumar K.V statl->st_mode = st->st_mode; 528c797b6c6SAneesh Kumar K.V statl->st_nlink = st->st_nlink; 529506fd90bSSasha Levin statl->st_uid = KUIDT_INIT(st->st_uid); 530506fd90bSSasha Levin statl->st_gid = KGIDT_INIT(st->st_gid); 531c797b6c6SAneesh Kumar K.V statl->st_rdev = st->st_rdev; 532c797b6c6SAneesh Kumar K.V statl->st_size = st->st_size; 533c797b6c6SAneesh Kumar K.V statl->st_blksize = st->st_blksize; 534c797b6c6SAneesh Kumar K.V statl->st_blocks = st->st_blocks; 535c797b6c6SAneesh Kumar K.V statl->st_atime_sec = st->st_atime; 536c797b6c6SAneesh Kumar K.V statl->st_atime_nsec = st->st_atim.tv_nsec; 537c797b6c6SAneesh Kumar K.V statl->st_mtime_sec = st->st_mtime; 538c797b6c6SAneesh Kumar K.V statl->st_mtime_nsec = st->st_mtim.tv_nsec; 539c797b6c6SAneesh Kumar K.V statl->st_ctime_sec = st->st_ctime; 540c797b6c6SAneesh Kumar K.V statl->st_ctime_nsec = st->st_ctim.tv_nsec; 541c797b6c6SAneesh Kumar K.V /* Currently we only support BASIC fields in stat */ 542c797b6c6SAneesh Kumar K.V statl->st_result_mask = P9_STATS_BASIC; 543c797b6c6SAneesh Kumar K.V stat2qid(st, &statl->qid); 5441c7850f9SSasha Levin } 5451c7850f9SSasha Levin 546ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev, 547af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5481c7850f9SSasha Levin { 549bfc15268SAneesh Kumar K.V u64 offset; 550bfc15268SAneesh Kumar K.V u32 fid_val; 551c797b6c6SAneesh Kumar K.V u16 iov_cnt; 552c797b6c6SAneesh Kumar K.V void *iov_base; 553c797b6c6SAneesh Kumar K.V size_t iov_len; 554bfc15268SAneesh Kumar K.V u32 count, rcount; 555bfc15268SAneesh Kumar K.V struct p9_fid *fid; 556c797b6c6SAneesh Kumar K.V 5571c7850f9SSasha Levin 558bfc15268SAneesh Kumar K.V rcount = 0; 559bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 56031a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 56150c479e0SAneesh Kumar K.V 56250c479e0SAneesh Kumar K.V iov_base = pdu->in_iov[0].iov_base; 56350c479e0SAneesh Kumar K.V iov_len = pdu->in_iov[0].iov_len; 56450c479e0SAneesh Kumar K.V iov_cnt = pdu->in_iov_cnt; 5655529bcd7SAsias He pdu->in_iov[0].iov_base += VIRTIO_9P_HDR_LEN + sizeof(u32); 5665529bcd7SAsias He pdu->in_iov[0].iov_len -= VIRTIO_9P_HDR_LEN + sizeof(u32); 5676b163a87SAneesh Kumar K.V pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov, 568bfc15268SAneesh Kumar K.V count, 5696b163a87SAneesh Kumar K.V pdu->in_iov_cnt); 570bfc15268SAneesh Kumar K.V rcount = preadv(fid->fd, pdu->in_iov, 571bfc15268SAneesh Kumar K.V pdu->in_iov_cnt, offset); 572bfc15268SAneesh Kumar K.V if (rcount > count) 573bfc15268SAneesh Kumar K.V rcount = count; 574bfc15268SAneesh Kumar K.V /* 575bfc15268SAneesh Kumar K.V * Update the iov_base back, so that rest of 576bfc15268SAneesh Kumar K.V * pdu_writef works correctly. 577bfc15268SAneesh Kumar K.V */ 57850c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_base = iov_base; 57950c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_len = iov_len; 58050c479e0SAneesh Kumar K.V pdu->in_iov_cnt = iov_cnt; 581c797b6c6SAneesh Kumar K.V 5825529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 583bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 584bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 585bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 586ead43b01SAneesh Kumar K.V return; 5871c7850f9SSasha Levin } 5881c7850f9SSasha Levin 589c797b6c6SAneesh Kumar K.V static int virtio_p9_dentry_size(struct dirent *dent) 590c797b6c6SAneesh Kumar K.V { 591c797b6c6SAneesh Kumar K.V /* 592c797b6c6SAneesh Kumar K.V * Size of each dirent: 593c797b6c6SAneesh Kumar K.V * qid(13) + offset(8) + type(1) + name_len(2) + name 594c797b6c6SAneesh Kumar K.V */ 595c797b6c6SAneesh Kumar K.V return 24 + strlen(dent->d_name); 596c797b6c6SAneesh Kumar K.V } 597c797b6c6SAneesh Kumar K.V 598c797b6c6SAneesh Kumar K.V static void virtio_p9_readdir(struct p9_dev *p9dev, 599c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 600c797b6c6SAneesh Kumar K.V { 601c797b6c6SAneesh Kumar K.V u32 fid_val; 602c797b6c6SAneesh Kumar K.V u32 count, rcount; 603c797b6c6SAneesh Kumar K.V struct stat st; 604c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 605c797b6c6SAneesh Kumar K.V struct dirent *dent; 606c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 607c797b6c6SAneesh Kumar K.V u64 offset, old_offset; 608c797b6c6SAneesh Kumar K.V 609c797b6c6SAneesh Kumar K.V rcount = 0; 610c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 61131a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 612c797b6c6SAneesh Kumar K.V 61332585666SSasha Levin if (!is_dir(fid)) { 61469bb4278SSasha Levin errno = EINVAL; 615c797b6c6SAneesh Kumar K.V goto err_out; 616c797b6c6SAneesh Kumar K.V } 617c797b6c6SAneesh Kumar K.V 618c797b6c6SAneesh Kumar K.V /* Move the offset specified */ 619c797b6c6SAneesh Kumar K.V seekdir(fid->dir, offset); 620c797b6c6SAneesh Kumar K.V 621c797b6c6SAneesh Kumar K.V old_offset = offset; 622c797b6c6SAneesh Kumar K.V /* If reading a dir, fill the buffer with p9_stat entries */ 623c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir); 624c797b6c6SAneesh Kumar K.V 625c797b6c6SAneesh Kumar K.V /* Skip the space for writing count */ 626c797b6c6SAneesh Kumar K.V pdu->write_offset += sizeof(u32); 627c797b6c6SAneesh Kumar K.V while (dent) { 628c797b6c6SAneesh Kumar K.V u32 read; 629c797b6c6SAneesh Kumar K.V struct p9_qid qid; 630c797b6c6SAneesh Kumar K.V 631c797b6c6SAneesh Kumar K.V if ((rcount + virtio_p9_dentry_size(dent)) > count) { 632c797b6c6SAneesh Kumar K.V /* seek to the previous offset and return */ 633c797b6c6SAneesh Kumar K.V seekdir(fid->dir, old_offset); 634c797b6c6SAneesh Kumar K.V break; 635c797b6c6SAneesh Kumar K.V } 636c797b6c6SAneesh Kumar K.V old_offset = dent->d_off; 637c797b6c6SAneesh Kumar K.V lstat(rel_to_abs(p9dev, dent->d_name, full_path), &st); 638c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 639c797b6c6SAneesh Kumar K.V read = pdu->write_offset; 640c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qqbs", &qid, dent->d_off, 641c797b6c6SAneesh Kumar K.V dent->d_type, dent->d_name); 642c797b6c6SAneesh Kumar K.V rcount += pdu->write_offset - read; 643c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir); 644c797b6c6SAneesh Kumar K.V } 645c797b6c6SAneesh Kumar K.V 6465529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 647c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 648c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 649c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 650c797b6c6SAneesh Kumar K.V return; 651c797b6c6SAneesh Kumar K.V err_out: 652c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 653c797b6c6SAneesh Kumar K.V return; 654c797b6c6SAneesh Kumar K.V } 655c797b6c6SAneesh Kumar K.V 656c797b6c6SAneesh Kumar K.V 657c797b6c6SAneesh Kumar K.V static void virtio_p9_getattr(struct p9_dev *p9dev, 658af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 6591c7850f9SSasha Levin { 660bfc15268SAneesh Kumar K.V u32 fid_val; 661af045e53SAneesh Kumar K.V struct stat st; 662c797b6c6SAneesh Kumar K.V u64 request_mask; 663bfc15268SAneesh Kumar K.V struct p9_fid *fid; 664c797b6c6SAneesh Kumar K.V struct p9_stat_dotl statl; 6651c7850f9SSasha Levin 666c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dq", &fid_val, &request_mask); 66731a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 66830204a77SAneesh Kumar K.V if (lstat(fid->abs_path, &st) < 0) 6696c8ca053SAneesh Kumar K.V goto err_out; 6701c7850f9SSasha Levin 671c797b6c6SAneesh Kumar K.V virtio_p9_fill_stat(p9dev, &st, &statl); 672c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "A", &statl); 673bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 674bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 675ead43b01SAneesh Kumar K.V return; 6766c8ca053SAneesh Kumar K.V err_out: 6776c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 6786c8ca053SAneesh Kumar K.V return; 6791c7850f9SSasha Levin } 6801c7850f9SSasha Levin 681c797b6c6SAneesh Kumar K.V /* FIXME!! from linux/fs.h */ 682c797b6c6SAneesh Kumar K.V /* 683c797b6c6SAneesh Kumar K.V * Attribute flags. These should be or-ed together to figure out what 684c797b6c6SAneesh Kumar K.V * has been changed! 685c797b6c6SAneesh Kumar K.V */ 686c797b6c6SAneesh Kumar K.V #define ATTR_MODE (1 << 0) 687c797b6c6SAneesh Kumar K.V #define ATTR_UID (1 << 1) 688c797b6c6SAneesh Kumar K.V #define ATTR_GID (1 << 2) 689c797b6c6SAneesh Kumar K.V #define ATTR_SIZE (1 << 3) 690c797b6c6SAneesh Kumar K.V #define ATTR_ATIME (1 << 4) 691c797b6c6SAneesh Kumar K.V #define ATTR_MTIME (1 << 5) 692c797b6c6SAneesh Kumar K.V #define ATTR_CTIME (1 << 6) 693c797b6c6SAneesh Kumar K.V #define ATTR_ATIME_SET (1 << 7) 694c797b6c6SAneesh Kumar K.V #define ATTR_MTIME_SET (1 << 8) 695c797b6c6SAneesh Kumar K.V #define ATTR_FORCE (1 << 9) /* Not a change, but a change it */ 696c797b6c6SAneesh Kumar K.V #define ATTR_ATTR_FLAG (1 << 10) 697c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SUID (1 << 11) 698c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SGID (1 << 12) 699c797b6c6SAneesh Kumar K.V #define ATTR_FILE (1 << 13) 700c797b6c6SAneesh Kumar K.V #define ATTR_KILL_PRIV (1 << 14) 701c797b6c6SAneesh Kumar K.V #define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ 702c797b6c6SAneesh Kumar K.V #define ATTR_TIMES_SET (1 << 16) 703c797b6c6SAneesh Kumar K.V 704c797b6c6SAneesh Kumar K.V #define ATTR_MASK 127 705c797b6c6SAneesh Kumar K.V 706c797b6c6SAneesh Kumar K.V static void virtio_p9_setattr(struct p9_dev *p9dev, 707af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 7081c7850f9SSasha Levin { 709c797b6c6SAneesh Kumar K.V int ret = 0; 710bfc15268SAneesh Kumar K.V u32 fid_val; 711bfc15268SAneesh Kumar K.V struct p9_fid *fid; 712c797b6c6SAneesh Kumar K.V struct p9_iattr_dotl p9attr; 7131c7850f9SSasha Levin 714c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dI", &fid_val, &p9attr); 71531a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 7161c7850f9SSasha Levin 717c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MODE) { 718c797b6c6SAneesh Kumar K.V ret = chmod(fid->abs_path, p9attr.mode); 719c797b6c6SAneesh Kumar K.V if (ret < 0) 720c797b6c6SAneesh Kumar K.V goto err_out; 721c797b6c6SAneesh Kumar K.V } 722c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_ATIME | ATTR_MTIME)) { 723c797b6c6SAneesh Kumar K.V struct timespec times[2]; 724c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME) { 725c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME_SET) { 726c797b6c6SAneesh Kumar K.V times[0].tv_sec = p9attr.atime_sec; 727c797b6c6SAneesh Kumar K.V times[0].tv_nsec = p9attr.atime_nsec; 728c797b6c6SAneesh Kumar K.V } else { 729c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_NOW; 730c797b6c6SAneesh Kumar K.V } 731c797b6c6SAneesh Kumar K.V } else { 732c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_OMIT; 733c797b6c6SAneesh Kumar K.V } 734c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME) { 735c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME_SET) { 736c797b6c6SAneesh Kumar K.V times[1].tv_sec = p9attr.mtime_sec; 737c797b6c6SAneesh Kumar K.V times[1].tv_nsec = p9attr.mtime_nsec; 738c797b6c6SAneesh Kumar K.V } else { 739c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_NOW; 740c797b6c6SAneesh Kumar K.V } 741c797b6c6SAneesh Kumar K.V } else 742c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_OMIT; 743c797b6c6SAneesh Kumar K.V 744c797b6c6SAneesh Kumar K.V ret = utimensat(-1, fid->abs_path, times, AT_SYMLINK_NOFOLLOW); 745c797b6c6SAneesh Kumar K.V if (ret < 0) 746c797b6c6SAneesh Kumar K.V goto err_out; 747c797b6c6SAneesh Kumar K.V } 748c797b6c6SAneesh Kumar K.V /* 749c797b6c6SAneesh Kumar K.V * If the only valid entry in iattr is ctime we can call 750c797b6c6SAneesh Kumar K.V * chown(-1,-1) to update the ctime of the file 751c797b6c6SAneesh Kumar K.V */ 752c797b6c6SAneesh Kumar K.V if ((p9attr.valid & (ATTR_UID | ATTR_GID)) || 753c797b6c6SAneesh Kumar K.V ((p9attr.valid & ATTR_CTIME) 754c797b6c6SAneesh Kumar K.V && !((p9attr.valid & ATTR_MASK) & ~ATTR_CTIME))) { 755c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_UID)) 756506fd90bSSasha Levin p9attr.uid = KUIDT_INIT(-1); 757c797b6c6SAneesh Kumar K.V 758c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_GID)) 759506fd90bSSasha Levin p9attr.gid = KGIDT_INIT(-1); 760c797b6c6SAneesh Kumar K.V 761506fd90bSSasha Levin ret = lchown(fid->abs_path, __kuid_val(p9attr.uid), 762506fd90bSSasha Levin __kgid_val(p9attr.gid)); 763c797b6c6SAneesh Kumar K.V if (ret < 0) 764c797b6c6SAneesh Kumar K.V goto err_out; 765c797b6c6SAneesh Kumar K.V } 766c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_SIZE)) { 767c797b6c6SAneesh Kumar K.V ret = truncate(fid->abs_path, p9attr.size); 768c797b6c6SAneesh Kumar K.V if (ret < 0) 769c797b6c6SAneesh Kumar K.V goto err_out; 770c797b6c6SAneesh Kumar K.V } 7715529bcd7SAsias He *outlen = VIRTIO_9P_HDR_LEN; 772bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 773ead43b01SAneesh Kumar K.V return; 7744bc9734aSAneesh Kumar K.V err_out: 7754bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 7764bc9734aSAneesh Kumar K.V return; 7771c7850f9SSasha Levin } 7781c7850f9SSasha Levin 779ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev, 780af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 7811c7850f9SSasha Levin { 7824bc9734aSAneesh Kumar K.V 783bfc15268SAneesh Kumar K.V u64 offset; 784bfc15268SAneesh Kumar K.V u32 fid_val; 7854bc9734aSAneesh Kumar K.V u32 count; 7864bc9734aSAneesh Kumar K.V ssize_t res; 78750c479e0SAneesh Kumar K.V u16 iov_cnt; 78850c479e0SAneesh Kumar K.V void *iov_base; 78950c479e0SAneesh Kumar K.V size_t iov_len; 790bfc15268SAneesh Kumar K.V struct p9_fid *fid; 791b064b05aSAneesh Kumar K.V /* u32 fid + u64 offset + u32 count */ 792b064b05aSAneesh Kumar K.V int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32); 7931c7850f9SSasha Levin 794bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 79531a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 796af045e53SAneesh Kumar K.V 79750c479e0SAneesh Kumar K.V iov_base = pdu->out_iov[0].iov_base; 79850c479e0SAneesh Kumar K.V iov_len = pdu->out_iov[0].iov_len; 79950c479e0SAneesh Kumar K.V iov_cnt = pdu->out_iov_cnt; 80050c479e0SAneesh Kumar K.V 801bfc15268SAneesh Kumar K.V /* Adjust the iovec to skip the header and meta data */ 802b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size); 803b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_len -= (sizeof(struct p9_msg) + twrite_size); 804bfc15268SAneesh Kumar K.V pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count, 8056b163a87SAneesh Kumar K.V pdu->out_iov_cnt); 8064bc9734aSAneesh Kumar K.V res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset); 80750c479e0SAneesh Kumar K.V /* 80850c479e0SAneesh Kumar K.V * Update the iov_base back, so that rest of 80950c479e0SAneesh Kumar K.V * pdu_readf works correctly. 81050c479e0SAneesh Kumar K.V */ 81150c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_base = iov_base; 81250c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_len = iov_len; 81350c479e0SAneesh Kumar K.V pdu->out_iov_cnt = iov_cnt; 814c797b6c6SAneesh Kumar K.V 8154bc9734aSAneesh Kumar K.V if (res < 0) 8164bc9734aSAneesh Kumar K.V goto err_out; 8174bc9734aSAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", res); 818bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 819bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 820ead43b01SAneesh Kumar K.V return; 8214bc9734aSAneesh Kumar K.V err_out: 8224bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 8234bc9734aSAneesh Kumar K.V return; 8241c7850f9SSasha Levin } 8251c7850f9SSasha Levin 8266fc5cd9bSSasha Levin static void virtio_p9_remove(struct p9_dev *p9dev, 8276fc5cd9bSSasha Levin struct p9_pdu *pdu, u32 *outlen) 8286fc5cd9bSSasha Levin { 8296fc5cd9bSSasha Levin int ret; 8306fc5cd9bSSasha Levin u32 fid_val; 8316fc5cd9bSSasha Levin struct p9_fid *fid; 8326fc5cd9bSSasha Levin 8336fc5cd9bSSasha Levin virtio_p9_pdu_readf(pdu, "d", &fid_val); 83431a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 8356fc5cd9bSSasha Levin 8369b604a9cSSasha Levin ret = remove(fid->abs_path); 8376fc5cd9bSSasha Levin if (ret < 0) 8386fc5cd9bSSasha Levin goto err_out; 8396fc5cd9bSSasha Levin *outlen = pdu->write_offset; 8406fc5cd9bSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 8416fc5cd9bSSasha Levin return; 8426fc5cd9bSSasha Levin 8436fc5cd9bSSasha Levin err_out: 8446fc5cd9bSSasha Levin virtio_p9_error_reply(p9dev, pdu, errno, outlen); 8456fc5cd9bSSasha Levin return; 8466fc5cd9bSSasha Levin } 8476fc5cd9bSSasha Levin 848f161f28bSSasha Levin static void virtio_p9_rename(struct p9_dev *p9dev, 849f161f28bSSasha Levin struct p9_pdu *pdu, u32 *outlen) 850f161f28bSSasha Levin { 851f161f28bSSasha Levin int ret; 852f161f28bSSasha Levin u32 fid_val, new_fid_val; 853f161f28bSSasha Levin struct p9_fid *fid, *new_fid; 854f161f28bSSasha Levin char full_path[PATH_MAX], *new_name; 855f161f28bSSasha Levin 856f161f28bSSasha Levin virtio_p9_pdu_readf(pdu, "dds", &fid_val, &new_fid_val, &new_name); 85731a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 85831a6fb8dSSasha Levin new_fid = get_fid(p9dev, new_fid_val); 859f161f28bSSasha Levin 86032832dd1SG. Campana ret = snprintf(full_path, sizeof(full_path), "%s/%s", new_fid->abs_path, new_name); 86132832dd1SG. Campana if (ret >= (int)sizeof(full_path)) { 86232832dd1SG. Campana errno = ENAMETOOLONG; 86332832dd1SG. Campana goto err_out; 86432832dd1SG. Campana } 86532832dd1SG. Campana 8669bb99a82SG. Campana if (path_is_illegal(full_path)) { 8679bb99a82SG. Campana errno = EACCES; 8689bb99a82SG. Campana goto err_out; 8699bb99a82SG. Campana } 8709bb99a82SG. Campana 871f161f28bSSasha Levin ret = rename(fid->abs_path, full_path); 872f161f28bSSasha Levin if (ret < 0) 873f161f28bSSasha Levin goto err_out; 874f161f28bSSasha Levin *outlen = pdu->write_offset; 875f161f28bSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 876f161f28bSSasha Levin return; 877f161f28bSSasha Levin 878f161f28bSSasha Levin err_out: 879f161f28bSSasha Levin virtio_p9_error_reply(p9dev, pdu, errno, outlen); 880f161f28bSSasha Levin return; 881f161f28bSSasha Levin } 882f161f28bSSasha Levin 883c797b6c6SAneesh Kumar K.V static void virtio_p9_readlink(struct p9_dev *p9dev, 884c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 885c797b6c6SAneesh Kumar K.V { 886c797b6c6SAneesh Kumar K.V int ret; 887c797b6c6SAneesh Kumar K.V u32 fid_val; 888c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 889c797b6c6SAneesh Kumar K.V char target_path[PATH_MAX]; 890c797b6c6SAneesh Kumar K.V 891c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 89231a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 893c797b6c6SAneesh Kumar K.V 894c797b6c6SAneesh Kumar K.V memset(target_path, 0, PATH_MAX); 895c797b6c6SAneesh Kumar K.V ret = readlink(fid->abs_path, target_path, PATH_MAX - 1); 896c797b6c6SAneesh Kumar K.V if (ret < 0) 897c797b6c6SAneesh Kumar K.V goto err_out; 898c797b6c6SAneesh Kumar K.V 899c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "s", target_path); 900c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 901c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 902c797b6c6SAneesh Kumar K.V return; 903c797b6c6SAneesh Kumar K.V err_out: 904c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 905c797b6c6SAneesh Kumar K.V return; 906c797b6c6SAneesh Kumar K.V } 907c797b6c6SAneesh Kumar K.V 908c797b6c6SAneesh Kumar K.V static void virtio_p9_statfs(struct p9_dev *p9dev, 909c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 910c797b6c6SAneesh Kumar K.V { 911c797b6c6SAneesh Kumar K.V int ret; 912c797b6c6SAneesh Kumar K.V u64 fsid; 913c797b6c6SAneesh Kumar K.V u32 fid_val; 914c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 915c797b6c6SAneesh Kumar K.V struct statfs stat_buf; 916c797b6c6SAneesh Kumar K.V 917c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 91831a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 919c797b6c6SAneesh Kumar K.V 920c797b6c6SAneesh Kumar K.V ret = statfs(fid->abs_path, &stat_buf); 921c797b6c6SAneesh Kumar K.V if (ret < 0) 922c797b6c6SAneesh Kumar K.V goto err_out; 923c797b6c6SAneesh Kumar K.V /* FIXME!! f_blocks needs update based on client msize */ 924c797b6c6SAneesh Kumar K.V fsid = (unsigned int) stat_buf.f_fsid.__val[0] | 925c797b6c6SAneesh Kumar K.V (unsigned long long)stat_buf.f_fsid.__val[1] << 32; 926c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ddqqqqqqd", stat_buf.f_type, 927c797b6c6SAneesh Kumar K.V stat_buf.f_bsize, stat_buf.f_blocks, 928c797b6c6SAneesh Kumar K.V stat_buf.f_bfree, stat_buf.f_bavail, 929c797b6c6SAneesh Kumar K.V stat_buf.f_files, stat_buf.f_ffree, 930c797b6c6SAneesh Kumar K.V fsid, stat_buf.f_namelen); 931c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 932c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 933c797b6c6SAneesh Kumar K.V return; 934c797b6c6SAneesh Kumar K.V err_out: 935c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 936c797b6c6SAneesh Kumar K.V return; 937c797b6c6SAneesh Kumar K.V } 938c797b6c6SAneesh Kumar K.V 939c797b6c6SAneesh Kumar K.V static void virtio_p9_mknod(struct p9_dev *p9dev, 940c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 941c797b6c6SAneesh Kumar K.V { 942c797b6c6SAneesh Kumar K.V int ret; 943c797b6c6SAneesh Kumar K.V char *name; 944c797b6c6SAneesh Kumar K.V struct stat st; 945c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 946c797b6c6SAneesh Kumar K.V struct p9_qid qid; 947c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 948c797b6c6SAneesh Kumar K.V u32 fid_val, mode, major, minor, gid; 949c797b6c6SAneesh Kumar K.V 950c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdddd", &fid_val, &name, &mode, 951c797b6c6SAneesh Kumar K.V &major, &minor, &gid); 952c797b6c6SAneesh Kumar K.V 95331a6fb8dSSasha Levin dfid = get_fid(p9dev, fid_val); 95432832dd1SG. Campana ret = snprintf(full_path, sizeof(full_path), "%s/%s", dfid->abs_path, name); 95532832dd1SG. Campana if (ret >= (int)sizeof(full_path)) { 95632832dd1SG. Campana errno = ENAMETOOLONG; 95732832dd1SG. Campana goto err_out; 95832832dd1SG. Campana } 95932832dd1SG. Campana 9609bb99a82SG. Campana if (path_is_illegal(full_path)) { 9619bb99a82SG. Campana errno = EACCES; 9629bb99a82SG. Campana goto err_out; 9639bb99a82SG. Campana } 9649bb99a82SG. Campana 965c797b6c6SAneesh Kumar K.V ret = mknod(full_path, mode, makedev(major, minor)); 966c797b6c6SAneesh Kumar K.V if (ret < 0) 967c797b6c6SAneesh Kumar K.V goto err_out; 968c797b6c6SAneesh Kumar K.V 969c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0) 970c797b6c6SAneesh Kumar K.V goto err_out; 971c797b6c6SAneesh Kumar K.V 972c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 973c797b6c6SAneesh Kumar K.V if (ret < 0) 974c797b6c6SAneesh Kumar K.V goto err_out; 975c797b6c6SAneesh Kumar K.V 976c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 977c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 978c797b6c6SAneesh Kumar K.V free(name); 979c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 980c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 981c797b6c6SAneesh Kumar K.V return; 982c797b6c6SAneesh Kumar K.V err_out: 983c797b6c6SAneesh Kumar K.V free(name); 984c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 985c797b6c6SAneesh Kumar K.V return; 986c797b6c6SAneesh Kumar K.V } 987c797b6c6SAneesh Kumar K.V 988c797b6c6SAneesh Kumar K.V static void virtio_p9_fsync(struct p9_dev *p9dev, 989c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 990c797b6c6SAneesh Kumar K.V { 991644140efSRussell King int ret, fd; 992c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 993c797b6c6SAneesh Kumar K.V u32 fid_val, datasync; 994c797b6c6SAneesh Kumar K.V 995c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid_val, &datasync); 99631a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 997c797b6c6SAneesh Kumar K.V 998644140efSRussell King if (fid->dir) 999644140efSRussell King fd = dirfd(fid->dir); 1000c797b6c6SAneesh Kumar K.V else 1001644140efSRussell King fd = fid->fd; 1002644140efSRussell King 1003644140efSRussell King if (datasync) 1004644140efSRussell King ret = fdatasync(fd); 1005644140efSRussell King else 1006644140efSRussell King ret = fsync(fd); 1007c797b6c6SAneesh Kumar K.V if (ret < 0) 1008c797b6c6SAneesh Kumar K.V goto err_out; 1009c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1010c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1011c797b6c6SAneesh Kumar K.V return; 1012c797b6c6SAneesh Kumar K.V err_out: 1013c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1014c797b6c6SAneesh Kumar K.V return; 1015c797b6c6SAneesh Kumar K.V } 1016c797b6c6SAneesh Kumar K.V 1017c797b6c6SAneesh Kumar K.V static void virtio_p9_symlink(struct p9_dev *p9dev, 1018c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1019c797b6c6SAneesh Kumar K.V { 1020c797b6c6SAneesh Kumar K.V int ret; 1021c797b6c6SAneesh Kumar K.V struct stat st; 1022c797b6c6SAneesh Kumar K.V u32 fid_val, gid; 1023c797b6c6SAneesh Kumar K.V struct p9_qid qid; 1024c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 1025c797b6c6SAneesh Kumar K.V char new_name[PATH_MAX]; 1026c797b6c6SAneesh Kumar K.V char *old_path, *name; 1027c797b6c6SAneesh Kumar K.V 1028c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dssd", &fid_val, &name, &old_path, &gid); 1029c797b6c6SAneesh Kumar K.V 103031a6fb8dSSasha Levin dfid = get_fid(p9dev, fid_val); 103132832dd1SG. Campana ret = snprintf(new_name, sizeof(new_name), "%s/%s", dfid->abs_path, name); 103232832dd1SG. Campana if (ret >= (int)sizeof(new_name)) { 103332832dd1SG. Campana errno = ENAMETOOLONG; 103432832dd1SG. Campana goto err_out; 103532832dd1SG. Campana } 103632832dd1SG. Campana 10379bb99a82SG. Campana if (path_is_illegal(new_name)) { 10389bb99a82SG. Campana errno = EACCES; 10399bb99a82SG. Campana goto err_out; 10409bb99a82SG. Campana } 10419bb99a82SG. Campana 1042c797b6c6SAneesh Kumar K.V ret = symlink(old_path, new_name); 1043c797b6c6SAneesh Kumar K.V if (ret < 0) 1044c797b6c6SAneesh Kumar K.V goto err_out; 1045c797b6c6SAneesh Kumar K.V 1046c797b6c6SAneesh Kumar K.V if (lstat(new_name, &st) < 0) 1047c797b6c6SAneesh Kumar K.V goto err_out; 1048c797b6c6SAneesh Kumar K.V 1049c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 1050c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 1051c797b6c6SAneesh Kumar K.V free(name); 1052c797b6c6SAneesh Kumar K.V free(old_path); 1053c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1054c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1055c797b6c6SAneesh Kumar K.V return; 1056c797b6c6SAneesh Kumar K.V err_out: 1057c797b6c6SAneesh Kumar K.V free(name); 1058c797b6c6SAneesh Kumar K.V free(old_path); 1059c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1060c797b6c6SAneesh Kumar K.V return; 1061c797b6c6SAneesh Kumar K.V } 1062c797b6c6SAneesh Kumar K.V 1063c797b6c6SAneesh Kumar K.V static void virtio_p9_link(struct p9_dev *p9dev, 1064c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1065c797b6c6SAneesh Kumar K.V { 1066c797b6c6SAneesh Kumar K.V int ret; 1067c797b6c6SAneesh Kumar K.V char *name; 1068c797b6c6SAneesh Kumar K.V u32 fid_val, dfid_val; 1069c797b6c6SAneesh Kumar K.V struct p9_fid *dfid, *fid; 1070c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 1071c797b6c6SAneesh Kumar K.V 1072c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dds", &dfid_val, &fid_val, &name); 1073c797b6c6SAneesh Kumar K.V 107431a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 107531a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 107632832dd1SG. Campana ret = snprintf(full_path, sizeof(full_path), "%s/%s", dfid->abs_path, name); 107732832dd1SG. Campana if (ret >= (int)sizeof(full_path)) { 107832832dd1SG. Campana errno = ENAMETOOLONG; 107932832dd1SG. Campana goto err_out; 108032832dd1SG. Campana } 108132832dd1SG. Campana 10829bb99a82SG. Campana if (path_is_illegal(full_path)) { 10839bb99a82SG. Campana errno = EACCES; 10849bb99a82SG. Campana goto err_out; 10859bb99a82SG. Campana } 10869bb99a82SG. Campana 1087c797b6c6SAneesh Kumar K.V ret = link(fid->abs_path, full_path); 1088c797b6c6SAneesh Kumar K.V if (ret < 0) 1089c797b6c6SAneesh Kumar K.V goto err_out; 1090c797b6c6SAneesh Kumar K.V free(name); 1091c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1092c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1093c797b6c6SAneesh Kumar K.V return; 1094c797b6c6SAneesh Kumar K.V err_out: 1095c797b6c6SAneesh Kumar K.V free(name); 1096c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1097c797b6c6SAneesh Kumar K.V return; 1098c797b6c6SAneesh Kumar K.V 1099c797b6c6SAneesh Kumar K.V } 1100c797b6c6SAneesh Kumar K.V 1101c797b6c6SAneesh Kumar K.V static void virtio_p9_lock(struct p9_dev *p9dev, 1102c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1103c797b6c6SAneesh Kumar K.V { 1104c797b6c6SAneesh Kumar K.V u8 ret; 1105c797b6c6SAneesh Kumar K.V u32 fid_val; 1106c797b6c6SAneesh Kumar K.V struct p9_flock flock; 1107c797b6c6SAneesh Kumar K.V 1108c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbdqqds", &fid_val, &flock.type, 1109c797b6c6SAneesh Kumar K.V &flock.flags, &flock.start, &flock.length, 1110c797b6c6SAneesh Kumar K.V &flock.proc_id, &flock.client_id); 1111c797b6c6SAneesh Kumar K.V 1112c797b6c6SAneesh Kumar K.V /* Just return success */ 1113c797b6c6SAneesh Kumar K.V ret = P9_LOCK_SUCCESS; 1114c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", ret); 1115c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1116c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1117c797b6c6SAneesh Kumar K.V free(flock.client_id); 1118c797b6c6SAneesh Kumar K.V return; 1119c797b6c6SAneesh Kumar K.V } 1120c797b6c6SAneesh Kumar K.V 1121c797b6c6SAneesh Kumar K.V static void virtio_p9_getlock(struct p9_dev *p9dev, 1122c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1123c797b6c6SAneesh Kumar K.V { 1124c797b6c6SAneesh Kumar K.V u32 fid_val; 1125c797b6c6SAneesh Kumar K.V struct p9_getlock glock; 1126c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbqqds", &fid_val, &glock.type, 1127c797b6c6SAneesh Kumar K.V &glock.start, &glock.length, &glock.proc_id, 1128c797b6c6SAneesh Kumar K.V &glock.client_id); 1129c797b6c6SAneesh Kumar K.V 1130c797b6c6SAneesh Kumar K.V /* Just return success */ 1131c797b6c6SAneesh Kumar K.V glock.type = F_UNLCK; 1132c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "bqqds", glock.type, 1133c797b6c6SAneesh Kumar K.V glock.start, glock.length, glock.proc_id, 1134c797b6c6SAneesh Kumar K.V glock.client_id); 1135c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1136c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1137c797b6c6SAneesh Kumar K.V free(glock.client_id); 1138c797b6c6SAneesh Kumar K.V return; 1139c797b6c6SAneesh Kumar K.V } 1140c797b6c6SAneesh Kumar K.V 1141c797b6c6SAneesh Kumar K.V static int virtio_p9_ancestor(char *path, char *ancestor) 1142c797b6c6SAneesh Kumar K.V { 1143c797b6c6SAneesh Kumar K.V int size = strlen(ancestor); 1144c797b6c6SAneesh Kumar K.V if (!strncmp(path, ancestor, size)) { 1145c797b6c6SAneesh Kumar K.V /* 1146c797b6c6SAneesh Kumar K.V * Now check whether ancestor is a full name or 1147c797b6c6SAneesh Kumar K.V * or directory component and not just part 1148c797b6c6SAneesh Kumar K.V * of a name. 1149c797b6c6SAneesh Kumar K.V */ 1150c797b6c6SAneesh Kumar K.V if (path[size] == '\0' || path[size] == '/') 1151c797b6c6SAneesh Kumar K.V return 1; 1152c797b6c6SAneesh Kumar K.V } 1153c797b6c6SAneesh Kumar K.V return 0; 1154c797b6c6SAneesh Kumar K.V } 1155c797b6c6SAneesh Kumar K.V 1156*e277a1b4SG. Campana static int virtio_p9_fix_path(struct p9_fid *fid, char *old_name, char *new_name) 1157c797b6c6SAneesh Kumar K.V { 1158*e277a1b4SG. Campana int ret; 1159*e277a1b4SG. Campana char *p, tmp_name[PATH_MAX]; 1160c797b6c6SAneesh Kumar K.V size_t rp_sz = strlen(old_name); 1161c797b6c6SAneesh Kumar K.V 1162*e277a1b4SG. Campana if (rp_sz == strlen(fid->path)) { 1163c797b6c6SAneesh Kumar K.V /* replace the full name */ 1164*e277a1b4SG. Campana p = new_name; 1165*e277a1b4SG. Campana } else { 1166c797b6c6SAneesh Kumar K.V /* save the trailing path details */ 1167*e277a1b4SG. Campana ret = snprintf(tmp_name, sizeof(tmp_name), "%s%s", new_name, fid->path + rp_sz); 1168*e277a1b4SG. Campana if (ret >= (int)sizeof(tmp_name)) 1169*e277a1b4SG. Campana return -1; 1170*e277a1b4SG. Campana p = tmp_name; 1171*e277a1b4SG. Campana } 1172*e277a1b4SG. Campana 1173*e277a1b4SG. Campana return join_path(fid, p); 1174c797b6c6SAneesh Kumar K.V } 1175c797b6c6SAneesh Kumar K.V 1176e2341580SSasha Levin static void rename_fids(struct p9_dev *p9dev, char *old_name, char *new_name) 1177e2341580SSasha Levin { 1178e2341580SSasha Levin struct rb_node *node = rb_first(&p9dev->fids); 1179e2341580SSasha Levin 1180e2341580SSasha Levin while (node) { 1181e2341580SSasha Levin struct p9_fid *fid = rb_entry(node, struct p9_fid, node); 1182e2341580SSasha Levin 1183e2341580SSasha Levin if (fid->fid != P9_NOFID && virtio_p9_ancestor(fid->path, old_name)) { 1184*e277a1b4SG. Campana virtio_p9_fix_path(fid, old_name, new_name); 1185e2341580SSasha Levin } 1186e2341580SSasha Levin node = rb_next(node); 1187e2341580SSasha Levin } 1188e2341580SSasha Levin } 1189e2341580SSasha Levin 1190c797b6c6SAneesh Kumar K.V static void virtio_p9_renameat(struct p9_dev *p9dev, 1191c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1192c797b6c6SAneesh Kumar K.V { 1193e2341580SSasha Levin int ret; 1194c797b6c6SAneesh Kumar K.V char *old_name, *new_name; 1195c797b6c6SAneesh Kumar K.V u32 old_dfid_val, new_dfid_val; 1196c797b6c6SAneesh Kumar K.V struct p9_fid *old_dfid, *new_dfid; 1197c797b6c6SAneesh Kumar K.V char old_full_path[PATH_MAX], new_full_path[PATH_MAX]; 1198c797b6c6SAneesh Kumar K.V 1199c797b6c6SAneesh Kumar K.V 1200c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsds", &old_dfid_val, &old_name, 1201c797b6c6SAneesh Kumar K.V &new_dfid_val, &new_name); 1202c797b6c6SAneesh Kumar K.V 120331a6fb8dSSasha Levin old_dfid = get_fid(p9dev, old_dfid_val); 120431a6fb8dSSasha Levin new_dfid = get_fid(p9dev, new_dfid_val); 1205c797b6c6SAneesh Kumar K.V 120632832dd1SG. Campana ret = snprintf(old_full_path, sizeof(old_full_path), "%s/%s", old_dfid->abs_path, old_name); 120732832dd1SG. Campana if (ret >= (int)sizeof(old_full_path)) { 120832832dd1SG. Campana errno = ENAMETOOLONG; 120932832dd1SG. Campana goto err_out; 121032832dd1SG. Campana } 121132832dd1SG. Campana 121232832dd1SG. Campana ret = snprintf(new_full_path, sizeof(new_full_path), "%s/%s", new_dfid->abs_path, new_name); 121332832dd1SG. Campana if (ret >= (int)sizeof(new_full_path)) { 121432832dd1SG. Campana errno = ENAMETOOLONG; 121532832dd1SG. Campana goto err_out; 121632832dd1SG. Campana } 121732832dd1SG. Campana 12189bb99a82SG. Campana if (path_is_illegal(old_full_path) || path_is_illegal(new_full_path)) { 12199bb99a82SG. Campana errno = EACCES; 12209bb99a82SG. Campana goto err_out; 12219bb99a82SG. Campana } 12229bb99a82SG. Campana 1223c797b6c6SAneesh Kumar K.V ret = rename(old_full_path, new_full_path); 1224c797b6c6SAneesh Kumar K.V if (ret < 0) 1225c797b6c6SAneesh Kumar K.V goto err_out; 1226c797b6c6SAneesh Kumar K.V /* 1227c797b6c6SAneesh Kumar K.V * Now fix path in other fids, if the renamed path is part of 1228c797b6c6SAneesh Kumar K.V * that. 1229c797b6c6SAneesh Kumar K.V */ 1230e2341580SSasha Levin rename_fids(p9dev, old_name, new_name); 1231c797b6c6SAneesh Kumar K.V free(old_name); 1232c797b6c6SAneesh Kumar K.V free(new_name); 1233c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1234c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1235c797b6c6SAneesh Kumar K.V return; 1236c797b6c6SAneesh Kumar K.V err_out: 1237c797b6c6SAneesh Kumar K.V free(old_name); 1238c797b6c6SAneesh Kumar K.V free(new_name); 1239c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1240c797b6c6SAneesh Kumar K.V return; 1241c797b6c6SAneesh Kumar K.V } 1242c797b6c6SAneesh Kumar K.V 1243c797b6c6SAneesh Kumar K.V static void virtio_p9_unlinkat(struct p9_dev *p9dev, 1244c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1245c797b6c6SAneesh Kumar K.V { 1246c797b6c6SAneesh Kumar K.V int ret; 1247c797b6c6SAneesh Kumar K.V char *name; 1248c797b6c6SAneesh Kumar K.V u32 fid_val, flags; 1249c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 1250c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 1251c797b6c6SAneesh Kumar K.V 1252c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsd", &fid_val, &name, &flags); 125331a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 1254c797b6c6SAneesh Kumar K.V 125532832dd1SG. Campana ret = snprintf(full_path, sizeof(full_path), "%s/%s", fid->abs_path, name); 125632832dd1SG. Campana if (ret >= (int)sizeof(full_path)) { 125732832dd1SG. Campana errno = ENAMETOOLONG; 125832832dd1SG. Campana goto err_out; 125932832dd1SG. Campana } 126032832dd1SG. Campana 12619bb99a82SG. Campana if (path_is_illegal(full_path)) { 12629bb99a82SG. Campana errno = EACCES; 12639bb99a82SG. Campana goto err_out; 12649bb99a82SG. Campana } 12659bb99a82SG. Campana 1266c797b6c6SAneesh Kumar K.V ret = remove(full_path); 1267c797b6c6SAneesh Kumar K.V if (ret < 0) 1268c797b6c6SAneesh Kumar K.V goto err_out; 1269c797b6c6SAneesh Kumar K.V free(name); 1270c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1271c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1272c797b6c6SAneesh Kumar K.V return; 1273c797b6c6SAneesh Kumar K.V err_out: 1274c797b6c6SAneesh Kumar K.V free(name); 1275c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1276c797b6c6SAneesh Kumar K.V return; 1277c797b6c6SAneesh Kumar K.V } 1278c797b6c6SAneesh Kumar K.V 12795cc808aaSSasha Levin static void virtio_p9_flush(struct p9_dev *p9dev, 12805cc808aaSSasha Levin struct p9_pdu *pdu, u32 *outlen) 12815cc808aaSSasha Levin { 12825cc808aaSSasha Levin u16 tag, oldtag; 12835cc808aaSSasha Levin 12845cc808aaSSasha Levin virtio_p9_pdu_readf(pdu, "ww", &tag, &oldtag); 12855cc808aaSSasha Levin virtio_p9_pdu_writef(pdu, "w", tag); 12865cc808aaSSasha Levin *outlen = pdu->write_offset; 12875cc808aaSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 12885cc808aaSSasha Levin 12895cc808aaSSasha Levin return; 12905cc808aaSSasha Levin } 12915cc808aaSSasha Levin 1292c797b6c6SAneesh Kumar K.V static void virtio_p9_eopnotsupp(struct p9_dev *p9dev, 1293c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1294c797b6c6SAneesh Kumar K.V { 1295c797b6c6SAneesh Kumar K.V return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen); 1296c797b6c6SAneesh Kumar K.V } 1297c797b6c6SAneesh Kumar K.V 1298ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev, 1299af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen); 1300b4422bf3SAneesh Kumar K.V 1301c797b6c6SAneesh Kumar K.V /* FIXME should be removed when merging with latest linus tree */ 1302c797b6c6SAneesh Kumar K.V #define P9_TRENAMEAT 74 1303c797b6c6SAneesh Kumar K.V #define P9_TUNLINKAT 76 1304c797b6c6SAneesh Kumar K.V 1305c797b6c6SAneesh Kumar K.V static p9_handler *virtio_9p_dotl_handler [] = { 1306c797b6c6SAneesh Kumar K.V [P9_TREADDIR] = virtio_p9_readdir, 1307c797b6c6SAneesh Kumar K.V [P9_TSTATFS] = virtio_p9_statfs, 1308c797b6c6SAneesh Kumar K.V [P9_TGETATTR] = virtio_p9_getattr, 1309c797b6c6SAneesh Kumar K.V [P9_TSETATTR] = virtio_p9_setattr, 1310c797b6c6SAneesh Kumar K.V [P9_TXATTRWALK] = virtio_p9_eopnotsupp, 1311c797b6c6SAneesh Kumar K.V [P9_TXATTRCREATE] = virtio_p9_eopnotsupp, 1312c797b6c6SAneesh Kumar K.V [P9_TMKNOD] = virtio_p9_mknod, 1313c797b6c6SAneesh Kumar K.V [P9_TLOCK] = virtio_p9_lock, 1314c797b6c6SAneesh Kumar K.V [P9_TGETLOCK] = virtio_p9_getlock, 1315c797b6c6SAneesh Kumar K.V [P9_TRENAMEAT] = virtio_p9_renameat, 1316c797b6c6SAneesh Kumar K.V [P9_TREADLINK] = virtio_p9_readlink, 1317c797b6c6SAneesh Kumar K.V [P9_TUNLINKAT] = virtio_p9_unlinkat, 1318c797b6c6SAneesh Kumar K.V [P9_TMKDIR] = virtio_p9_mkdir, 1319b4422bf3SAneesh Kumar K.V [P9_TVERSION] = virtio_p9_version, 1320c797b6c6SAneesh Kumar K.V [P9_TLOPEN] = virtio_p9_open, 1321b4422bf3SAneesh Kumar K.V [P9_TATTACH] = virtio_p9_attach, 1322b4422bf3SAneesh Kumar K.V [P9_TWALK] = virtio_p9_walk, 1323c797b6c6SAneesh Kumar K.V [P9_TCLUNK] = virtio_p9_clunk, 1324c797b6c6SAneesh Kumar K.V [P9_TFSYNC] = virtio_p9_fsync, 1325b4422bf3SAneesh Kumar K.V [P9_TREAD] = virtio_p9_read, 13265cc808aaSSasha Levin [P9_TFLUSH] = virtio_p9_flush, 1327c797b6c6SAneesh Kumar K.V [P9_TLINK] = virtio_p9_link, 1328c797b6c6SAneesh Kumar K.V [P9_TSYMLINK] = virtio_p9_symlink, 1329c797b6c6SAneesh Kumar K.V [P9_TLCREATE] = virtio_p9_create, 1330b4422bf3SAneesh Kumar K.V [P9_TWRITE] = virtio_p9_write, 13316fc5cd9bSSasha Levin [P9_TREMOVE] = virtio_p9_remove, 1332f161f28bSSasha Levin [P9_TRENAME] = virtio_p9_rename, 1333b4422bf3SAneesh Kumar K.V }; 1334b4422bf3SAneesh Kumar K.V 1335af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq) 1336af045e53SAneesh Kumar K.V { 1337af045e53SAneesh Kumar K.V struct p9_pdu *pdu = calloc(1, sizeof(*pdu)); 1338af045e53SAneesh Kumar K.V if (!pdu) 1339af045e53SAneesh Kumar K.V return NULL; 1340af045e53SAneesh Kumar K.V 1341bfc15268SAneesh Kumar K.V /* skip the pdu header p9_msg */ 13425529bcd7SAsias He pdu->read_offset = VIRTIO_9P_HDR_LEN; 13435529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 1344af045e53SAneesh Kumar K.V pdu->queue_head = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov, 1345a8a44649SAsias He pdu->out_iov, &pdu->in_iov_cnt, &pdu->out_iov_cnt); 1346af045e53SAneesh Kumar K.V return pdu; 1347af045e53SAneesh Kumar K.V } 1348af045e53SAneesh Kumar K.V 1349af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu) 1350af045e53SAneesh Kumar K.V { 1351af045e53SAneesh Kumar K.V struct p9_msg *msg; 1352af045e53SAneesh Kumar K.V /* 1353af045e53SAneesh Kumar K.V * we can peek directly into pdu for a u8 1354af045e53SAneesh Kumar K.V * value. The host endianess won't be an issue 1355af045e53SAneesh Kumar K.V */ 1356af045e53SAneesh Kumar K.V msg = pdu->out_iov[0].iov_base; 1357af045e53SAneesh Kumar K.V return msg->cmd; 1358af045e53SAneesh Kumar K.V } 1359af045e53SAneesh Kumar K.V 1360b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job) 13611c7850f9SSasha Levin { 1362af045e53SAneesh Kumar K.V u8 cmd; 1363b4422bf3SAneesh Kumar K.V u32 len = 0; 1364b4422bf3SAneesh Kumar K.V p9_handler *handler; 1365b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 1366af045e53SAneesh Kumar K.V struct virt_queue *vq; 1367af045e53SAneesh Kumar K.V struct p9_pdu *p9pdu; 13681c7850f9SSasha Levin 1369b4422bf3SAneesh Kumar K.V vq = job->vq; 1370b4422bf3SAneesh Kumar K.V p9dev = job->p9dev; 13711c7850f9SSasha Levin 1372af045e53SAneesh Kumar K.V p9pdu = virtio_p9_pdu_init(kvm, vq); 1373af045e53SAneesh Kumar K.V cmd = virtio_p9_get_cmd(p9pdu); 1374af045e53SAneesh Kumar K.V 1375c797b6c6SAneesh Kumar K.V if ((cmd >= ARRAY_SIZE(virtio_9p_dotl_handler)) || 1376c797b6c6SAneesh Kumar K.V !virtio_9p_dotl_handler[cmd]) 137797b408afSAneesh Kumar K.V handler = virtio_p9_eopnotsupp; 1378dd78d9eaSAneesh Kumar K.V else 1379c797b6c6SAneesh Kumar K.V handler = virtio_9p_dotl_handler[cmd]; 1380c797b6c6SAneesh Kumar K.V 1381af045e53SAneesh Kumar K.V handler(p9dev, p9pdu, &len); 1382af045e53SAneesh Kumar K.V virt_queue__set_used_elem(vq, p9pdu->queue_head, len); 1383af045e53SAneesh Kumar K.V free(p9pdu); 13841c7850f9SSasha Levin return true; 13851c7850f9SSasha Levin } 13861c7850f9SSasha Levin 13871c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param) 13881c7850f9SSasha Levin { 1389b4422bf3SAneesh Kumar K.V struct p9_dev_job *job = (struct p9_dev_job *)param; 1390b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = job->p9dev; 1391b4422bf3SAneesh Kumar K.V struct virt_queue *vq = job->vq; 13921c7850f9SSasha Levin 13931c7850f9SSasha Levin while (virt_queue__available(vq)) { 1394b4422bf3SAneesh Kumar K.V virtio_p9_do_io_request(kvm, job); 139502eca50cSAsias He p9dev->vdev.ops->signal_vq(kvm, &p9dev->vdev, vq - p9dev->vqs); 13961c7850f9SSasha Levin } 13971c7850f9SSasha Levin } 13981c7850f9SSasha Levin 1399c5ae742bSSasha Levin static u8 *get_config(struct kvm *kvm, void *dev) 14001c7850f9SSasha Levin { 1401c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 14021c7850f9SSasha Levin 1403c5ae742bSSasha Levin return ((u8 *)(p9dev->config)); 1404c7838fbdSSasha Levin } 1405c7838fbdSSasha Levin 1406c7838fbdSSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev) 1407c7838fbdSSasha Levin { 1408c7838fbdSSasha Levin return 1 << VIRTIO_9P_MOUNT_TAG; 1409c7838fbdSSasha Levin } 1410c7838fbdSSasha Levin 1411c7838fbdSSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features) 1412c7838fbdSSasha Levin { 1413c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1414e0ea1859SMarc Zyngier struct virtio_9p_config *conf = p9dev->config; 1415c7838fbdSSasha Levin 1416c7838fbdSSasha Levin p9dev->features = features; 1417e0ea1859SMarc Zyngier conf->tag_len = virtio_host_to_guest_u16(&p9dev->vdev, conf->tag_len); 1418c7838fbdSSasha Levin } 1419c7838fbdSSasha Levin 1420c59ba304SWill Deacon static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align, 1421c59ba304SWill Deacon u32 pfn) 1422c7838fbdSSasha Levin { 1423c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1424b4422bf3SAneesh Kumar K.V struct p9_dev_job *job; 1425b4422bf3SAneesh Kumar K.V struct virt_queue *queue; 1426c7838fbdSSasha Levin void *p; 14271c7850f9SSasha Levin 1428312c62d1SSasha Levin compat__remove_message(compat_id); 1429e59662b3SSasha Levin 1430c7838fbdSSasha Levin queue = &p9dev->vqs[vq]; 1431c7838fbdSSasha Levin queue->pfn = pfn; 1432e7e2950aSSasha Levin p = virtio_get_vq(kvm, queue->pfn, page_size); 1433c7838fbdSSasha Levin job = &p9dev->jobs[vq]; 14341c7850f9SSasha Levin 1435c59ba304SWill Deacon vring_init(&queue->vring, VIRTQUEUE_NUM, p, align); 1436e0ea1859SMarc Zyngier virtio_init_device_vq(&p9dev->vdev, queue); 14371c7850f9SSasha Levin 1438b4422bf3SAneesh Kumar K.V *job = (struct p9_dev_job) { 1439b4422bf3SAneesh Kumar K.V .vq = queue, 1440b4422bf3SAneesh Kumar K.V .p9dev = p9dev, 1441b4422bf3SAneesh Kumar K.V }; 1442df0c7f57SSasha Levin thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job); 144360eb42d5SSasha Levin 1444c7838fbdSSasha Levin return 0; 14451c7850f9SSasha Levin } 14461c7850f9SSasha Levin 1447c7838fbdSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 1448c7838fbdSSasha Levin { 1449c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 14501c7850f9SSasha Levin 1451c7838fbdSSasha Levin thread_pool__do_job(&p9dev->jobs[vq].job_id); 1452c7838fbdSSasha Levin 1453c7838fbdSSasha Levin return 0; 1454c7838fbdSSasha Levin } 1455c7838fbdSSasha Levin 1456c7838fbdSSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq) 1457c7838fbdSSasha Levin { 1458c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1459c7838fbdSSasha Levin 1460c7838fbdSSasha Levin return p9dev->vqs[vq].pfn; 1461c7838fbdSSasha Levin } 1462c7838fbdSSasha Levin 1463c7838fbdSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 1464c7838fbdSSasha Levin { 1465c7838fbdSSasha Levin return VIRTQUEUE_NUM; 1466c7838fbdSSasha Levin } 1467c7838fbdSSasha Levin 14687aba29c1SWill Deacon static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size) 14697aba29c1SWill Deacon { 14707aba29c1SWill Deacon /* FIXME: dynamic */ 14717aba29c1SWill Deacon return size; 14727aba29c1SWill Deacon } 14737aba29c1SWill Deacon 147415542babSAndre Przywara struct virtio_ops p9_dev_virtio_ops = { 1475c7838fbdSSasha Levin .get_config = get_config, 1476c7838fbdSSasha Levin .get_host_features = get_host_features, 1477c7838fbdSSasha Levin .set_guest_features = set_guest_features, 1478c7838fbdSSasha Levin .init_vq = init_vq, 1479c7838fbdSSasha Levin .notify_vq = notify_vq, 1480c7838fbdSSasha Levin .get_pfn_vq = get_pfn_vq, 1481c7838fbdSSasha Levin .get_size_vq = get_size_vq, 14827aba29c1SWill Deacon .set_size_vq = set_size_vq, 1483c7838fbdSSasha Levin }; 14841c47ce69SSasha Levin 1485cac9e8fdSSasha Levin int virtio_9p_rootdir_parser(const struct option *opt, const char *arg, int unset) 1486cac9e8fdSSasha Levin { 1487cac9e8fdSSasha Levin char *tag_name; 1488cac9e8fdSSasha Levin char tmp[PATH_MAX]; 1489cac9e8fdSSasha Levin struct kvm *kvm = opt->ptr; 1490cac9e8fdSSasha Levin 1491cac9e8fdSSasha Levin /* 1492cac9e8fdSSasha Levin * 9p dir can be of the form dirname,tag_name or 1493cac9e8fdSSasha Levin * just dirname. In the later case we use the 1494cac9e8fdSSasha Levin * default tag name 1495cac9e8fdSSasha Levin */ 1496cac9e8fdSSasha Levin tag_name = strstr(arg, ","); 1497cac9e8fdSSasha Levin if (tag_name) { 1498cac9e8fdSSasha Levin *tag_name = '\0'; 1499cac9e8fdSSasha Levin tag_name++; 1500cac9e8fdSSasha Levin } 1501cac9e8fdSSasha Levin if (realpath(arg, tmp)) { 1502cac9e8fdSSasha Levin if (virtio_9p__register(kvm, tmp, tag_name) < 0) 1503cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1504cac9e8fdSSasha Levin } else 1505cac9e8fdSSasha Levin die("Failed resolving 9p path"); 1506cac9e8fdSSasha Levin return 0; 1507cac9e8fdSSasha Levin } 1508cac9e8fdSSasha Levin 1509cac9e8fdSSasha Levin int virtio_9p_img_name_parser(const struct option *opt, const char *arg, int unset) 1510cac9e8fdSSasha Levin { 1511cac9e8fdSSasha Levin char path[PATH_MAX]; 1512cac9e8fdSSasha Levin struct stat st; 1513cac9e8fdSSasha Levin struct kvm *kvm = opt->ptr; 1514cac9e8fdSSasha Levin 1515cac9e8fdSSasha Levin if (stat(arg, &st) == 0 && 1516cac9e8fdSSasha Levin S_ISDIR(st.st_mode)) { 1517cac9e8fdSSasha Levin char tmp[PATH_MAX]; 1518cac9e8fdSSasha Levin 1519cac9e8fdSSasha Levin if (kvm->cfg.using_rootfs) 1520cac9e8fdSSasha Levin die("Please use only one rootfs directory atmost"); 1521cac9e8fdSSasha Levin 1522cac9e8fdSSasha Levin if (realpath(arg, tmp) == 0 || 1523cac9e8fdSSasha Levin virtio_9p__register(kvm, tmp, "/dev/root") < 0) 1524cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1525cac9e8fdSSasha Levin kvm->cfg.using_rootfs = 1; 1526cac9e8fdSSasha Levin return 0; 1527cac9e8fdSSasha Levin } 1528cac9e8fdSSasha Levin 1529cac9e8fdSSasha Levin snprintf(path, PATH_MAX, "%s%s", kvm__get_dir(), arg); 1530cac9e8fdSSasha Levin 1531cac9e8fdSSasha Levin if (stat(path, &st) == 0 && 1532cac9e8fdSSasha Levin S_ISDIR(st.st_mode)) { 1533cac9e8fdSSasha Levin char tmp[PATH_MAX]; 1534cac9e8fdSSasha Levin 1535cac9e8fdSSasha Levin if (kvm->cfg.using_rootfs) 1536cac9e8fdSSasha Levin die("Please use only one rootfs directory atmost"); 1537cac9e8fdSSasha Levin 1538cac9e8fdSSasha Levin if (realpath(path, tmp) == 0 || 1539cac9e8fdSSasha Levin virtio_9p__register(kvm, tmp, "/dev/root") < 0) 1540cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1541cac9e8fdSSasha Levin if (virtio_9p__register(kvm, "/", "hostfs") < 0) 1542cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1543cac9e8fdSSasha Levin kvm_setup_resolv(arg); 1544cac9e8fdSSasha Levin kvm->cfg.using_rootfs = kvm->cfg.custom_rootfs = 1; 1545cac9e8fdSSasha Levin kvm->cfg.custom_rootfs_name = arg; 1546cac9e8fdSSasha Levin return 0; 1547cac9e8fdSSasha Levin } 1548cac9e8fdSSasha Levin 1549cac9e8fdSSasha Levin return -1; 1550cac9e8fdSSasha Levin } 1551cac9e8fdSSasha Levin 15521c47ce69SSasha Levin int virtio_9p__init(struct kvm *kvm) 15531c47ce69SSasha Levin { 15541c47ce69SSasha Levin struct p9_dev *p9dev; 15551c47ce69SSasha Levin 15561c47ce69SSasha Levin list_for_each_entry(p9dev, &devs, list) { 155702eca50cSAsias He virtio_init(kvm, p9dev, &p9dev->vdev, &p9_dev_virtio_ops, 1558d97dadecSWill Deacon VIRTIO_DEFAULT_TRANS(kvm), PCI_DEVICE_ID_VIRTIO_9P, 1559ae06ce71SWill Deacon VIRTIO_ID_9P, PCI_CLASS_9P); 1560c7838fbdSSasha Levin } 1561c7838fbdSSasha Levin 1562c7838fbdSSasha Levin return 0; 1563c7838fbdSSasha Levin } 156449a8afd1SSasha Levin virtio_dev_init(virtio_9p__init); 1565c7838fbdSSasha Levin 1566c7838fbdSSasha Levin int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name) 1567c7838fbdSSasha Levin { 1568c7838fbdSSasha Levin struct p9_dev *p9dev; 156954f6802dSPekka Enberg int err = 0; 15701c7850f9SSasha Levin 1571b4422bf3SAneesh Kumar K.V p9dev = calloc(1, sizeof(*p9dev)); 1572b4422bf3SAneesh Kumar K.V if (!p9dev) 157354f6802dSPekka Enberg return -ENOMEM; 157454f6802dSPekka Enberg 1575b4422bf3SAneesh Kumar K.V if (!tag_name) 15765529bcd7SAsias He tag_name = VIRTIO_9P_DEFAULT_TAG; 157754f6802dSPekka Enberg 1578b4422bf3SAneesh Kumar K.V p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1); 157954f6802dSPekka Enberg if (p9dev->config == NULL) { 158054f6802dSPekka Enberg err = -ENOMEM; 1581b4422bf3SAneesh Kumar K.V goto free_p9dev; 158254f6802dSPekka Enberg } 15831c7850f9SSasha Levin 1584*e277a1b4SG. Campana strncpy(p9dev->root_dir, root, sizeof(p9dev->root_dir)); 1585*e277a1b4SG. Campana p9dev->root_dir[sizeof(p9dev->root_dir)-1] = '\x00'; 1586*e277a1b4SG. Campana 1587b4422bf3SAneesh Kumar K.V p9dev->config->tag_len = strlen(tag_name); 158854f6802dSPekka Enberg if (p9dev->config->tag_len > MAX_TAG_LEN) { 158954f6802dSPekka Enberg err = -EINVAL; 1590b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 159154f6802dSPekka Enberg } 15921c7850f9SSasha Levin 1593c7838fbdSSasha Levin memcpy(&p9dev->config->tag, tag_name, strlen(tag_name)); 15941c7850f9SSasha Levin 1595c7838fbdSSasha Levin list_add(&p9dev->list, &devs); 1596b4422bf3SAneesh Kumar K.V 1597d278197dSAsias He if (compat_id == -1) 159852f34d2cSAsias He compat_id = virtio_compat_add_message("virtio-9p", "CONFIG_NET_9P_VIRTIO"); 1599e59662b3SSasha Levin 160054f6802dSPekka Enberg return err; 160154f6802dSPekka Enberg 1602b4422bf3SAneesh Kumar K.V free_p9dev_config: 1603b4422bf3SAneesh Kumar K.V free(p9dev->config); 1604b4422bf3SAneesh Kumar K.V free_p9dev: 1605b4422bf3SAneesh Kumar K.V free(p9dev); 160654f6802dSPekka Enberg return err; 16071c7850f9SSasha Levin } 1608