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; 31e2341580SSasha Levin 32e2341580SSasha Levin while (node) { 33e2341580SSasha Levin struct p9_fid *cur = rb_entry(node, struct p9_fid, node); 34e2341580SSasha Levin 35e2341580SSasha Levin if (fid < cur->fid) { 36e2341580SSasha Levin node = node->rb_left; 37e2341580SSasha Levin } else if (fid > cur->fid) { 38e2341580SSasha Levin node = node->rb_right; 39e2341580SSasha Levin } else { 40e2341580SSasha Levin return cur; 41e2341580SSasha Levin } 42e2341580SSasha Levin } 43e2341580SSasha Levin 44e2341580SSasha Levin pfid = calloc(sizeof(*pfid), 1); 45e2341580SSasha Levin if (!pfid) 46e2341580SSasha Levin return NULL; 47e2341580SSasha Levin 48e2341580SSasha Levin pfid->fid = fid; 49e2341580SSasha Levin strcpy(pfid->abs_path, dev->root_dir); 50e2341580SSasha Levin pfid->path = pfid->abs_path + strlen(dev->root_dir); 51e2341580SSasha Levin 52e2341580SSasha Levin insert_new_fid(dev, pfid); 53e2341580SSasha Levin 54e2341580SSasha Levin return pfid; 55e2341580SSasha Levin } 56e2341580SSasha Levin 57e2341580SSasha Levin static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid) 58e2341580SSasha Levin { 59e2341580SSasha Levin struct rb_node **node = &(dev->fids.rb_node), *parent = NULL; 60e2341580SSasha Levin 61e2341580SSasha Levin while (*node) { 62e2341580SSasha Levin int result = fid->fid - rb_entry(*node, struct p9_fid, node)->fid; 63e2341580SSasha Levin 64e2341580SSasha Levin parent = *node; 65e2341580SSasha Levin if (result < 0) 66e2341580SSasha Levin node = &((*node)->rb_left); 67e2341580SSasha Levin else if (result > 0) 68e2341580SSasha Levin node = &((*node)->rb_right); 69e2341580SSasha Levin else 70e2341580SSasha Levin return -EEXIST; 71e2341580SSasha Levin } 72e2341580SSasha Levin 73e2341580SSasha Levin rb_link_node(&fid->node, parent, node); 74e2341580SSasha Levin rb_insert_color(&fid->node, &dev->fids); 75e2341580SSasha Levin return 0; 76e2341580SSasha Levin } 77e2341580SSasha Levin 7831a6fb8dSSasha Levin static struct p9_fid *get_fid(struct p9_dev *p9dev, int fid) 7931a6fb8dSSasha Levin { 80e2341580SSasha Levin struct p9_fid *new; 8131a6fb8dSSasha Levin 82e2341580SSasha Levin new = find_or_create_fid(p9dev, fid); 83e2341580SSasha Levin 84e2341580SSasha Levin return new; 8531a6fb8dSSasha Levin } 8631a6fb8dSSasha Levin 871c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */ 88b4422bf3SAneesh Kumar K.V static const char *rel_to_abs(struct p9_dev *p9dev, 89b4422bf3SAneesh Kumar K.V const char *path, char *abs_path) 901c7850f9SSasha Levin { 91b4422bf3SAneesh Kumar K.V sprintf(abs_path, "%s/%s", p9dev->root_dir, path); 921c7850f9SSasha Levin 931c7850f9SSasha Levin return abs_path; 941c7850f9SSasha Levin } 951c7850f9SSasha Levin 96c797b6c6SAneesh Kumar K.V static void stat2qid(struct stat *st, struct p9_qid *qid) 971c7850f9SSasha Levin { 981c7850f9SSasha Levin *qid = (struct p9_qid) { 991c7850f9SSasha Levin .path = st->st_ino, 1001c7850f9SSasha Levin .version = st->st_mtime, 1011c7850f9SSasha Levin }; 1021c7850f9SSasha Levin 1031c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) 1041c7850f9SSasha Levin qid->type |= P9_QTDIR; 1051c7850f9SSasha Levin } 1061c7850f9SSasha Levin 107b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid) 1081c7850f9SSasha Levin { 109e2341580SSasha Levin struct p9_fid *pfid = get_fid(p9dev, fid); 110e2341580SSasha Levin 111e2341580SSasha Levin if (pfid->fd > 0) 112e2341580SSasha Levin close(pfid->fd); 113e2341580SSasha Levin 114e2341580SSasha Levin if (pfid->dir) 115e2341580SSasha Levin closedir(pfid->dir); 116e2341580SSasha Levin 117e2341580SSasha Levin rb_erase(&pfid->node, &p9dev->fids); 118e2341580SSasha Levin free(pfid); 1191c7850f9SSasha Levin } 120e2341580SSasha Levin 121bfc15268SAneesh Kumar K.V static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size) 1221c7850f9SSasha Levin { 123bfc15268SAneesh Kumar K.V u8 cmd; 124bfc15268SAneesh Kumar K.V u16 tag; 125bfc15268SAneesh Kumar K.V 126bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32); 127bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag); 128bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 129bfc15268SAneesh Kumar K.V /* cmd + 1 is the reply message */ 130bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag); 1311c7850f9SSasha Levin } 1321c7850f9SSasha Levin 1336b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt) 1346b163a87SAneesh Kumar K.V { 1356b163a87SAneesh Kumar K.V int i; 1366b163a87SAneesh Kumar K.V u32 total = 0; 1376b163a87SAneesh Kumar K.V for (i = 0; (i < iov_cnt) && (total < count); i++) { 1386b163a87SAneesh Kumar K.V if (total + iov[i].iov_len > count) { 1396b163a87SAneesh Kumar K.V /* we don't need this iov fully */ 1406b163a87SAneesh Kumar K.V iov[i].iov_len -= ((total + iov[i].iov_len) - count); 1416b163a87SAneesh Kumar K.V i++; 1426b163a87SAneesh Kumar K.V break; 1436b163a87SAneesh Kumar K.V } 1446b163a87SAneesh Kumar K.V total += iov[i].iov_len; 1456b163a87SAneesh Kumar K.V } 1466b163a87SAneesh Kumar K.V return i; 1476b163a87SAneesh Kumar K.V } 1486b163a87SAneesh Kumar K.V 149eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev, 150eee1ba8eSAneesh Kumar K.V struct p9_pdu *pdu, int err, u32 *outlen) 151eee1ba8eSAneesh Kumar K.V { 152bfc15268SAneesh Kumar K.V u16 tag; 153eee1ba8eSAneesh Kumar K.V 1549c2e1d1aSSuzuki K. Poulose /* EMFILE at server implies ENFILE for the VM */ 1559c2e1d1aSSuzuki K. Poulose if (err == EMFILE) 1569c2e1d1aSSuzuki K. Poulose err = ENFILE; 1579c2e1d1aSSuzuki K. Poulose 1585529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 159c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", err); 160bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 161eee1ba8eSAneesh Kumar K.V 162c797b6c6SAneesh Kumar K.V /* read the tag from input */ 163bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32) + sizeof(u8); 164bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "w", &tag); 165bfc15268SAneesh Kumar K.V 166c797b6c6SAneesh Kumar K.V /* Update the header */ 167bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 168c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RLERROR, tag); 169eee1ba8eSAneesh Kumar K.V } 170eee1ba8eSAneesh Kumar K.V 171ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev, 172af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1731c7850f9SSasha Levin { 174c797b6c6SAneesh Kumar K.V u32 msize; 175c797b6c6SAneesh Kumar K.V char *version; 176c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ds", &msize, &version); 177c797b6c6SAneesh Kumar K.V /* 178c797b6c6SAneesh Kumar K.V * reply with the same msize the client sent us 179c797b6c6SAneesh Kumar K.V * Error out if the request is not for 9P2000.L 180c797b6c6SAneesh Kumar K.V */ 1815529bcd7SAsias He if (!strcmp(version, VIRTIO_9P_VERSION_DOTL)) 182c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, version); 183c797b6c6SAneesh Kumar K.V else 184c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, "unknown"); 1851c7850f9SSasha Levin 186bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 187bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 188c797b6c6SAneesh Kumar K.V free(version); 189ead43b01SAneesh Kumar K.V return; 1901c7850f9SSasha Levin } 1911c7850f9SSasha Levin 192ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev, 193af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1941c7850f9SSasha Levin { 195bfc15268SAneesh Kumar K.V u32 fid; 1961c7850f9SSasha Levin 197bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid); 198bfc15268SAneesh Kumar K.V close_fid(p9dev, fid); 1991c7850f9SSasha Levin 200bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 201bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 202ead43b01SAneesh Kumar K.V return; 2031c7850f9SSasha Levin } 2041c7850f9SSasha Levin 205c797b6c6SAneesh Kumar K.V /* 206c797b6c6SAneesh Kumar K.V * FIXME!! Need to map to protocol independent value. Upstream 207c797b6c6SAneesh Kumar K.V * 9p also have the same BUG 208c797b6c6SAneesh Kumar K.V */ 209c797b6c6SAneesh Kumar K.V static int virtio_p9_openflags(int flags) 210c797b6c6SAneesh Kumar K.V { 211c797b6c6SAneesh Kumar K.V flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT | O_DIRECT); 212c797b6c6SAneesh Kumar K.V flags |= O_NOFOLLOW; 213c797b6c6SAneesh Kumar K.V return flags; 214c797b6c6SAneesh Kumar K.V } 215c797b6c6SAneesh Kumar K.V 21632585666SSasha Levin static bool is_dir(struct p9_fid *fid) 21732585666SSasha Levin { 21832585666SSasha Levin struct stat st; 21932585666SSasha Levin 22032585666SSasha Levin stat(fid->abs_path, &st); 22132585666SSasha Levin 22232585666SSasha Levin return S_ISDIR(st.st_mode); 22332585666SSasha Levin } 22432585666SSasha Levin 225*9bb99a82SG. Campana /* path is always absolute */ 226*9bb99a82SG. Campana static bool path_is_illegal(const char *path) 227*9bb99a82SG. Campana { 228*9bb99a82SG. Campana size_t len; 229*9bb99a82SG. Campana 230*9bb99a82SG. Campana if (strstr(path, "/../") != NULL) 231*9bb99a82SG. Campana return true; 232*9bb99a82SG. Campana 233*9bb99a82SG. Campana len = strlen(path); 234*9bb99a82SG. Campana if (len >= 3 && strcmp(path + len - 3, "/..") == 0) 235*9bb99a82SG. Campana return true; 236*9bb99a82SG. Campana 237*9bb99a82SG. Campana return false; 238*9bb99a82SG. Campana } 239*9bb99a82SG. Campana 240ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev, 241af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2421c7850f9SSasha Levin { 243c797b6c6SAneesh Kumar K.V u32 fid, flags; 2441c7850f9SSasha Levin struct stat st; 245bfc15268SAneesh Kumar K.V struct p9_qid qid; 246bfc15268SAneesh Kumar K.V struct p9_fid *new_fid; 247bfc15268SAneesh Kumar K.V 248c797b6c6SAneesh Kumar K.V 249c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid, &flags); 25031a6fb8dSSasha Levin new_fid = get_fid(p9dev, fid); 2511c7850f9SSasha Levin 25230204a77SAneesh Kumar K.V if (lstat(new_fid->abs_path, &st) < 0) 253eee1ba8eSAneesh Kumar K.V goto err_out; 2541c7850f9SSasha Levin 255c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 2561c7850f9SSasha Levin 25732585666SSasha Levin if (is_dir(new_fid)) { 2581c7850f9SSasha Levin new_fid->dir = opendir(new_fid->abs_path); 259eee1ba8eSAneesh Kumar K.V if (!new_fid->dir) 260eee1ba8eSAneesh Kumar K.V goto err_out; 261eee1ba8eSAneesh Kumar K.V } else { 262eee1ba8eSAneesh Kumar K.V new_fid->fd = open(new_fid->abs_path, 263c797b6c6SAneesh Kumar K.V virtio_p9_openflags(flags)); 264eee1ba8eSAneesh Kumar K.V if (new_fid->fd < 0) 265eee1ba8eSAneesh Kumar K.V goto err_out; 266eee1ba8eSAneesh Kumar K.V } 267c797b6c6SAneesh Kumar K.V /* FIXME!! need ot send proper iounit */ 268bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 269bfc15268SAneesh Kumar K.V 270bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 271bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 272ead43b01SAneesh Kumar K.V return; 273eee1ba8eSAneesh Kumar K.V err_out: 274eee1ba8eSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 275ead43b01SAneesh Kumar K.V return; 2761c7850f9SSasha Levin } 2771c7850f9SSasha Levin 278ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev, 279af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2801c7850f9SSasha Levin { 281c797b6c6SAneesh Kumar K.V int fd, ret; 282bfc15268SAneesh Kumar K.V char *name; 283af045e53SAneesh Kumar K.V struct stat st; 284bfc15268SAneesh Kumar K.V struct p9_qid qid; 285c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 2864bc9734aSAneesh Kumar K.V char full_path[PATH_MAX]; 287c797b6c6SAneesh Kumar K.V u32 dfid_val, flags, mode, gid; 288af045e53SAneesh Kumar K.V 289c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsddd", &dfid_val, 290c797b6c6SAneesh Kumar K.V &name, &flags, &mode, &gid); 29131a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 2921c7850f9SSasha Levin 293c797b6c6SAneesh Kumar K.V flags = virtio_p9_openflags(flags); 2945f900f6dSSasha Levin 295c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 296*9bb99a82SG. Campana if (path_is_illegal(full_path)) { 297*9bb99a82SG. Campana errno = EACCES; 298*9bb99a82SG. Campana goto err_out; 299*9bb99a82SG. Campana } 300*9bb99a82SG. Campana 301c797b6c6SAneesh Kumar K.V fd = open(full_path, flags | O_CREAT, mode); 3024bc9734aSAneesh Kumar K.V if (fd < 0) 3034bc9734aSAneesh Kumar K.V goto err_out; 304c797b6c6SAneesh Kumar K.V dfid->fd = fd; 305c797b6c6SAneesh Kumar K.V 3064bc9734aSAneesh Kumar K.V if (lstat(full_path, &st) < 0) 3076c8ca053SAneesh Kumar K.V goto err_out; 3081c7850f9SSasha Levin 309c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 310c797b6c6SAneesh Kumar K.V if (ret < 0) 311c797b6c6SAneesh Kumar K.V goto err_out; 312c797b6c6SAneesh Kumar K.V 313c797b6c6SAneesh Kumar K.V sprintf(dfid->path, "%s/%s", dfid->path, name); 314c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 315bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 316bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 317bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 3185f900f6dSSasha Levin free(name); 3196c8ca053SAneesh Kumar K.V return; 3206c8ca053SAneesh Kumar K.V err_out: 3215f900f6dSSasha Levin free(name); 322c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 323c797b6c6SAneesh Kumar K.V return; 324c797b6c6SAneesh Kumar K.V } 325c797b6c6SAneesh Kumar K.V 326c797b6c6SAneesh Kumar K.V static void virtio_p9_mkdir(struct p9_dev *p9dev, 327c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 328c797b6c6SAneesh Kumar K.V { 329c797b6c6SAneesh Kumar K.V int ret; 330c797b6c6SAneesh Kumar K.V char *name; 331c797b6c6SAneesh Kumar K.V struct stat st; 332c797b6c6SAneesh Kumar K.V struct p9_qid qid; 333c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 334c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 335c797b6c6SAneesh Kumar K.V u32 dfid_val, mode, gid; 336c797b6c6SAneesh Kumar K.V 337c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdd", &dfid_val, 338c797b6c6SAneesh Kumar K.V &name, &mode, &gid); 33931a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 340c797b6c6SAneesh Kumar K.V 341c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 342*9bb99a82SG. Campana if (path_is_illegal(full_path)) { 343*9bb99a82SG. Campana errno = EACCES; 344*9bb99a82SG. Campana goto err_out; 345*9bb99a82SG. Campana } 346*9bb99a82SG. Campana 347c797b6c6SAneesh Kumar K.V ret = mkdir(full_path, mode); 348c797b6c6SAneesh Kumar K.V if (ret < 0) 349c797b6c6SAneesh Kumar K.V goto err_out; 350c797b6c6SAneesh Kumar K.V 351c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0) 352c797b6c6SAneesh Kumar K.V goto err_out; 353c797b6c6SAneesh Kumar K.V 354c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 355c797b6c6SAneesh Kumar K.V if (ret < 0) 356c797b6c6SAneesh Kumar K.V goto err_out; 357c797b6c6SAneesh Kumar K.V 358c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 359c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 360c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 361c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 362c797b6c6SAneesh Kumar K.V free(name); 363c797b6c6SAneesh Kumar K.V return; 364c797b6c6SAneesh Kumar K.V err_out: 365c797b6c6SAneesh Kumar K.V free(name); 366c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 367ead43b01SAneesh Kumar K.V return; 3681c7850f9SSasha Levin } 3691c7850f9SSasha Levin 370ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev, 371af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 3721c7850f9SSasha Levin { 373af045e53SAneesh Kumar K.V u8 i; 374bfc15268SAneesh Kumar K.V u16 nwqid; 375bfc15268SAneesh Kumar K.V u16 nwname; 376bfc15268SAneesh Kumar K.V struct p9_qid wqid; 377e2341580SSasha Levin struct p9_fid *new_fid, *old_fid; 378c797b6c6SAneesh Kumar K.V u32 fid_val, newfid_val; 379c797b6c6SAneesh Kumar K.V 3801c7850f9SSasha Levin 381bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname); 38231a6fb8dSSasha Levin new_fid = get_fid(p9dev, newfid_val); 3831c7850f9SSasha Levin 384bfc15268SAneesh Kumar K.V nwqid = 0; 385bfc15268SAneesh Kumar K.V if (nwname) { 38631a6fb8dSSasha Levin struct p9_fid *fid = get_fid(p9dev, fid_val); 387bfc15268SAneesh Kumar K.V 388baac79a5SAneesh Kumar K.V strcpy(new_fid->path, fid->path); 389bfc15268SAneesh Kumar K.V /* skip the space for count */ 390bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 391bfc15268SAneesh Kumar K.V for (i = 0; i < nwname; i++) { 392bfc15268SAneesh Kumar K.V struct stat st; 3931c7850f9SSasha Levin char tmp[PATH_MAX] = {0}; 3941c7850f9SSasha Levin char full_path[PATH_MAX]; 395e55ed135SPekka Enberg char *str; 396bfc15268SAneesh Kumar K.V 397bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "s", &str); 3981c7850f9SSasha Levin 3991c7850f9SSasha Levin /* Format the new path we're 'walk'ing into */ 400baac79a5SAneesh Kumar K.V sprintf(tmp, "%s/%s", new_fid->path, str); 401e55ed135SPekka Enberg 402e55ed135SPekka Enberg free(str); 403e55ed135SPekka Enberg 404c797b6c6SAneesh Kumar K.V if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0) 4056c8ca053SAneesh Kumar K.V goto err_out; 4061c7850f9SSasha Levin 407c797b6c6SAneesh Kumar K.V stat2qid(&st, &wqid); 4081c7850f9SSasha Levin strcpy(new_fid->path, tmp); 409c797b6c6SAneesh Kumar K.V new_fid->uid = fid->uid; 410bfc15268SAneesh Kumar K.V nwqid++; 411bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &wqid); 4121c7850f9SSasha Levin } 4131c7850f9SSasha Levin } else { 414bfc15268SAneesh Kumar K.V /* 415bfc15268SAneesh Kumar K.V * update write_offset so our outlen get correct value 416bfc15268SAneesh Kumar K.V */ 417bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 418e2341580SSasha Levin old_fid = get_fid(p9dev, fid_val); 419e2341580SSasha Levin strcpy(new_fid->path, old_fid->path); 420e2341580SSasha Levin new_fid->uid = old_fid->uid; 4211c7850f9SSasha Levin } 422bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 4235529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 424bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", nwqid); 425bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 4266c8ca053SAneesh Kumar K.V return; 4276c8ca053SAneesh Kumar K.V err_out: 4286c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 429ead43b01SAneesh Kumar K.V return; 4301c7850f9SSasha Levin } 4311c7850f9SSasha Levin 432ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev, 433af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4341c7850f9SSasha Levin { 435bfc15268SAneesh Kumar K.V char *uname; 436bfc15268SAneesh Kumar K.V char *aname; 4371c7850f9SSasha Levin struct stat st; 438bfc15268SAneesh Kumar K.V struct p9_qid qid; 4391c7850f9SSasha Levin struct p9_fid *fid; 440c797b6c6SAneesh Kumar K.V u32 fid_val, afid, uid; 441bfc15268SAneesh Kumar K.V 442c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddssd", &fid_val, &afid, 443c797b6c6SAneesh Kumar K.V &uname, &aname, &uid); 4441c7850f9SSasha Levin 44539257180SPekka Enberg free(uname); 44639257180SPekka Enberg free(aname); 44739257180SPekka Enberg 44830204a77SAneesh Kumar K.V if (lstat(p9dev->root_dir, &st) < 0) 4496c8ca053SAneesh Kumar K.V goto err_out; 4501c7850f9SSasha Levin 451c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 4521c7850f9SSasha Levin 45331a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 454c797b6c6SAneesh Kumar K.V fid->uid = uid; 4551c7850f9SSasha Levin strcpy(fid->path, "/"); 4561c7850f9SSasha Levin 457bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 458bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 459bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 4606c8ca053SAneesh Kumar K.V return; 4616c8ca053SAneesh Kumar K.V err_out: 4626c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 463ead43b01SAneesh Kumar K.V return; 4641c7850f9SSasha Levin } 4651c7850f9SSasha Levin 466c797b6c6SAneesh Kumar K.V static void virtio_p9_fill_stat(struct p9_dev *p9dev, 467c797b6c6SAneesh Kumar K.V struct stat *st, struct p9_stat_dotl *statl) 4685f900f6dSSasha Levin { 469c797b6c6SAneesh Kumar K.V memset(statl, 0, sizeof(*statl)); 470c797b6c6SAneesh Kumar K.V statl->st_mode = st->st_mode; 471c797b6c6SAneesh Kumar K.V statl->st_nlink = st->st_nlink; 472506fd90bSSasha Levin statl->st_uid = KUIDT_INIT(st->st_uid); 473506fd90bSSasha Levin statl->st_gid = KGIDT_INIT(st->st_gid); 474c797b6c6SAneesh Kumar K.V statl->st_rdev = st->st_rdev; 475c797b6c6SAneesh Kumar K.V statl->st_size = st->st_size; 476c797b6c6SAneesh Kumar K.V statl->st_blksize = st->st_blksize; 477c797b6c6SAneesh Kumar K.V statl->st_blocks = st->st_blocks; 478c797b6c6SAneesh Kumar K.V statl->st_atime_sec = st->st_atime; 479c797b6c6SAneesh Kumar K.V statl->st_atime_nsec = st->st_atim.tv_nsec; 480c797b6c6SAneesh Kumar K.V statl->st_mtime_sec = st->st_mtime; 481c797b6c6SAneesh Kumar K.V statl->st_mtime_nsec = st->st_mtim.tv_nsec; 482c797b6c6SAneesh Kumar K.V statl->st_ctime_sec = st->st_ctime; 483c797b6c6SAneesh Kumar K.V statl->st_ctime_nsec = st->st_ctim.tv_nsec; 484c797b6c6SAneesh Kumar K.V /* Currently we only support BASIC fields in stat */ 485c797b6c6SAneesh Kumar K.V statl->st_result_mask = P9_STATS_BASIC; 486c797b6c6SAneesh Kumar K.V stat2qid(st, &statl->qid); 4871c7850f9SSasha Levin } 4881c7850f9SSasha Levin 489ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev, 490af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4911c7850f9SSasha Levin { 492bfc15268SAneesh Kumar K.V u64 offset; 493bfc15268SAneesh Kumar K.V u32 fid_val; 494c797b6c6SAneesh Kumar K.V u16 iov_cnt; 495c797b6c6SAneesh Kumar K.V void *iov_base; 496c797b6c6SAneesh Kumar K.V size_t iov_len; 497bfc15268SAneesh Kumar K.V u32 count, rcount; 498bfc15268SAneesh Kumar K.V struct p9_fid *fid; 499c797b6c6SAneesh Kumar K.V 5001c7850f9SSasha Levin 501bfc15268SAneesh Kumar K.V rcount = 0; 502bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 50331a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 50450c479e0SAneesh Kumar K.V 50550c479e0SAneesh Kumar K.V iov_base = pdu->in_iov[0].iov_base; 50650c479e0SAneesh Kumar K.V iov_len = pdu->in_iov[0].iov_len; 50750c479e0SAneesh Kumar K.V iov_cnt = pdu->in_iov_cnt; 5085529bcd7SAsias He pdu->in_iov[0].iov_base += VIRTIO_9P_HDR_LEN + sizeof(u32); 5095529bcd7SAsias He pdu->in_iov[0].iov_len -= VIRTIO_9P_HDR_LEN + sizeof(u32); 5106b163a87SAneesh Kumar K.V pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov, 511bfc15268SAneesh Kumar K.V count, 5126b163a87SAneesh Kumar K.V pdu->in_iov_cnt); 513bfc15268SAneesh Kumar K.V rcount = preadv(fid->fd, pdu->in_iov, 514bfc15268SAneesh Kumar K.V pdu->in_iov_cnt, offset); 515bfc15268SAneesh Kumar K.V if (rcount > count) 516bfc15268SAneesh Kumar K.V rcount = count; 517bfc15268SAneesh Kumar K.V /* 518bfc15268SAneesh Kumar K.V * Update the iov_base back, so that rest of 519bfc15268SAneesh Kumar K.V * pdu_writef works correctly. 520bfc15268SAneesh Kumar K.V */ 52150c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_base = iov_base; 52250c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_len = iov_len; 52350c479e0SAneesh Kumar K.V pdu->in_iov_cnt = iov_cnt; 524c797b6c6SAneesh Kumar K.V 5255529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 526bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 527bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 528bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 529ead43b01SAneesh Kumar K.V return; 5301c7850f9SSasha Levin } 5311c7850f9SSasha Levin 532c797b6c6SAneesh Kumar K.V static int virtio_p9_dentry_size(struct dirent *dent) 533c797b6c6SAneesh Kumar K.V { 534c797b6c6SAneesh Kumar K.V /* 535c797b6c6SAneesh Kumar K.V * Size of each dirent: 536c797b6c6SAneesh Kumar K.V * qid(13) + offset(8) + type(1) + name_len(2) + name 537c797b6c6SAneesh Kumar K.V */ 538c797b6c6SAneesh Kumar K.V return 24 + strlen(dent->d_name); 539c797b6c6SAneesh Kumar K.V } 540c797b6c6SAneesh Kumar K.V 541c797b6c6SAneesh Kumar K.V static void virtio_p9_readdir(struct p9_dev *p9dev, 542c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 543c797b6c6SAneesh Kumar K.V { 544c797b6c6SAneesh Kumar K.V u32 fid_val; 545c797b6c6SAneesh Kumar K.V u32 count, rcount; 546c797b6c6SAneesh Kumar K.V struct stat st; 547c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 548c797b6c6SAneesh Kumar K.V struct dirent *dent; 549c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 550c797b6c6SAneesh Kumar K.V u64 offset, old_offset; 551c797b6c6SAneesh Kumar K.V 552c797b6c6SAneesh Kumar K.V rcount = 0; 553c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 55431a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 555c797b6c6SAneesh Kumar K.V 55632585666SSasha Levin if (!is_dir(fid)) { 55769bb4278SSasha Levin errno = EINVAL; 558c797b6c6SAneesh Kumar K.V goto err_out; 559c797b6c6SAneesh Kumar K.V } 560c797b6c6SAneesh Kumar K.V 561c797b6c6SAneesh Kumar K.V /* Move the offset specified */ 562c797b6c6SAneesh Kumar K.V seekdir(fid->dir, offset); 563c797b6c6SAneesh Kumar K.V 564c797b6c6SAneesh Kumar K.V old_offset = offset; 565c797b6c6SAneesh Kumar K.V /* If reading a dir, fill the buffer with p9_stat entries */ 566c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir); 567c797b6c6SAneesh Kumar K.V 568c797b6c6SAneesh Kumar K.V /* Skip the space for writing count */ 569c797b6c6SAneesh Kumar K.V pdu->write_offset += sizeof(u32); 570c797b6c6SAneesh Kumar K.V while (dent) { 571c797b6c6SAneesh Kumar K.V u32 read; 572c797b6c6SAneesh Kumar K.V struct p9_qid qid; 573c797b6c6SAneesh Kumar K.V 574c797b6c6SAneesh Kumar K.V if ((rcount + virtio_p9_dentry_size(dent)) > count) { 575c797b6c6SAneesh Kumar K.V /* seek to the previous offset and return */ 576c797b6c6SAneesh Kumar K.V seekdir(fid->dir, old_offset); 577c797b6c6SAneesh Kumar K.V break; 578c797b6c6SAneesh Kumar K.V } 579c797b6c6SAneesh Kumar K.V old_offset = dent->d_off; 580c797b6c6SAneesh Kumar K.V lstat(rel_to_abs(p9dev, dent->d_name, full_path), &st); 581c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 582c797b6c6SAneesh Kumar K.V read = pdu->write_offset; 583c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qqbs", &qid, dent->d_off, 584c797b6c6SAneesh Kumar K.V dent->d_type, dent->d_name); 585c797b6c6SAneesh Kumar K.V rcount += pdu->write_offset - read; 586c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir); 587c797b6c6SAneesh Kumar K.V } 588c797b6c6SAneesh Kumar K.V 5895529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 590c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 591c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 592c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 593c797b6c6SAneesh Kumar K.V return; 594c797b6c6SAneesh Kumar K.V err_out: 595c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 596c797b6c6SAneesh Kumar K.V return; 597c797b6c6SAneesh Kumar K.V } 598c797b6c6SAneesh Kumar K.V 599c797b6c6SAneesh Kumar K.V 600c797b6c6SAneesh Kumar K.V static void virtio_p9_getattr(struct p9_dev *p9dev, 601af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 6021c7850f9SSasha Levin { 603bfc15268SAneesh Kumar K.V u32 fid_val; 604af045e53SAneesh Kumar K.V struct stat st; 605c797b6c6SAneesh Kumar K.V u64 request_mask; 606bfc15268SAneesh Kumar K.V struct p9_fid *fid; 607c797b6c6SAneesh Kumar K.V struct p9_stat_dotl statl; 6081c7850f9SSasha Levin 609c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dq", &fid_val, &request_mask); 61031a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 61130204a77SAneesh Kumar K.V if (lstat(fid->abs_path, &st) < 0) 6126c8ca053SAneesh Kumar K.V goto err_out; 6131c7850f9SSasha Levin 614c797b6c6SAneesh Kumar K.V virtio_p9_fill_stat(p9dev, &st, &statl); 615c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "A", &statl); 616bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 617bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 618ead43b01SAneesh Kumar K.V return; 6196c8ca053SAneesh Kumar K.V err_out: 6206c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 6216c8ca053SAneesh Kumar K.V return; 6221c7850f9SSasha Levin } 6231c7850f9SSasha Levin 624c797b6c6SAneesh Kumar K.V /* FIXME!! from linux/fs.h */ 625c797b6c6SAneesh Kumar K.V /* 626c797b6c6SAneesh Kumar K.V * Attribute flags. These should be or-ed together to figure out what 627c797b6c6SAneesh Kumar K.V * has been changed! 628c797b6c6SAneesh Kumar K.V */ 629c797b6c6SAneesh Kumar K.V #define ATTR_MODE (1 << 0) 630c797b6c6SAneesh Kumar K.V #define ATTR_UID (1 << 1) 631c797b6c6SAneesh Kumar K.V #define ATTR_GID (1 << 2) 632c797b6c6SAneesh Kumar K.V #define ATTR_SIZE (1 << 3) 633c797b6c6SAneesh Kumar K.V #define ATTR_ATIME (1 << 4) 634c797b6c6SAneesh Kumar K.V #define ATTR_MTIME (1 << 5) 635c797b6c6SAneesh Kumar K.V #define ATTR_CTIME (1 << 6) 636c797b6c6SAneesh Kumar K.V #define ATTR_ATIME_SET (1 << 7) 637c797b6c6SAneesh Kumar K.V #define ATTR_MTIME_SET (1 << 8) 638c797b6c6SAneesh Kumar K.V #define ATTR_FORCE (1 << 9) /* Not a change, but a change it */ 639c797b6c6SAneesh Kumar K.V #define ATTR_ATTR_FLAG (1 << 10) 640c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SUID (1 << 11) 641c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SGID (1 << 12) 642c797b6c6SAneesh Kumar K.V #define ATTR_FILE (1 << 13) 643c797b6c6SAneesh Kumar K.V #define ATTR_KILL_PRIV (1 << 14) 644c797b6c6SAneesh Kumar K.V #define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ 645c797b6c6SAneesh Kumar K.V #define ATTR_TIMES_SET (1 << 16) 646c797b6c6SAneesh Kumar K.V 647c797b6c6SAneesh Kumar K.V #define ATTR_MASK 127 648c797b6c6SAneesh Kumar K.V 649c797b6c6SAneesh Kumar K.V static void virtio_p9_setattr(struct p9_dev *p9dev, 650af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 6511c7850f9SSasha Levin { 652c797b6c6SAneesh Kumar K.V int ret = 0; 653bfc15268SAneesh Kumar K.V u32 fid_val; 654bfc15268SAneesh Kumar K.V struct p9_fid *fid; 655c797b6c6SAneesh Kumar K.V struct p9_iattr_dotl p9attr; 6561c7850f9SSasha Levin 657c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dI", &fid_val, &p9attr); 65831a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 6591c7850f9SSasha Levin 660c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MODE) { 661c797b6c6SAneesh Kumar K.V ret = chmod(fid->abs_path, p9attr.mode); 662c797b6c6SAneesh Kumar K.V if (ret < 0) 663c797b6c6SAneesh Kumar K.V goto err_out; 664c797b6c6SAneesh Kumar K.V } 665c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_ATIME | ATTR_MTIME)) { 666c797b6c6SAneesh Kumar K.V struct timespec times[2]; 667c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME) { 668c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME_SET) { 669c797b6c6SAneesh Kumar K.V times[0].tv_sec = p9attr.atime_sec; 670c797b6c6SAneesh Kumar K.V times[0].tv_nsec = p9attr.atime_nsec; 671c797b6c6SAneesh Kumar K.V } else { 672c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_NOW; 673c797b6c6SAneesh Kumar K.V } 674c797b6c6SAneesh Kumar K.V } else { 675c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_OMIT; 676c797b6c6SAneesh Kumar K.V } 677c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME) { 678c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME_SET) { 679c797b6c6SAneesh Kumar K.V times[1].tv_sec = p9attr.mtime_sec; 680c797b6c6SAneesh Kumar K.V times[1].tv_nsec = p9attr.mtime_nsec; 681c797b6c6SAneesh Kumar K.V } else { 682c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_NOW; 683c797b6c6SAneesh Kumar K.V } 684c797b6c6SAneesh Kumar K.V } else 685c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_OMIT; 686c797b6c6SAneesh Kumar K.V 687c797b6c6SAneesh Kumar K.V ret = utimensat(-1, fid->abs_path, times, AT_SYMLINK_NOFOLLOW); 688c797b6c6SAneesh Kumar K.V if (ret < 0) 689c797b6c6SAneesh Kumar K.V goto err_out; 690c797b6c6SAneesh Kumar K.V } 691c797b6c6SAneesh Kumar K.V /* 692c797b6c6SAneesh Kumar K.V * If the only valid entry in iattr is ctime we can call 693c797b6c6SAneesh Kumar K.V * chown(-1,-1) to update the ctime of the file 694c797b6c6SAneesh Kumar K.V */ 695c797b6c6SAneesh Kumar K.V if ((p9attr.valid & (ATTR_UID | ATTR_GID)) || 696c797b6c6SAneesh Kumar K.V ((p9attr.valid & ATTR_CTIME) 697c797b6c6SAneesh Kumar K.V && !((p9attr.valid & ATTR_MASK) & ~ATTR_CTIME))) { 698c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_UID)) 699506fd90bSSasha Levin p9attr.uid = KUIDT_INIT(-1); 700c797b6c6SAneesh Kumar K.V 701c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_GID)) 702506fd90bSSasha Levin p9attr.gid = KGIDT_INIT(-1); 703c797b6c6SAneesh Kumar K.V 704506fd90bSSasha Levin ret = lchown(fid->abs_path, __kuid_val(p9attr.uid), 705506fd90bSSasha Levin __kgid_val(p9attr.gid)); 706c797b6c6SAneesh Kumar K.V if (ret < 0) 707c797b6c6SAneesh Kumar K.V goto err_out; 708c797b6c6SAneesh Kumar K.V } 709c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_SIZE)) { 710c797b6c6SAneesh Kumar K.V ret = truncate(fid->abs_path, p9attr.size); 711c797b6c6SAneesh Kumar K.V if (ret < 0) 712c797b6c6SAneesh Kumar K.V goto err_out; 713c797b6c6SAneesh Kumar K.V } 7145529bcd7SAsias He *outlen = VIRTIO_9P_HDR_LEN; 715bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 716ead43b01SAneesh Kumar K.V return; 7174bc9734aSAneesh Kumar K.V err_out: 7184bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 7194bc9734aSAneesh Kumar K.V return; 7201c7850f9SSasha Levin } 7211c7850f9SSasha Levin 722ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev, 723af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 7241c7850f9SSasha Levin { 7254bc9734aSAneesh Kumar K.V 726bfc15268SAneesh Kumar K.V u64 offset; 727bfc15268SAneesh Kumar K.V u32 fid_val; 7284bc9734aSAneesh Kumar K.V u32 count; 7294bc9734aSAneesh Kumar K.V ssize_t res; 73050c479e0SAneesh Kumar K.V u16 iov_cnt; 73150c479e0SAneesh Kumar K.V void *iov_base; 73250c479e0SAneesh Kumar K.V size_t iov_len; 733bfc15268SAneesh Kumar K.V struct p9_fid *fid; 734b064b05aSAneesh Kumar K.V /* u32 fid + u64 offset + u32 count */ 735b064b05aSAneesh Kumar K.V int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32); 7361c7850f9SSasha Levin 737bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 73831a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 739af045e53SAneesh Kumar K.V 74050c479e0SAneesh Kumar K.V iov_base = pdu->out_iov[0].iov_base; 74150c479e0SAneesh Kumar K.V iov_len = pdu->out_iov[0].iov_len; 74250c479e0SAneesh Kumar K.V iov_cnt = pdu->out_iov_cnt; 74350c479e0SAneesh Kumar K.V 744bfc15268SAneesh Kumar K.V /* Adjust the iovec to skip the header and meta data */ 745b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size); 746b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_len -= (sizeof(struct p9_msg) + twrite_size); 747bfc15268SAneesh Kumar K.V pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count, 7486b163a87SAneesh Kumar K.V pdu->out_iov_cnt); 7494bc9734aSAneesh Kumar K.V res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset); 75050c479e0SAneesh Kumar K.V /* 75150c479e0SAneesh Kumar K.V * Update the iov_base back, so that rest of 75250c479e0SAneesh Kumar K.V * pdu_readf works correctly. 75350c479e0SAneesh Kumar K.V */ 75450c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_base = iov_base; 75550c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_len = iov_len; 75650c479e0SAneesh Kumar K.V pdu->out_iov_cnt = iov_cnt; 757c797b6c6SAneesh Kumar K.V 7584bc9734aSAneesh Kumar K.V if (res < 0) 7594bc9734aSAneesh Kumar K.V goto err_out; 7604bc9734aSAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", res); 761bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 762bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 763ead43b01SAneesh Kumar K.V return; 7644bc9734aSAneesh Kumar K.V err_out: 7654bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 7664bc9734aSAneesh Kumar K.V return; 7671c7850f9SSasha Levin } 7681c7850f9SSasha Levin 7696fc5cd9bSSasha Levin static void virtio_p9_remove(struct p9_dev *p9dev, 7706fc5cd9bSSasha Levin struct p9_pdu *pdu, u32 *outlen) 7716fc5cd9bSSasha Levin { 7726fc5cd9bSSasha Levin int ret; 7736fc5cd9bSSasha Levin u32 fid_val; 7746fc5cd9bSSasha Levin struct p9_fid *fid; 7756fc5cd9bSSasha Levin 7766fc5cd9bSSasha Levin virtio_p9_pdu_readf(pdu, "d", &fid_val); 77731a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 7786fc5cd9bSSasha Levin 7799b604a9cSSasha Levin ret = remove(fid->abs_path); 7806fc5cd9bSSasha Levin if (ret < 0) 7816fc5cd9bSSasha Levin goto err_out; 7826fc5cd9bSSasha Levin *outlen = pdu->write_offset; 7836fc5cd9bSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 7846fc5cd9bSSasha Levin return; 7856fc5cd9bSSasha Levin 7866fc5cd9bSSasha Levin err_out: 7876fc5cd9bSSasha Levin virtio_p9_error_reply(p9dev, pdu, errno, outlen); 7886fc5cd9bSSasha Levin return; 7896fc5cd9bSSasha Levin } 7906fc5cd9bSSasha Levin 791f161f28bSSasha Levin static void virtio_p9_rename(struct p9_dev *p9dev, 792f161f28bSSasha Levin struct p9_pdu *pdu, u32 *outlen) 793f161f28bSSasha Levin { 794f161f28bSSasha Levin int ret; 795f161f28bSSasha Levin u32 fid_val, new_fid_val; 796f161f28bSSasha Levin struct p9_fid *fid, *new_fid; 797f161f28bSSasha Levin char full_path[PATH_MAX], *new_name; 798f161f28bSSasha Levin 799f161f28bSSasha Levin virtio_p9_pdu_readf(pdu, "dds", &fid_val, &new_fid_val, &new_name); 80031a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 80131a6fb8dSSasha Levin new_fid = get_fid(p9dev, new_fid_val); 802f161f28bSSasha Levin 803f161f28bSSasha Levin sprintf(full_path, "%s/%s", new_fid->abs_path, new_name); 804*9bb99a82SG. Campana if (path_is_illegal(full_path)) { 805*9bb99a82SG. Campana errno = EACCES; 806*9bb99a82SG. Campana goto err_out; 807*9bb99a82SG. Campana } 808*9bb99a82SG. Campana 809f161f28bSSasha Levin ret = rename(fid->abs_path, full_path); 810f161f28bSSasha Levin if (ret < 0) 811f161f28bSSasha Levin goto err_out; 812f161f28bSSasha Levin *outlen = pdu->write_offset; 813f161f28bSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 814f161f28bSSasha Levin return; 815f161f28bSSasha Levin 816f161f28bSSasha Levin err_out: 817f161f28bSSasha Levin virtio_p9_error_reply(p9dev, pdu, errno, outlen); 818f161f28bSSasha Levin return; 819f161f28bSSasha Levin } 820f161f28bSSasha Levin 821c797b6c6SAneesh Kumar K.V static void virtio_p9_readlink(struct p9_dev *p9dev, 822c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 823c797b6c6SAneesh Kumar K.V { 824c797b6c6SAneesh Kumar K.V int ret; 825c797b6c6SAneesh Kumar K.V u32 fid_val; 826c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 827c797b6c6SAneesh Kumar K.V char target_path[PATH_MAX]; 828c797b6c6SAneesh Kumar K.V 829c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 83031a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 831c797b6c6SAneesh Kumar K.V 832c797b6c6SAneesh Kumar K.V memset(target_path, 0, PATH_MAX); 833c797b6c6SAneesh Kumar K.V ret = readlink(fid->abs_path, target_path, PATH_MAX - 1); 834c797b6c6SAneesh Kumar K.V if (ret < 0) 835c797b6c6SAneesh Kumar K.V goto err_out; 836c797b6c6SAneesh Kumar K.V 837c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "s", target_path); 838c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 839c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 840c797b6c6SAneesh Kumar K.V return; 841c797b6c6SAneesh Kumar K.V err_out: 842c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 843c797b6c6SAneesh Kumar K.V return; 844c797b6c6SAneesh Kumar K.V } 845c797b6c6SAneesh Kumar K.V 846c797b6c6SAneesh Kumar K.V static void virtio_p9_statfs(struct p9_dev *p9dev, 847c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 848c797b6c6SAneesh Kumar K.V { 849c797b6c6SAneesh Kumar K.V int ret; 850c797b6c6SAneesh Kumar K.V u64 fsid; 851c797b6c6SAneesh Kumar K.V u32 fid_val; 852c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 853c797b6c6SAneesh Kumar K.V struct statfs stat_buf; 854c797b6c6SAneesh Kumar K.V 855c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 85631a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 857c797b6c6SAneesh Kumar K.V 858c797b6c6SAneesh Kumar K.V ret = statfs(fid->abs_path, &stat_buf); 859c797b6c6SAneesh Kumar K.V if (ret < 0) 860c797b6c6SAneesh Kumar K.V goto err_out; 861c797b6c6SAneesh Kumar K.V /* FIXME!! f_blocks needs update based on client msize */ 862c797b6c6SAneesh Kumar K.V fsid = (unsigned int) stat_buf.f_fsid.__val[0] | 863c797b6c6SAneesh Kumar K.V (unsigned long long)stat_buf.f_fsid.__val[1] << 32; 864c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ddqqqqqqd", stat_buf.f_type, 865c797b6c6SAneesh Kumar K.V stat_buf.f_bsize, stat_buf.f_blocks, 866c797b6c6SAneesh Kumar K.V stat_buf.f_bfree, stat_buf.f_bavail, 867c797b6c6SAneesh Kumar K.V stat_buf.f_files, stat_buf.f_ffree, 868c797b6c6SAneesh Kumar K.V fsid, stat_buf.f_namelen); 869c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 870c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 871c797b6c6SAneesh Kumar K.V return; 872c797b6c6SAneesh Kumar K.V err_out: 873c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 874c797b6c6SAneesh Kumar K.V return; 875c797b6c6SAneesh Kumar K.V } 876c797b6c6SAneesh Kumar K.V 877c797b6c6SAneesh Kumar K.V static void virtio_p9_mknod(struct p9_dev *p9dev, 878c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 879c797b6c6SAneesh Kumar K.V { 880c797b6c6SAneesh Kumar K.V int ret; 881c797b6c6SAneesh Kumar K.V char *name; 882c797b6c6SAneesh Kumar K.V struct stat st; 883c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 884c797b6c6SAneesh Kumar K.V struct p9_qid qid; 885c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 886c797b6c6SAneesh Kumar K.V u32 fid_val, mode, major, minor, gid; 887c797b6c6SAneesh Kumar K.V 888c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdddd", &fid_val, &name, &mode, 889c797b6c6SAneesh Kumar K.V &major, &minor, &gid); 890c797b6c6SAneesh Kumar K.V 89131a6fb8dSSasha Levin dfid = get_fid(p9dev, fid_val); 892c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 893*9bb99a82SG. Campana if (path_is_illegal(full_path)) { 894*9bb99a82SG. Campana errno = EACCES; 895*9bb99a82SG. Campana goto err_out; 896*9bb99a82SG. Campana } 897*9bb99a82SG. Campana 898c797b6c6SAneesh Kumar K.V ret = mknod(full_path, mode, makedev(major, minor)); 899c797b6c6SAneesh Kumar K.V if (ret < 0) 900c797b6c6SAneesh Kumar K.V goto err_out; 901c797b6c6SAneesh Kumar K.V 902c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0) 903c797b6c6SAneesh Kumar K.V goto err_out; 904c797b6c6SAneesh Kumar K.V 905c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 906c797b6c6SAneesh Kumar K.V if (ret < 0) 907c797b6c6SAneesh Kumar K.V goto err_out; 908c797b6c6SAneesh Kumar K.V 909c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 910c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 911c797b6c6SAneesh Kumar K.V free(name); 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 free(name); 917c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 918c797b6c6SAneesh Kumar K.V return; 919c797b6c6SAneesh Kumar K.V } 920c797b6c6SAneesh Kumar K.V 921c797b6c6SAneesh Kumar K.V static void virtio_p9_fsync(struct p9_dev *p9dev, 922c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 923c797b6c6SAneesh Kumar K.V { 924644140efSRussell King int ret, fd; 925c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 926c797b6c6SAneesh Kumar K.V u32 fid_val, datasync; 927c797b6c6SAneesh Kumar K.V 928c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid_val, &datasync); 92931a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 930c797b6c6SAneesh Kumar K.V 931644140efSRussell King if (fid->dir) 932644140efSRussell King fd = dirfd(fid->dir); 933c797b6c6SAneesh Kumar K.V else 934644140efSRussell King fd = fid->fd; 935644140efSRussell King 936644140efSRussell King if (datasync) 937644140efSRussell King ret = fdatasync(fd); 938644140efSRussell King else 939644140efSRussell King ret = fsync(fd); 940c797b6c6SAneesh Kumar K.V if (ret < 0) 941c797b6c6SAneesh Kumar K.V goto err_out; 942c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 943c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 944c797b6c6SAneesh Kumar K.V return; 945c797b6c6SAneesh Kumar K.V err_out: 946c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 947c797b6c6SAneesh Kumar K.V return; 948c797b6c6SAneesh Kumar K.V } 949c797b6c6SAneesh Kumar K.V 950c797b6c6SAneesh Kumar K.V static void virtio_p9_symlink(struct p9_dev *p9dev, 951c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 952c797b6c6SAneesh Kumar K.V { 953c797b6c6SAneesh Kumar K.V int ret; 954c797b6c6SAneesh Kumar K.V struct stat st; 955c797b6c6SAneesh Kumar K.V u32 fid_val, gid; 956c797b6c6SAneesh Kumar K.V struct p9_qid qid; 957c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 958c797b6c6SAneesh Kumar K.V char new_name[PATH_MAX]; 959c797b6c6SAneesh Kumar K.V char *old_path, *name; 960c797b6c6SAneesh Kumar K.V 961c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dssd", &fid_val, &name, &old_path, &gid); 962c797b6c6SAneesh Kumar K.V 96331a6fb8dSSasha Levin dfid = get_fid(p9dev, fid_val); 964c797b6c6SAneesh Kumar K.V sprintf(new_name, "%s/%s", dfid->abs_path, name); 965*9bb99a82SG. Campana if (path_is_illegal(new_name)) { 966*9bb99a82SG. Campana errno = EACCES; 967*9bb99a82SG. Campana goto err_out; 968*9bb99a82SG. Campana } 969*9bb99a82SG. Campana 970c797b6c6SAneesh Kumar K.V ret = symlink(old_path, new_name); 971c797b6c6SAneesh Kumar K.V if (ret < 0) 972c797b6c6SAneesh Kumar K.V goto err_out; 973c797b6c6SAneesh Kumar K.V 974c797b6c6SAneesh Kumar K.V if (lstat(new_name, &st) < 0) 975c797b6c6SAneesh Kumar K.V goto err_out; 976c797b6c6SAneesh Kumar K.V 977c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 978c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 979c797b6c6SAneesh Kumar K.V free(name); 980c797b6c6SAneesh Kumar K.V free(old_path); 981c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 982c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 983c797b6c6SAneesh Kumar K.V return; 984c797b6c6SAneesh Kumar K.V err_out: 985c797b6c6SAneesh Kumar K.V free(name); 986c797b6c6SAneesh Kumar K.V free(old_path); 987c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 988c797b6c6SAneesh Kumar K.V return; 989c797b6c6SAneesh Kumar K.V } 990c797b6c6SAneesh Kumar K.V 991c797b6c6SAneesh Kumar K.V static void virtio_p9_link(struct p9_dev *p9dev, 992c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 993c797b6c6SAneesh Kumar K.V { 994c797b6c6SAneesh Kumar K.V int ret; 995c797b6c6SAneesh Kumar K.V char *name; 996c797b6c6SAneesh Kumar K.V u32 fid_val, dfid_val; 997c797b6c6SAneesh Kumar K.V struct p9_fid *dfid, *fid; 998c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 999c797b6c6SAneesh Kumar K.V 1000c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dds", &dfid_val, &fid_val, &name); 1001c797b6c6SAneesh Kumar K.V 100231a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 100331a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 1004c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 1005*9bb99a82SG. Campana if (path_is_illegal(full_path)) { 1006*9bb99a82SG. Campana errno = EACCES; 1007*9bb99a82SG. Campana goto err_out; 1008*9bb99a82SG. Campana } 1009*9bb99a82SG. Campana 1010c797b6c6SAneesh Kumar K.V ret = link(fid->abs_path, full_path); 1011c797b6c6SAneesh Kumar K.V if (ret < 0) 1012c797b6c6SAneesh Kumar K.V goto err_out; 1013c797b6c6SAneesh Kumar K.V free(name); 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 free(name); 1019c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1020c797b6c6SAneesh Kumar K.V return; 1021c797b6c6SAneesh Kumar K.V 1022c797b6c6SAneesh Kumar K.V } 1023c797b6c6SAneesh Kumar K.V 1024c797b6c6SAneesh Kumar K.V static void virtio_p9_lock(struct p9_dev *p9dev, 1025c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1026c797b6c6SAneesh Kumar K.V { 1027c797b6c6SAneesh Kumar K.V u8 ret; 1028c797b6c6SAneesh Kumar K.V u32 fid_val; 1029c797b6c6SAneesh Kumar K.V struct p9_flock flock; 1030c797b6c6SAneesh Kumar K.V 1031c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbdqqds", &fid_val, &flock.type, 1032c797b6c6SAneesh Kumar K.V &flock.flags, &flock.start, &flock.length, 1033c797b6c6SAneesh Kumar K.V &flock.proc_id, &flock.client_id); 1034c797b6c6SAneesh Kumar K.V 1035c797b6c6SAneesh Kumar K.V /* Just return success */ 1036c797b6c6SAneesh Kumar K.V ret = P9_LOCK_SUCCESS; 1037c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", ret); 1038c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1039c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1040c797b6c6SAneesh Kumar K.V free(flock.client_id); 1041c797b6c6SAneesh Kumar K.V return; 1042c797b6c6SAneesh Kumar K.V } 1043c797b6c6SAneesh Kumar K.V 1044c797b6c6SAneesh Kumar K.V static void virtio_p9_getlock(struct p9_dev *p9dev, 1045c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1046c797b6c6SAneesh Kumar K.V { 1047c797b6c6SAneesh Kumar K.V u32 fid_val; 1048c797b6c6SAneesh Kumar K.V struct p9_getlock glock; 1049c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbqqds", &fid_val, &glock.type, 1050c797b6c6SAneesh Kumar K.V &glock.start, &glock.length, &glock.proc_id, 1051c797b6c6SAneesh Kumar K.V &glock.client_id); 1052c797b6c6SAneesh Kumar K.V 1053c797b6c6SAneesh Kumar K.V /* Just return success */ 1054c797b6c6SAneesh Kumar K.V glock.type = F_UNLCK; 1055c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "bqqds", glock.type, 1056c797b6c6SAneesh Kumar K.V glock.start, glock.length, glock.proc_id, 1057c797b6c6SAneesh Kumar K.V glock.client_id); 1058c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1059c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1060c797b6c6SAneesh Kumar K.V free(glock.client_id); 1061c797b6c6SAneesh Kumar K.V return; 1062c797b6c6SAneesh Kumar K.V } 1063c797b6c6SAneesh Kumar K.V 1064c797b6c6SAneesh Kumar K.V static int virtio_p9_ancestor(char *path, char *ancestor) 1065c797b6c6SAneesh Kumar K.V { 1066c797b6c6SAneesh Kumar K.V int size = strlen(ancestor); 1067c797b6c6SAneesh Kumar K.V if (!strncmp(path, ancestor, size)) { 1068c797b6c6SAneesh Kumar K.V /* 1069c797b6c6SAneesh Kumar K.V * Now check whether ancestor is a full name or 1070c797b6c6SAneesh Kumar K.V * or directory component and not just part 1071c797b6c6SAneesh Kumar K.V * of a name. 1072c797b6c6SAneesh Kumar K.V */ 1073c797b6c6SAneesh Kumar K.V if (path[size] == '\0' || path[size] == '/') 1074c797b6c6SAneesh Kumar K.V return 1; 1075c797b6c6SAneesh Kumar K.V } 1076c797b6c6SAneesh Kumar K.V return 0; 1077c797b6c6SAneesh Kumar K.V } 1078c797b6c6SAneesh Kumar K.V 1079c797b6c6SAneesh Kumar K.V static void virtio_p9_fix_path(char *fid_path, char *old_name, char *new_name) 1080c797b6c6SAneesh Kumar K.V { 1081c797b6c6SAneesh Kumar K.V char tmp_name[PATH_MAX]; 1082c797b6c6SAneesh Kumar K.V size_t rp_sz = strlen(old_name); 1083c797b6c6SAneesh Kumar K.V 1084c797b6c6SAneesh Kumar K.V if (rp_sz == strlen(fid_path)) { 1085c797b6c6SAneesh Kumar K.V /* replace the full name */ 1086c797b6c6SAneesh Kumar K.V strcpy(fid_path, new_name); 1087c797b6c6SAneesh Kumar K.V return; 1088c797b6c6SAneesh Kumar K.V } 1089c797b6c6SAneesh Kumar K.V /* save the trailing path details */ 1090c797b6c6SAneesh Kumar K.V strcpy(tmp_name, fid_path + rp_sz); 1091c797b6c6SAneesh Kumar K.V sprintf(fid_path, "%s%s", new_name, tmp_name); 1092c797b6c6SAneesh Kumar K.V return; 1093c797b6c6SAneesh Kumar K.V } 1094c797b6c6SAneesh Kumar K.V 1095e2341580SSasha Levin static void rename_fids(struct p9_dev *p9dev, char *old_name, char *new_name) 1096e2341580SSasha Levin { 1097e2341580SSasha Levin struct rb_node *node = rb_first(&p9dev->fids); 1098e2341580SSasha Levin 1099e2341580SSasha Levin while (node) { 1100e2341580SSasha Levin struct p9_fid *fid = rb_entry(node, struct p9_fid, node); 1101e2341580SSasha Levin 1102e2341580SSasha Levin if (fid->fid != P9_NOFID && virtio_p9_ancestor(fid->path, old_name)) { 1103e2341580SSasha Levin virtio_p9_fix_path(fid->path, old_name, new_name); 1104e2341580SSasha Levin } 1105e2341580SSasha Levin node = rb_next(node); 1106e2341580SSasha Levin } 1107e2341580SSasha Levin } 1108e2341580SSasha Levin 1109c797b6c6SAneesh Kumar K.V static void virtio_p9_renameat(struct p9_dev *p9dev, 1110c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1111c797b6c6SAneesh Kumar K.V { 1112e2341580SSasha Levin int ret; 1113c797b6c6SAneesh Kumar K.V char *old_name, *new_name; 1114c797b6c6SAneesh Kumar K.V u32 old_dfid_val, new_dfid_val; 1115c797b6c6SAneesh Kumar K.V struct p9_fid *old_dfid, *new_dfid; 1116c797b6c6SAneesh Kumar K.V char old_full_path[PATH_MAX], new_full_path[PATH_MAX]; 1117c797b6c6SAneesh Kumar K.V 1118c797b6c6SAneesh Kumar K.V 1119c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsds", &old_dfid_val, &old_name, 1120c797b6c6SAneesh Kumar K.V &new_dfid_val, &new_name); 1121c797b6c6SAneesh Kumar K.V 112231a6fb8dSSasha Levin old_dfid = get_fid(p9dev, old_dfid_val); 112331a6fb8dSSasha Levin new_dfid = get_fid(p9dev, new_dfid_val); 1124c797b6c6SAneesh Kumar K.V 1125c797b6c6SAneesh Kumar K.V sprintf(old_full_path, "%s/%s", old_dfid->abs_path, old_name); 1126c797b6c6SAneesh Kumar K.V sprintf(new_full_path, "%s/%s", new_dfid->abs_path, new_name); 1127*9bb99a82SG. Campana if (path_is_illegal(old_full_path) || path_is_illegal(new_full_path)) { 1128*9bb99a82SG. Campana errno = EACCES; 1129*9bb99a82SG. Campana goto err_out; 1130*9bb99a82SG. Campana } 1131*9bb99a82SG. Campana 1132c797b6c6SAneesh Kumar K.V ret = rename(old_full_path, new_full_path); 1133c797b6c6SAneesh Kumar K.V if (ret < 0) 1134c797b6c6SAneesh Kumar K.V goto err_out; 1135c797b6c6SAneesh Kumar K.V /* 1136c797b6c6SAneesh Kumar K.V * Now fix path in other fids, if the renamed path is part of 1137c797b6c6SAneesh Kumar K.V * that. 1138c797b6c6SAneesh Kumar K.V */ 1139e2341580SSasha Levin rename_fids(p9dev, old_name, new_name); 1140c797b6c6SAneesh Kumar K.V free(old_name); 1141c797b6c6SAneesh Kumar K.V free(new_name); 1142c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1143c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1144c797b6c6SAneesh Kumar K.V return; 1145c797b6c6SAneesh Kumar K.V err_out: 1146c797b6c6SAneesh Kumar K.V free(old_name); 1147c797b6c6SAneesh Kumar K.V free(new_name); 1148c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1149c797b6c6SAneesh Kumar K.V return; 1150c797b6c6SAneesh Kumar K.V } 1151c797b6c6SAneesh Kumar K.V 1152c797b6c6SAneesh Kumar K.V static void virtio_p9_unlinkat(struct p9_dev *p9dev, 1153c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1154c797b6c6SAneesh Kumar K.V { 1155c797b6c6SAneesh Kumar K.V int ret; 1156c797b6c6SAneesh Kumar K.V char *name; 1157c797b6c6SAneesh Kumar K.V u32 fid_val, flags; 1158c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 1159c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 1160c797b6c6SAneesh Kumar K.V 1161c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsd", &fid_val, &name, &flags); 116231a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 1163c797b6c6SAneesh Kumar K.V 1164c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", fid->abs_path, name); 1165*9bb99a82SG. Campana if (path_is_illegal(full_path)) { 1166*9bb99a82SG. Campana errno = EACCES; 1167*9bb99a82SG. Campana goto err_out; 1168*9bb99a82SG. Campana } 1169*9bb99a82SG. Campana 1170c797b6c6SAneesh Kumar K.V ret = remove(full_path); 1171c797b6c6SAneesh Kumar K.V if (ret < 0) 1172c797b6c6SAneesh Kumar K.V goto err_out; 1173c797b6c6SAneesh Kumar K.V free(name); 1174c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1175c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1176c797b6c6SAneesh Kumar K.V return; 1177c797b6c6SAneesh Kumar K.V err_out: 1178c797b6c6SAneesh Kumar K.V free(name); 1179c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1180c797b6c6SAneesh Kumar K.V return; 1181c797b6c6SAneesh Kumar K.V } 1182c797b6c6SAneesh Kumar K.V 11835cc808aaSSasha Levin static void virtio_p9_flush(struct p9_dev *p9dev, 11845cc808aaSSasha Levin struct p9_pdu *pdu, u32 *outlen) 11855cc808aaSSasha Levin { 11865cc808aaSSasha Levin u16 tag, oldtag; 11875cc808aaSSasha Levin 11885cc808aaSSasha Levin virtio_p9_pdu_readf(pdu, "ww", &tag, &oldtag); 11895cc808aaSSasha Levin virtio_p9_pdu_writef(pdu, "w", tag); 11905cc808aaSSasha Levin *outlen = pdu->write_offset; 11915cc808aaSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 11925cc808aaSSasha Levin 11935cc808aaSSasha Levin return; 11945cc808aaSSasha Levin } 11955cc808aaSSasha Levin 1196c797b6c6SAneesh Kumar K.V static void virtio_p9_eopnotsupp(struct p9_dev *p9dev, 1197c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1198c797b6c6SAneesh Kumar K.V { 1199c797b6c6SAneesh Kumar K.V return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen); 1200c797b6c6SAneesh Kumar K.V } 1201c797b6c6SAneesh Kumar K.V 1202ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev, 1203af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen); 1204b4422bf3SAneesh Kumar K.V 1205c797b6c6SAneesh Kumar K.V /* FIXME should be removed when merging with latest linus tree */ 1206c797b6c6SAneesh Kumar K.V #define P9_TRENAMEAT 74 1207c797b6c6SAneesh Kumar K.V #define P9_TUNLINKAT 76 1208c797b6c6SAneesh Kumar K.V 1209c797b6c6SAneesh Kumar K.V static p9_handler *virtio_9p_dotl_handler [] = { 1210c797b6c6SAneesh Kumar K.V [P9_TREADDIR] = virtio_p9_readdir, 1211c797b6c6SAneesh Kumar K.V [P9_TSTATFS] = virtio_p9_statfs, 1212c797b6c6SAneesh Kumar K.V [P9_TGETATTR] = virtio_p9_getattr, 1213c797b6c6SAneesh Kumar K.V [P9_TSETATTR] = virtio_p9_setattr, 1214c797b6c6SAneesh Kumar K.V [P9_TXATTRWALK] = virtio_p9_eopnotsupp, 1215c797b6c6SAneesh Kumar K.V [P9_TXATTRCREATE] = virtio_p9_eopnotsupp, 1216c797b6c6SAneesh Kumar K.V [P9_TMKNOD] = virtio_p9_mknod, 1217c797b6c6SAneesh Kumar K.V [P9_TLOCK] = virtio_p9_lock, 1218c797b6c6SAneesh Kumar K.V [P9_TGETLOCK] = virtio_p9_getlock, 1219c797b6c6SAneesh Kumar K.V [P9_TRENAMEAT] = virtio_p9_renameat, 1220c797b6c6SAneesh Kumar K.V [P9_TREADLINK] = virtio_p9_readlink, 1221c797b6c6SAneesh Kumar K.V [P9_TUNLINKAT] = virtio_p9_unlinkat, 1222c797b6c6SAneesh Kumar K.V [P9_TMKDIR] = virtio_p9_mkdir, 1223b4422bf3SAneesh Kumar K.V [P9_TVERSION] = virtio_p9_version, 1224c797b6c6SAneesh Kumar K.V [P9_TLOPEN] = virtio_p9_open, 1225b4422bf3SAneesh Kumar K.V [P9_TATTACH] = virtio_p9_attach, 1226b4422bf3SAneesh Kumar K.V [P9_TWALK] = virtio_p9_walk, 1227c797b6c6SAneesh Kumar K.V [P9_TCLUNK] = virtio_p9_clunk, 1228c797b6c6SAneesh Kumar K.V [P9_TFSYNC] = virtio_p9_fsync, 1229b4422bf3SAneesh Kumar K.V [P9_TREAD] = virtio_p9_read, 12305cc808aaSSasha Levin [P9_TFLUSH] = virtio_p9_flush, 1231c797b6c6SAneesh Kumar K.V [P9_TLINK] = virtio_p9_link, 1232c797b6c6SAneesh Kumar K.V [P9_TSYMLINK] = virtio_p9_symlink, 1233c797b6c6SAneesh Kumar K.V [P9_TLCREATE] = virtio_p9_create, 1234b4422bf3SAneesh Kumar K.V [P9_TWRITE] = virtio_p9_write, 12356fc5cd9bSSasha Levin [P9_TREMOVE] = virtio_p9_remove, 1236f161f28bSSasha Levin [P9_TRENAME] = virtio_p9_rename, 1237b4422bf3SAneesh Kumar K.V }; 1238b4422bf3SAneesh Kumar K.V 1239af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq) 1240af045e53SAneesh Kumar K.V { 1241af045e53SAneesh Kumar K.V struct p9_pdu *pdu = calloc(1, sizeof(*pdu)); 1242af045e53SAneesh Kumar K.V if (!pdu) 1243af045e53SAneesh Kumar K.V return NULL; 1244af045e53SAneesh Kumar K.V 1245bfc15268SAneesh Kumar K.V /* skip the pdu header p9_msg */ 12465529bcd7SAsias He pdu->read_offset = VIRTIO_9P_HDR_LEN; 12475529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 1248af045e53SAneesh Kumar K.V pdu->queue_head = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov, 1249a8a44649SAsias He pdu->out_iov, &pdu->in_iov_cnt, &pdu->out_iov_cnt); 1250af045e53SAneesh Kumar K.V return pdu; 1251af045e53SAneesh Kumar K.V } 1252af045e53SAneesh Kumar K.V 1253af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu) 1254af045e53SAneesh Kumar K.V { 1255af045e53SAneesh Kumar K.V struct p9_msg *msg; 1256af045e53SAneesh Kumar K.V /* 1257af045e53SAneesh Kumar K.V * we can peek directly into pdu for a u8 1258af045e53SAneesh Kumar K.V * value. The host endianess won't be an issue 1259af045e53SAneesh Kumar K.V */ 1260af045e53SAneesh Kumar K.V msg = pdu->out_iov[0].iov_base; 1261af045e53SAneesh Kumar K.V return msg->cmd; 1262af045e53SAneesh Kumar K.V } 1263af045e53SAneesh Kumar K.V 1264b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job) 12651c7850f9SSasha Levin { 1266af045e53SAneesh Kumar K.V u8 cmd; 1267b4422bf3SAneesh Kumar K.V u32 len = 0; 1268b4422bf3SAneesh Kumar K.V p9_handler *handler; 1269b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 1270af045e53SAneesh Kumar K.V struct virt_queue *vq; 1271af045e53SAneesh Kumar K.V struct p9_pdu *p9pdu; 12721c7850f9SSasha Levin 1273b4422bf3SAneesh Kumar K.V vq = job->vq; 1274b4422bf3SAneesh Kumar K.V p9dev = job->p9dev; 12751c7850f9SSasha Levin 1276af045e53SAneesh Kumar K.V p9pdu = virtio_p9_pdu_init(kvm, vq); 1277af045e53SAneesh Kumar K.V cmd = virtio_p9_get_cmd(p9pdu); 1278af045e53SAneesh Kumar K.V 1279c797b6c6SAneesh Kumar K.V if ((cmd >= ARRAY_SIZE(virtio_9p_dotl_handler)) || 1280c797b6c6SAneesh Kumar K.V !virtio_9p_dotl_handler[cmd]) 128197b408afSAneesh Kumar K.V handler = virtio_p9_eopnotsupp; 1282dd78d9eaSAneesh Kumar K.V else 1283c797b6c6SAneesh Kumar K.V handler = virtio_9p_dotl_handler[cmd]; 1284c797b6c6SAneesh Kumar K.V 1285af045e53SAneesh Kumar K.V handler(p9dev, p9pdu, &len); 1286af045e53SAneesh Kumar K.V virt_queue__set_used_elem(vq, p9pdu->queue_head, len); 1287af045e53SAneesh Kumar K.V free(p9pdu); 12881c7850f9SSasha Levin return true; 12891c7850f9SSasha Levin } 12901c7850f9SSasha Levin 12911c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param) 12921c7850f9SSasha Levin { 1293b4422bf3SAneesh Kumar K.V struct p9_dev_job *job = (struct p9_dev_job *)param; 1294b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = job->p9dev; 1295b4422bf3SAneesh Kumar K.V struct virt_queue *vq = job->vq; 12961c7850f9SSasha Levin 12971c7850f9SSasha Levin while (virt_queue__available(vq)) { 1298b4422bf3SAneesh Kumar K.V virtio_p9_do_io_request(kvm, job); 129902eca50cSAsias He p9dev->vdev.ops->signal_vq(kvm, &p9dev->vdev, vq - p9dev->vqs); 13001c7850f9SSasha Levin } 13011c7850f9SSasha Levin } 13021c7850f9SSasha Levin 1303c5ae742bSSasha Levin static u8 *get_config(struct kvm *kvm, void *dev) 13041c7850f9SSasha Levin { 1305c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 13061c7850f9SSasha Levin 1307c5ae742bSSasha Levin return ((u8 *)(p9dev->config)); 1308c7838fbdSSasha Levin } 1309c7838fbdSSasha Levin 1310c7838fbdSSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev) 1311c7838fbdSSasha Levin { 1312c7838fbdSSasha Levin return 1 << VIRTIO_9P_MOUNT_TAG; 1313c7838fbdSSasha Levin } 1314c7838fbdSSasha Levin 1315c7838fbdSSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features) 1316c7838fbdSSasha Levin { 1317c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1318e0ea1859SMarc Zyngier struct virtio_9p_config *conf = p9dev->config; 1319c7838fbdSSasha Levin 1320c7838fbdSSasha Levin p9dev->features = features; 1321e0ea1859SMarc Zyngier conf->tag_len = virtio_host_to_guest_u16(&p9dev->vdev, conf->tag_len); 1322c7838fbdSSasha Levin } 1323c7838fbdSSasha Levin 1324c59ba304SWill Deacon static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align, 1325c59ba304SWill Deacon u32 pfn) 1326c7838fbdSSasha Levin { 1327c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1328b4422bf3SAneesh Kumar K.V struct p9_dev_job *job; 1329b4422bf3SAneesh Kumar K.V struct virt_queue *queue; 1330c7838fbdSSasha Levin void *p; 13311c7850f9SSasha Levin 1332312c62d1SSasha Levin compat__remove_message(compat_id); 1333e59662b3SSasha Levin 1334c7838fbdSSasha Levin queue = &p9dev->vqs[vq]; 1335c7838fbdSSasha Levin queue->pfn = pfn; 1336e7e2950aSSasha Levin p = virtio_get_vq(kvm, queue->pfn, page_size); 1337c7838fbdSSasha Levin job = &p9dev->jobs[vq]; 13381c7850f9SSasha Levin 1339c59ba304SWill Deacon vring_init(&queue->vring, VIRTQUEUE_NUM, p, align); 1340e0ea1859SMarc Zyngier virtio_init_device_vq(&p9dev->vdev, queue); 13411c7850f9SSasha Levin 1342b4422bf3SAneesh Kumar K.V *job = (struct p9_dev_job) { 1343b4422bf3SAneesh Kumar K.V .vq = queue, 1344b4422bf3SAneesh Kumar K.V .p9dev = p9dev, 1345b4422bf3SAneesh Kumar K.V }; 1346df0c7f57SSasha Levin thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job); 134760eb42d5SSasha Levin 1348c7838fbdSSasha Levin return 0; 13491c7850f9SSasha Levin } 13501c7850f9SSasha Levin 1351c7838fbdSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 1352c7838fbdSSasha Levin { 1353c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 13541c7850f9SSasha Levin 1355c7838fbdSSasha Levin thread_pool__do_job(&p9dev->jobs[vq].job_id); 1356c7838fbdSSasha Levin 1357c7838fbdSSasha Levin return 0; 1358c7838fbdSSasha Levin } 1359c7838fbdSSasha Levin 1360c7838fbdSSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq) 1361c7838fbdSSasha Levin { 1362c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1363c7838fbdSSasha Levin 1364c7838fbdSSasha Levin return p9dev->vqs[vq].pfn; 1365c7838fbdSSasha Levin } 1366c7838fbdSSasha Levin 1367c7838fbdSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 1368c7838fbdSSasha Levin { 1369c7838fbdSSasha Levin return VIRTQUEUE_NUM; 1370c7838fbdSSasha Levin } 1371c7838fbdSSasha Levin 13727aba29c1SWill Deacon static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size) 13737aba29c1SWill Deacon { 13747aba29c1SWill Deacon /* FIXME: dynamic */ 13757aba29c1SWill Deacon return size; 13767aba29c1SWill Deacon } 13777aba29c1SWill Deacon 137815542babSAndre Przywara struct virtio_ops p9_dev_virtio_ops = { 1379c7838fbdSSasha Levin .get_config = get_config, 1380c7838fbdSSasha Levin .get_host_features = get_host_features, 1381c7838fbdSSasha Levin .set_guest_features = set_guest_features, 1382c7838fbdSSasha Levin .init_vq = init_vq, 1383c7838fbdSSasha Levin .notify_vq = notify_vq, 1384c7838fbdSSasha Levin .get_pfn_vq = get_pfn_vq, 1385c7838fbdSSasha Levin .get_size_vq = get_size_vq, 13867aba29c1SWill Deacon .set_size_vq = set_size_vq, 1387c7838fbdSSasha Levin }; 13881c47ce69SSasha Levin 1389cac9e8fdSSasha Levin int virtio_9p_rootdir_parser(const struct option *opt, const char *arg, int unset) 1390cac9e8fdSSasha Levin { 1391cac9e8fdSSasha Levin char *tag_name; 1392cac9e8fdSSasha Levin char tmp[PATH_MAX]; 1393cac9e8fdSSasha Levin struct kvm *kvm = opt->ptr; 1394cac9e8fdSSasha Levin 1395cac9e8fdSSasha Levin /* 1396cac9e8fdSSasha Levin * 9p dir can be of the form dirname,tag_name or 1397cac9e8fdSSasha Levin * just dirname. In the later case we use the 1398cac9e8fdSSasha Levin * default tag name 1399cac9e8fdSSasha Levin */ 1400cac9e8fdSSasha Levin tag_name = strstr(arg, ","); 1401cac9e8fdSSasha Levin if (tag_name) { 1402cac9e8fdSSasha Levin *tag_name = '\0'; 1403cac9e8fdSSasha Levin tag_name++; 1404cac9e8fdSSasha Levin } 1405cac9e8fdSSasha Levin if (realpath(arg, tmp)) { 1406cac9e8fdSSasha Levin if (virtio_9p__register(kvm, tmp, tag_name) < 0) 1407cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1408cac9e8fdSSasha Levin } else 1409cac9e8fdSSasha Levin die("Failed resolving 9p path"); 1410cac9e8fdSSasha Levin return 0; 1411cac9e8fdSSasha Levin } 1412cac9e8fdSSasha Levin 1413cac9e8fdSSasha Levin int virtio_9p_img_name_parser(const struct option *opt, const char *arg, int unset) 1414cac9e8fdSSasha Levin { 1415cac9e8fdSSasha Levin char path[PATH_MAX]; 1416cac9e8fdSSasha Levin struct stat st; 1417cac9e8fdSSasha Levin struct kvm *kvm = opt->ptr; 1418cac9e8fdSSasha Levin 1419cac9e8fdSSasha Levin if (stat(arg, &st) == 0 && 1420cac9e8fdSSasha Levin S_ISDIR(st.st_mode)) { 1421cac9e8fdSSasha Levin char tmp[PATH_MAX]; 1422cac9e8fdSSasha Levin 1423cac9e8fdSSasha Levin if (kvm->cfg.using_rootfs) 1424cac9e8fdSSasha Levin die("Please use only one rootfs directory atmost"); 1425cac9e8fdSSasha Levin 1426cac9e8fdSSasha Levin if (realpath(arg, tmp) == 0 || 1427cac9e8fdSSasha Levin virtio_9p__register(kvm, tmp, "/dev/root") < 0) 1428cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1429cac9e8fdSSasha Levin kvm->cfg.using_rootfs = 1; 1430cac9e8fdSSasha Levin return 0; 1431cac9e8fdSSasha Levin } 1432cac9e8fdSSasha Levin 1433cac9e8fdSSasha Levin snprintf(path, PATH_MAX, "%s%s", kvm__get_dir(), arg); 1434cac9e8fdSSasha Levin 1435cac9e8fdSSasha Levin if (stat(path, &st) == 0 && 1436cac9e8fdSSasha Levin S_ISDIR(st.st_mode)) { 1437cac9e8fdSSasha Levin char tmp[PATH_MAX]; 1438cac9e8fdSSasha Levin 1439cac9e8fdSSasha Levin if (kvm->cfg.using_rootfs) 1440cac9e8fdSSasha Levin die("Please use only one rootfs directory atmost"); 1441cac9e8fdSSasha Levin 1442cac9e8fdSSasha Levin if (realpath(path, tmp) == 0 || 1443cac9e8fdSSasha Levin virtio_9p__register(kvm, tmp, "/dev/root") < 0) 1444cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1445cac9e8fdSSasha Levin if (virtio_9p__register(kvm, "/", "hostfs") < 0) 1446cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1447cac9e8fdSSasha Levin kvm_setup_resolv(arg); 1448cac9e8fdSSasha Levin kvm->cfg.using_rootfs = kvm->cfg.custom_rootfs = 1; 1449cac9e8fdSSasha Levin kvm->cfg.custom_rootfs_name = arg; 1450cac9e8fdSSasha Levin return 0; 1451cac9e8fdSSasha Levin } 1452cac9e8fdSSasha Levin 1453cac9e8fdSSasha Levin return -1; 1454cac9e8fdSSasha Levin } 1455cac9e8fdSSasha Levin 14561c47ce69SSasha Levin int virtio_9p__init(struct kvm *kvm) 14571c47ce69SSasha Levin { 14581c47ce69SSasha Levin struct p9_dev *p9dev; 14591c47ce69SSasha Levin 14601c47ce69SSasha Levin list_for_each_entry(p9dev, &devs, list) { 146102eca50cSAsias He virtio_init(kvm, p9dev, &p9dev->vdev, &p9_dev_virtio_ops, 1462d97dadecSWill Deacon VIRTIO_DEFAULT_TRANS(kvm), PCI_DEVICE_ID_VIRTIO_9P, 1463ae06ce71SWill Deacon VIRTIO_ID_9P, PCI_CLASS_9P); 1464c7838fbdSSasha Levin } 1465c7838fbdSSasha Levin 1466c7838fbdSSasha Levin return 0; 1467c7838fbdSSasha Levin } 146849a8afd1SSasha Levin virtio_dev_init(virtio_9p__init); 1469c7838fbdSSasha Levin 1470c7838fbdSSasha Levin int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name) 1471c7838fbdSSasha Levin { 1472c7838fbdSSasha Levin struct p9_dev *p9dev; 147354f6802dSPekka Enberg int err = 0; 14741c7850f9SSasha Levin 1475b4422bf3SAneesh Kumar K.V p9dev = calloc(1, sizeof(*p9dev)); 1476b4422bf3SAneesh Kumar K.V if (!p9dev) 147754f6802dSPekka Enberg return -ENOMEM; 147854f6802dSPekka Enberg 1479b4422bf3SAneesh Kumar K.V if (!tag_name) 14805529bcd7SAsias He tag_name = VIRTIO_9P_DEFAULT_TAG; 148154f6802dSPekka Enberg 1482b4422bf3SAneesh Kumar K.V p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1); 148354f6802dSPekka Enberg if (p9dev->config == NULL) { 148454f6802dSPekka Enberg err = -ENOMEM; 1485b4422bf3SAneesh Kumar K.V goto free_p9dev; 148654f6802dSPekka Enberg } 14871c7850f9SSasha Levin 1488b4422bf3SAneesh Kumar K.V strcpy(p9dev->root_dir, root); 1489b4422bf3SAneesh Kumar K.V p9dev->config->tag_len = strlen(tag_name); 149054f6802dSPekka Enberg if (p9dev->config->tag_len > MAX_TAG_LEN) { 149154f6802dSPekka Enberg err = -EINVAL; 1492b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 149354f6802dSPekka Enberg } 14941c7850f9SSasha Levin 1495c7838fbdSSasha Levin memcpy(&p9dev->config->tag, tag_name, strlen(tag_name)); 14961c7850f9SSasha Levin 1497c7838fbdSSasha Levin list_add(&p9dev->list, &devs); 1498b4422bf3SAneesh Kumar K.V 1499d278197dSAsias He if (compat_id == -1) 150052f34d2cSAsias He compat_id = virtio_compat_add_message("virtio-9p", "CONFIG_NET_9P_VIRTIO"); 1501e59662b3SSasha Levin 150254f6802dSPekka Enberg return err; 150354f6802dSPekka Enberg 1504b4422bf3SAneesh Kumar K.V free_p9dev_config: 1505b4422bf3SAneesh Kumar K.V free(p9dev->config); 1506b4422bf3SAneesh Kumar K.V free_p9dev: 1507b4422bf3SAneesh Kumar K.V free(p9dev); 150854f6802dSPekka Enberg return err; 15091c7850f9SSasha Levin } 1510