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> 21623682beSMarc Zyngier #include <linux/uidgid.h> 222daa28d4SAneesh Kumar K.V #include <net/9p/9p.h> 232daa28d4SAneesh Kumar K.V 24c7838fbdSSasha Levin static LIST_HEAD(devs); 25312c62d1SSasha Levin static int compat_id = -1; 26c7838fbdSSasha Levin 27e2341580SSasha Levin static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid); 28e2341580SSasha Levin static struct p9_fid *find_or_create_fid(struct p9_dev *dev, u32 fid) 29e2341580SSasha Levin { 30e2341580SSasha Levin struct rb_node *node = dev->fids.rb_node; 31e2341580SSasha Levin struct p9_fid *pfid = NULL; 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 49e2341580SSasha Levin pfid->fid = fid; 50e2341580SSasha Levin strcpy(pfid->abs_path, dev->root_dir); 51e2341580SSasha Levin pfid->path = pfid->abs_path + strlen(dev->root_dir); 52e2341580SSasha Levin 53e2341580SSasha Levin insert_new_fid(dev, pfid); 54e2341580SSasha Levin 55e2341580SSasha Levin return pfid; 56e2341580SSasha Levin } 57e2341580SSasha Levin 58e2341580SSasha Levin static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid) 59e2341580SSasha Levin { 60e2341580SSasha Levin struct rb_node **node = &(dev->fids.rb_node), *parent = NULL; 61e2341580SSasha Levin 62e2341580SSasha Levin while (*node) { 63e2341580SSasha Levin int result = fid->fid - rb_entry(*node, struct p9_fid, node)->fid; 64e2341580SSasha Levin 65e2341580SSasha Levin parent = *node; 66e2341580SSasha Levin if (result < 0) 67e2341580SSasha Levin node = &((*node)->rb_left); 68e2341580SSasha Levin else if (result > 0) 69e2341580SSasha Levin node = &((*node)->rb_right); 70e2341580SSasha Levin else 71e2341580SSasha Levin return -EEXIST; 72e2341580SSasha Levin } 73e2341580SSasha Levin 74e2341580SSasha Levin rb_link_node(&fid->node, parent, node); 75e2341580SSasha Levin rb_insert_color(&fid->node, &dev->fids); 76e2341580SSasha Levin return 0; 77e2341580SSasha Levin } 78e2341580SSasha Levin 7931a6fb8dSSasha Levin static struct p9_fid *get_fid(struct p9_dev *p9dev, int fid) 8031a6fb8dSSasha Levin { 81e2341580SSasha Levin struct p9_fid *new; 8231a6fb8dSSasha Levin 83e2341580SSasha Levin new = find_or_create_fid(p9dev, fid); 84e2341580SSasha Levin 85e2341580SSasha Levin return new; 8631a6fb8dSSasha Levin } 8731a6fb8dSSasha Levin 881c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */ 89b4422bf3SAneesh Kumar K.V static const char *rel_to_abs(struct p9_dev *p9dev, 90b4422bf3SAneesh Kumar K.V const char *path, char *abs_path) 911c7850f9SSasha Levin { 92b4422bf3SAneesh Kumar K.V sprintf(abs_path, "%s/%s", p9dev->root_dir, path); 931c7850f9SSasha Levin 941c7850f9SSasha Levin return abs_path; 951c7850f9SSasha Levin } 961c7850f9SSasha Levin 97c797b6c6SAneesh Kumar K.V static void stat2qid(struct stat *st, struct p9_qid *qid) 981c7850f9SSasha Levin { 991c7850f9SSasha Levin *qid = (struct p9_qid) { 1001c7850f9SSasha Levin .path = st->st_ino, 1011c7850f9SSasha Levin .version = st->st_mtime, 1021c7850f9SSasha Levin }; 1031c7850f9SSasha Levin 1041c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) 1051c7850f9SSasha Levin qid->type |= P9_QTDIR; 1061c7850f9SSasha Levin } 1071c7850f9SSasha Levin 108b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid) 1091c7850f9SSasha Levin { 110e2341580SSasha Levin struct p9_fid *pfid = get_fid(p9dev, fid); 111e2341580SSasha Levin 112e2341580SSasha Levin if (pfid->fd > 0) 113e2341580SSasha Levin close(pfid->fd); 114e2341580SSasha Levin 115e2341580SSasha Levin if (pfid->dir) 116e2341580SSasha Levin closedir(pfid->dir); 117e2341580SSasha Levin 118e2341580SSasha Levin rb_erase(&pfid->node, &p9dev->fids); 119e2341580SSasha Levin free(pfid); 1201c7850f9SSasha Levin } 121e2341580SSasha Levin 122bfc15268SAneesh Kumar K.V static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size) 1231c7850f9SSasha Levin { 124bfc15268SAneesh Kumar K.V u8 cmd; 125bfc15268SAneesh Kumar K.V u16 tag; 126bfc15268SAneesh Kumar K.V 127bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32); 128bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag); 129bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 130bfc15268SAneesh Kumar K.V /* cmd + 1 is the reply message */ 131bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag); 1321c7850f9SSasha Levin } 1331c7850f9SSasha Levin 1346b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt) 1356b163a87SAneesh Kumar K.V { 1366b163a87SAneesh Kumar K.V int i; 1376b163a87SAneesh Kumar K.V u32 total = 0; 1386b163a87SAneesh Kumar K.V for (i = 0; (i < iov_cnt) && (total < count); i++) { 1396b163a87SAneesh Kumar K.V if (total + iov[i].iov_len > count) { 1406b163a87SAneesh Kumar K.V /* we don't need this iov fully */ 1416b163a87SAneesh Kumar K.V iov[i].iov_len -= ((total + iov[i].iov_len) - count); 1426b163a87SAneesh Kumar K.V i++; 1436b163a87SAneesh Kumar K.V break; 1446b163a87SAneesh Kumar K.V } 1456b163a87SAneesh Kumar K.V total += iov[i].iov_len; 1466b163a87SAneesh Kumar K.V } 1476b163a87SAneesh Kumar K.V return i; 1486b163a87SAneesh Kumar K.V } 1496b163a87SAneesh Kumar K.V 150eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev, 151eee1ba8eSAneesh Kumar K.V struct p9_pdu *pdu, int err, u32 *outlen) 152eee1ba8eSAneesh Kumar K.V { 153bfc15268SAneesh Kumar K.V u16 tag; 154eee1ba8eSAneesh Kumar K.V 1555529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 156c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", err); 157bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 158eee1ba8eSAneesh Kumar K.V 159c797b6c6SAneesh Kumar K.V /* read the tag from input */ 160bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32) + sizeof(u8); 161bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "w", &tag); 162bfc15268SAneesh Kumar K.V 163c797b6c6SAneesh Kumar K.V /* Update the header */ 164bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 165c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RLERROR, tag); 166eee1ba8eSAneesh Kumar K.V } 167eee1ba8eSAneesh Kumar K.V 168ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev, 169af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1701c7850f9SSasha Levin { 171c797b6c6SAneesh Kumar K.V u32 msize; 172c797b6c6SAneesh Kumar K.V char *version; 173c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ds", &msize, &version); 174c797b6c6SAneesh Kumar K.V /* 175c797b6c6SAneesh Kumar K.V * reply with the same msize the client sent us 176c797b6c6SAneesh Kumar K.V * Error out if the request is not for 9P2000.L 177c797b6c6SAneesh Kumar K.V */ 1785529bcd7SAsias He if (!strcmp(version, VIRTIO_9P_VERSION_DOTL)) 179c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, version); 180c797b6c6SAneesh Kumar K.V else 181c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, "unknown"); 1821c7850f9SSasha Levin 183bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 184bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 185c797b6c6SAneesh Kumar K.V free(version); 186ead43b01SAneesh Kumar K.V return; 1871c7850f9SSasha Levin } 1881c7850f9SSasha Levin 189ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev, 190af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1911c7850f9SSasha Levin { 192bfc15268SAneesh Kumar K.V u32 fid; 1931c7850f9SSasha Levin 194bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid); 195bfc15268SAneesh Kumar K.V close_fid(p9dev, fid); 1961c7850f9SSasha Levin 197bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 198bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 199ead43b01SAneesh Kumar K.V return; 2001c7850f9SSasha Levin } 2011c7850f9SSasha Levin 202c797b6c6SAneesh Kumar K.V /* 203c797b6c6SAneesh Kumar K.V * FIXME!! Need to map to protocol independent value. Upstream 204c797b6c6SAneesh Kumar K.V * 9p also have the same BUG 205c797b6c6SAneesh Kumar K.V */ 206c797b6c6SAneesh Kumar K.V static int virtio_p9_openflags(int flags) 207c797b6c6SAneesh Kumar K.V { 208c797b6c6SAneesh Kumar K.V flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT | O_DIRECT); 209c797b6c6SAneesh Kumar K.V flags |= O_NOFOLLOW; 210c797b6c6SAneesh Kumar K.V return flags; 211c797b6c6SAneesh Kumar K.V } 212c797b6c6SAneesh Kumar K.V 21332585666SSasha Levin static bool is_dir(struct p9_fid *fid) 21432585666SSasha Levin { 21532585666SSasha Levin struct stat st; 21632585666SSasha Levin 21732585666SSasha Levin stat(fid->abs_path, &st); 21832585666SSasha Levin 21932585666SSasha Levin return S_ISDIR(st.st_mode); 22032585666SSasha Levin } 22132585666SSasha Levin 222ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev, 223af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2241c7850f9SSasha Levin { 225c797b6c6SAneesh Kumar K.V u32 fid, flags; 2261c7850f9SSasha Levin struct stat st; 227bfc15268SAneesh Kumar K.V struct p9_qid qid; 228bfc15268SAneesh Kumar K.V struct p9_fid *new_fid; 229bfc15268SAneesh Kumar K.V 230c797b6c6SAneesh Kumar K.V 231c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid, &flags); 23231a6fb8dSSasha Levin new_fid = get_fid(p9dev, fid); 2331c7850f9SSasha Levin 23430204a77SAneesh Kumar K.V if (lstat(new_fid->abs_path, &st) < 0) 235eee1ba8eSAneesh Kumar K.V goto err_out; 2361c7850f9SSasha Levin 237c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 2381c7850f9SSasha Levin 23932585666SSasha Levin if (is_dir(new_fid)) { 2401c7850f9SSasha Levin new_fid->dir = opendir(new_fid->abs_path); 241eee1ba8eSAneesh Kumar K.V if (!new_fid->dir) 242eee1ba8eSAneesh Kumar K.V goto err_out; 243eee1ba8eSAneesh Kumar K.V } else { 244eee1ba8eSAneesh Kumar K.V new_fid->fd = open(new_fid->abs_path, 245c797b6c6SAneesh Kumar K.V virtio_p9_openflags(flags)); 246eee1ba8eSAneesh Kumar K.V if (new_fid->fd < 0) 247eee1ba8eSAneesh Kumar K.V goto err_out; 248eee1ba8eSAneesh Kumar K.V } 249c797b6c6SAneesh Kumar K.V /* FIXME!! need ot send proper iounit */ 250bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 251bfc15268SAneesh Kumar K.V 252bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 253bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 254ead43b01SAneesh Kumar K.V return; 255eee1ba8eSAneesh Kumar K.V err_out: 256eee1ba8eSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 257ead43b01SAneesh Kumar K.V return; 2581c7850f9SSasha Levin } 2591c7850f9SSasha Levin 260ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev, 261af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2621c7850f9SSasha Levin { 263c797b6c6SAneesh Kumar K.V int fd, ret; 264bfc15268SAneesh Kumar K.V char *name; 265af045e53SAneesh Kumar K.V struct stat st; 266bfc15268SAneesh Kumar K.V struct p9_qid qid; 267c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 2684bc9734aSAneesh Kumar K.V char full_path[PATH_MAX]; 269c797b6c6SAneesh Kumar K.V u32 dfid_val, flags, mode, gid; 270af045e53SAneesh Kumar K.V 271c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsddd", &dfid_val, 272c797b6c6SAneesh Kumar K.V &name, &flags, &mode, &gid); 27331a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 2741c7850f9SSasha Levin 275c797b6c6SAneesh Kumar K.V flags = virtio_p9_openflags(flags); 2765f900f6dSSasha Levin 277c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 278c797b6c6SAneesh Kumar K.V fd = open(full_path, flags | O_CREAT, mode); 2794bc9734aSAneesh Kumar K.V if (fd < 0) 2804bc9734aSAneesh Kumar K.V goto err_out; 281c797b6c6SAneesh Kumar K.V dfid->fd = fd; 282c797b6c6SAneesh Kumar K.V 2834bc9734aSAneesh Kumar K.V if (lstat(full_path, &st) < 0) 2846c8ca053SAneesh Kumar K.V goto err_out; 2851c7850f9SSasha Levin 286c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 287c797b6c6SAneesh Kumar K.V if (ret < 0) 288c797b6c6SAneesh Kumar K.V goto err_out; 289c797b6c6SAneesh Kumar K.V 290c797b6c6SAneesh Kumar K.V sprintf(dfid->path, "%s/%s", dfid->path, name); 291c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 292bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 293bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 294bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 2955f900f6dSSasha Levin free(name); 2966c8ca053SAneesh Kumar K.V return; 2976c8ca053SAneesh Kumar K.V err_out: 2985f900f6dSSasha Levin free(name); 299c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 300c797b6c6SAneesh Kumar K.V return; 301c797b6c6SAneesh Kumar K.V } 302c797b6c6SAneesh Kumar K.V 303c797b6c6SAneesh Kumar K.V static void virtio_p9_mkdir(struct p9_dev *p9dev, 304c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 305c797b6c6SAneesh Kumar K.V { 306c797b6c6SAneesh Kumar K.V int ret; 307c797b6c6SAneesh Kumar K.V char *name; 308c797b6c6SAneesh Kumar K.V struct stat st; 309c797b6c6SAneesh Kumar K.V struct p9_qid qid; 310c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 311c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 312c797b6c6SAneesh Kumar K.V u32 dfid_val, mode, gid; 313c797b6c6SAneesh Kumar K.V 314c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdd", &dfid_val, 315c797b6c6SAneesh Kumar K.V &name, &mode, &gid); 31631a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 317c797b6c6SAneesh Kumar K.V 318c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 319c797b6c6SAneesh Kumar K.V ret = mkdir(full_path, mode); 320c797b6c6SAneesh Kumar K.V if (ret < 0) 321c797b6c6SAneesh Kumar K.V goto err_out; 322c797b6c6SAneesh Kumar K.V 323c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0) 324c797b6c6SAneesh Kumar K.V goto err_out; 325c797b6c6SAneesh Kumar K.V 326c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 327c797b6c6SAneesh Kumar K.V if (ret < 0) 328c797b6c6SAneesh Kumar K.V goto err_out; 329c797b6c6SAneesh Kumar K.V 330c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 331c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 332c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 333c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 334c797b6c6SAneesh Kumar K.V free(name); 335c797b6c6SAneesh Kumar K.V return; 336c797b6c6SAneesh Kumar K.V err_out: 337c797b6c6SAneesh Kumar K.V free(name); 338c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 339ead43b01SAneesh Kumar K.V return; 3401c7850f9SSasha Levin } 3411c7850f9SSasha Levin 342ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev, 343af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 3441c7850f9SSasha Levin { 345af045e53SAneesh Kumar K.V u8 i; 346bfc15268SAneesh Kumar K.V u16 nwqid; 347bfc15268SAneesh Kumar K.V u16 nwname; 348bfc15268SAneesh Kumar K.V struct p9_qid wqid; 349e2341580SSasha Levin struct p9_fid *new_fid, *old_fid; 350c797b6c6SAneesh Kumar K.V u32 fid_val, newfid_val; 351c797b6c6SAneesh Kumar K.V 3521c7850f9SSasha Levin 353bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname); 35431a6fb8dSSasha Levin new_fid = get_fid(p9dev, newfid_val); 3551c7850f9SSasha Levin 356bfc15268SAneesh Kumar K.V nwqid = 0; 357bfc15268SAneesh Kumar K.V if (nwname) { 35831a6fb8dSSasha Levin struct p9_fid *fid = get_fid(p9dev, fid_val); 359bfc15268SAneesh Kumar K.V 360baac79a5SAneesh Kumar K.V strcpy(new_fid->path, fid->path); 361bfc15268SAneesh Kumar K.V /* skip the space for count */ 362bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 363bfc15268SAneesh Kumar K.V for (i = 0; i < nwname; i++) { 364bfc15268SAneesh Kumar K.V struct stat st; 3651c7850f9SSasha Levin char tmp[PATH_MAX] = {0}; 3661c7850f9SSasha Levin char full_path[PATH_MAX]; 367e55ed135SPekka Enberg char *str; 368bfc15268SAneesh Kumar K.V 369bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "s", &str); 3701c7850f9SSasha Levin 3711c7850f9SSasha Levin /* Format the new path we're 'walk'ing into */ 372baac79a5SAneesh Kumar K.V sprintf(tmp, "%s/%s", new_fid->path, str); 373e55ed135SPekka Enberg 374e55ed135SPekka Enberg free(str); 375e55ed135SPekka Enberg 376c797b6c6SAneesh Kumar K.V if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0) 3776c8ca053SAneesh Kumar K.V goto err_out; 3781c7850f9SSasha Levin 379c797b6c6SAneesh Kumar K.V stat2qid(&st, &wqid); 3801c7850f9SSasha Levin strcpy(new_fid->path, tmp); 381c797b6c6SAneesh Kumar K.V new_fid->uid = fid->uid; 382bfc15268SAneesh Kumar K.V nwqid++; 383bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &wqid); 3841c7850f9SSasha Levin } 3851c7850f9SSasha Levin } else { 386bfc15268SAneesh Kumar K.V /* 387bfc15268SAneesh Kumar K.V * update write_offset so our outlen get correct value 388bfc15268SAneesh Kumar K.V */ 389bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 390e2341580SSasha Levin old_fid = get_fid(p9dev, fid_val); 391e2341580SSasha Levin strcpy(new_fid->path, old_fid->path); 392e2341580SSasha Levin new_fid->uid = old_fid->uid; 3931c7850f9SSasha Levin } 394bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 3955529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 396bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", nwqid); 397bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 3986c8ca053SAneesh Kumar K.V return; 3996c8ca053SAneesh Kumar K.V err_out: 4006c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 401ead43b01SAneesh Kumar K.V return; 4021c7850f9SSasha Levin } 4031c7850f9SSasha Levin 404ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev, 405af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4061c7850f9SSasha Levin { 407bfc15268SAneesh Kumar K.V char *uname; 408bfc15268SAneesh Kumar K.V char *aname; 4091c7850f9SSasha Levin struct stat st; 410bfc15268SAneesh Kumar K.V struct p9_qid qid; 4111c7850f9SSasha Levin struct p9_fid *fid; 412c797b6c6SAneesh Kumar K.V u32 fid_val, afid, uid; 413bfc15268SAneesh Kumar K.V 414c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddssd", &fid_val, &afid, 415c797b6c6SAneesh Kumar K.V &uname, &aname, &uid); 4161c7850f9SSasha Levin 41739257180SPekka Enberg free(uname); 41839257180SPekka Enberg free(aname); 41939257180SPekka Enberg 42030204a77SAneesh Kumar K.V if (lstat(p9dev->root_dir, &st) < 0) 4216c8ca053SAneesh Kumar K.V goto err_out; 4221c7850f9SSasha Levin 423c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 4241c7850f9SSasha Levin 42531a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 426c797b6c6SAneesh Kumar K.V fid->uid = uid; 4271c7850f9SSasha Levin strcpy(fid->path, "/"); 4281c7850f9SSasha Levin 429bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 430bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 431bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 4326c8ca053SAneesh Kumar K.V return; 4336c8ca053SAneesh Kumar K.V err_out: 4346c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 435ead43b01SAneesh Kumar K.V return; 4361c7850f9SSasha Levin } 4371c7850f9SSasha Levin 438c797b6c6SAneesh Kumar K.V static void virtio_p9_fill_stat(struct p9_dev *p9dev, 439c797b6c6SAneesh Kumar K.V struct stat *st, struct p9_stat_dotl *statl) 4405f900f6dSSasha Levin { 441c797b6c6SAneesh Kumar K.V memset(statl, 0, sizeof(*statl)); 442c797b6c6SAneesh Kumar K.V statl->st_mode = st->st_mode; 443c797b6c6SAneesh Kumar K.V statl->st_nlink = st->st_nlink; 444506fd90bSSasha Levin statl->st_uid = KUIDT_INIT(st->st_uid); 445506fd90bSSasha Levin statl->st_gid = KGIDT_INIT(st->st_gid); 446c797b6c6SAneesh Kumar K.V statl->st_rdev = st->st_rdev; 447c797b6c6SAneesh Kumar K.V statl->st_size = st->st_size; 448c797b6c6SAneesh Kumar K.V statl->st_blksize = st->st_blksize; 449c797b6c6SAneesh Kumar K.V statl->st_blocks = st->st_blocks; 450c797b6c6SAneesh Kumar K.V statl->st_atime_sec = st->st_atime; 451c797b6c6SAneesh Kumar K.V statl->st_atime_nsec = st->st_atim.tv_nsec; 452c797b6c6SAneesh Kumar K.V statl->st_mtime_sec = st->st_mtime; 453c797b6c6SAneesh Kumar K.V statl->st_mtime_nsec = st->st_mtim.tv_nsec; 454c797b6c6SAneesh Kumar K.V statl->st_ctime_sec = st->st_ctime; 455c797b6c6SAneesh Kumar K.V statl->st_ctime_nsec = st->st_ctim.tv_nsec; 456c797b6c6SAneesh Kumar K.V /* Currently we only support BASIC fields in stat */ 457c797b6c6SAneesh Kumar K.V statl->st_result_mask = P9_STATS_BASIC; 458c797b6c6SAneesh Kumar K.V stat2qid(st, &statl->qid); 4591c7850f9SSasha Levin } 4601c7850f9SSasha Levin 461ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev, 462af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4631c7850f9SSasha Levin { 464bfc15268SAneesh Kumar K.V u64 offset; 465bfc15268SAneesh Kumar K.V u32 fid_val; 466c797b6c6SAneesh Kumar K.V u16 iov_cnt; 467c797b6c6SAneesh Kumar K.V void *iov_base; 468c797b6c6SAneesh Kumar K.V size_t iov_len; 469bfc15268SAneesh Kumar K.V u32 count, rcount; 470bfc15268SAneesh Kumar K.V struct p9_fid *fid; 471c797b6c6SAneesh Kumar K.V 4721c7850f9SSasha Levin 473bfc15268SAneesh Kumar K.V rcount = 0; 474bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 47531a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 47650c479e0SAneesh Kumar K.V 47750c479e0SAneesh Kumar K.V iov_base = pdu->in_iov[0].iov_base; 47850c479e0SAneesh Kumar K.V iov_len = pdu->in_iov[0].iov_len; 47950c479e0SAneesh Kumar K.V iov_cnt = pdu->in_iov_cnt; 4805529bcd7SAsias He pdu->in_iov[0].iov_base += VIRTIO_9P_HDR_LEN + sizeof(u32); 4815529bcd7SAsias He pdu->in_iov[0].iov_len -= VIRTIO_9P_HDR_LEN + sizeof(u32); 4826b163a87SAneesh Kumar K.V pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov, 483bfc15268SAneesh Kumar K.V count, 4846b163a87SAneesh Kumar K.V pdu->in_iov_cnt); 485bfc15268SAneesh Kumar K.V rcount = preadv(fid->fd, pdu->in_iov, 486bfc15268SAneesh Kumar K.V pdu->in_iov_cnt, offset); 487bfc15268SAneesh Kumar K.V if (rcount > count) 488bfc15268SAneesh Kumar K.V rcount = count; 489bfc15268SAneesh Kumar K.V /* 490bfc15268SAneesh Kumar K.V * Update the iov_base back, so that rest of 491bfc15268SAneesh Kumar K.V * pdu_writef works correctly. 492bfc15268SAneesh Kumar K.V */ 49350c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_base = iov_base; 49450c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_len = iov_len; 49550c479e0SAneesh Kumar K.V pdu->in_iov_cnt = iov_cnt; 496c797b6c6SAneesh Kumar K.V 4975529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 498bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 499bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 500bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 501ead43b01SAneesh Kumar K.V return; 5021c7850f9SSasha Levin } 5031c7850f9SSasha Levin 504c797b6c6SAneesh Kumar K.V static int virtio_p9_dentry_size(struct dirent *dent) 505c797b6c6SAneesh Kumar K.V { 506c797b6c6SAneesh Kumar K.V /* 507c797b6c6SAneesh Kumar K.V * Size of each dirent: 508c797b6c6SAneesh Kumar K.V * qid(13) + offset(8) + type(1) + name_len(2) + name 509c797b6c6SAneesh Kumar K.V */ 510c797b6c6SAneesh Kumar K.V return 24 + strlen(dent->d_name); 511c797b6c6SAneesh Kumar K.V } 512c797b6c6SAneesh Kumar K.V 513c797b6c6SAneesh Kumar K.V static void virtio_p9_readdir(struct p9_dev *p9dev, 514c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 515c797b6c6SAneesh Kumar K.V { 516c797b6c6SAneesh Kumar K.V u32 fid_val; 517c797b6c6SAneesh Kumar K.V u32 count, rcount; 518c797b6c6SAneesh Kumar K.V struct stat st; 519c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 520c797b6c6SAneesh Kumar K.V struct dirent *dent; 521c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 522c797b6c6SAneesh Kumar K.V u64 offset, old_offset; 523c797b6c6SAneesh Kumar K.V 524c797b6c6SAneesh Kumar K.V rcount = 0; 525c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 52631a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 527c797b6c6SAneesh Kumar K.V 52832585666SSasha Levin if (!is_dir(fid)) { 52969bb4278SSasha Levin errno = EINVAL; 530c797b6c6SAneesh Kumar K.V goto err_out; 531c797b6c6SAneesh Kumar K.V } 532c797b6c6SAneesh Kumar K.V 533c797b6c6SAneesh Kumar K.V /* Move the offset specified */ 534c797b6c6SAneesh Kumar K.V seekdir(fid->dir, offset); 535c797b6c6SAneesh Kumar K.V 536c797b6c6SAneesh Kumar K.V old_offset = offset; 537c797b6c6SAneesh Kumar K.V /* If reading a dir, fill the buffer with p9_stat entries */ 538c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir); 539c797b6c6SAneesh Kumar K.V 540c797b6c6SAneesh Kumar K.V /* Skip the space for writing count */ 541c797b6c6SAneesh Kumar K.V pdu->write_offset += sizeof(u32); 542c797b6c6SAneesh Kumar K.V while (dent) { 543c797b6c6SAneesh Kumar K.V u32 read; 544c797b6c6SAneesh Kumar K.V struct p9_qid qid; 545c797b6c6SAneesh Kumar K.V 546c797b6c6SAneesh Kumar K.V if ((rcount + virtio_p9_dentry_size(dent)) > count) { 547c797b6c6SAneesh Kumar K.V /* seek to the previous offset and return */ 548c797b6c6SAneesh Kumar K.V seekdir(fid->dir, old_offset); 549c797b6c6SAneesh Kumar K.V break; 550c797b6c6SAneesh Kumar K.V } 551c797b6c6SAneesh Kumar K.V old_offset = dent->d_off; 552c797b6c6SAneesh Kumar K.V lstat(rel_to_abs(p9dev, dent->d_name, full_path), &st); 553c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 554c797b6c6SAneesh Kumar K.V read = pdu->write_offset; 555c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qqbs", &qid, dent->d_off, 556c797b6c6SAneesh Kumar K.V dent->d_type, dent->d_name); 557c797b6c6SAneesh Kumar K.V rcount += pdu->write_offset - read; 558c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir); 559c797b6c6SAneesh Kumar K.V } 560c797b6c6SAneesh Kumar K.V 5615529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 562c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 563c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 564c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 565c797b6c6SAneesh Kumar K.V return; 566c797b6c6SAneesh Kumar K.V err_out: 567c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 568c797b6c6SAneesh Kumar K.V return; 569c797b6c6SAneesh Kumar K.V } 570c797b6c6SAneesh Kumar K.V 571c797b6c6SAneesh Kumar K.V 572c797b6c6SAneesh Kumar K.V static void virtio_p9_getattr(struct p9_dev *p9dev, 573af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5741c7850f9SSasha Levin { 575bfc15268SAneesh Kumar K.V u32 fid_val; 576af045e53SAneesh Kumar K.V struct stat st; 577c797b6c6SAneesh Kumar K.V u64 request_mask; 578bfc15268SAneesh Kumar K.V struct p9_fid *fid; 579c797b6c6SAneesh Kumar K.V struct p9_stat_dotl statl; 5801c7850f9SSasha Levin 581c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dq", &fid_val, &request_mask); 58231a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 58330204a77SAneesh Kumar K.V if (lstat(fid->abs_path, &st) < 0) 5846c8ca053SAneesh Kumar K.V goto err_out; 5851c7850f9SSasha Levin 586c797b6c6SAneesh Kumar K.V virtio_p9_fill_stat(p9dev, &st, &statl); 587c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "A", &statl); 588bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 589bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 590ead43b01SAneesh Kumar K.V return; 5916c8ca053SAneesh Kumar K.V err_out: 5926c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 5936c8ca053SAneesh Kumar K.V return; 5941c7850f9SSasha Levin } 5951c7850f9SSasha Levin 596c797b6c6SAneesh Kumar K.V /* FIXME!! from linux/fs.h */ 597c797b6c6SAneesh Kumar K.V /* 598c797b6c6SAneesh Kumar K.V * Attribute flags. These should be or-ed together to figure out what 599c797b6c6SAneesh Kumar K.V * has been changed! 600c797b6c6SAneesh Kumar K.V */ 601c797b6c6SAneesh Kumar K.V #define ATTR_MODE (1 << 0) 602c797b6c6SAneesh Kumar K.V #define ATTR_UID (1 << 1) 603c797b6c6SAneesh Kumar K.V #define ATTR_GID (1 << 2) 604c797b6c6SAneesh Kumar K.V #define ATTR_SIZE (1 << 3) 605c797b6c6SAneesh Kumar K.V #define ATTR_ATIME (1 << 4) 606c797b6c6SAneesh Kumar K.V #define ATTR_MTIME (1 << 5) 607c797b6c6SAneesh Kumar K.V #define ATTR_CTIME (1 << 6) 608c797b6c6SAneesh Kumar K.V #define ATTR_ATIME_SET (1 << 7) 609c797b6c6SAneesh Kumar K.V #define ATTR_MTIME_SET (1 << 8) 610c797b6c6SAneesh Kumar K.V #define ATTR_FORCE (1 << 9) /* Not a change, but a change it */ 611c797b6c6SAneesh Kumar K.V #define ATTR_ATTR_FLAG (1 << 10) 612c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SUID (1 << 11) 613c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SGID (1 << 12) 614c797b6c6SAneesh Kumar K.V #define ATTR_FILE (1 << 13) 615c797b6c6SAneesh Kumar K.V #define ATTR_KILL_PRIV (1 << 14) 616c797b6c6SAneesh Kumar K.V #define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ 617c797b6c6SAneesh Kumar K.V #define ATTR_TIMES_SET (1 << 16) 618c797b6c6SAneesh Kumar K.V 619c797b6c6SAneesh Kumar K.V #define ATTR_MASK 127 620c797b6c6SAneesh Kumar K.V 621c797b6c6SAneesh Kumar K.V static void virtio_p9_setattr(struct p9_dev *p9dev, 622af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 6231c7850f9SSasha Levin { 624c797b6c6SAneesh Kumar K.V int ret = 0; 625bfc15268SAneesh Kumar K.V u32 fid_val; 626bfc15268SAneesh Kumar K.V struct p9_fid *fid; 627c797b6c6SAneesh Kumar K.V struct p9_iattr_dotl p9attr; 6281c7850f9SSasha Levin 629c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dI", &fid_val, &p9attr); 63031a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 6311c7850f9SSasha Levin 632c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MODE) { 633c797b6c6SAneesh Kumar K.V ret = chmod(fid->abs_path, p9attr.mode); 634c797b6c6SAneesh Kumar K.V if (ret < 0) 635c797b6c6SAneesh Kumar K.V goto err_out; 636c797b6c6SAneesh Kumar K.V } 637c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_ATIME | ATTR_MTIME)) { 638c797b6c6SAneesh Kumar K.V struct timespec times[2]; 639c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME) { 640c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME_SET) { 641c797b6c6SAneesh Kumar K.V times[0].tv_sec = p9attr.atime_sec; 642c797b6c6SAneesh Kumar K.V times[0].tv_nsec = p9attr.atime_nsec; 643c797b6c6SAneesh Kumar K.V } else { 644c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_NOW; 645c797b6c6SAneesh Kumar K.V } 646c797b6c6SAneesh Kumar K.V } else { 647c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_OMIT; 648c797b6c6SAneesh Kumar K.V } 649c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME) { 650c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME_SET) { 651c797b6c6SAneesh Kumar K.V times[1].tv_sec = p9attr.mtime_sec; 652c797b6c6SAneesh Kumar K.V times[1].tv_nsec = p9attr.mtime_nsec; 653c797b6c6SAneesh Kumar K.V } else { 654c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_NOW; 655c797b6c6SAneesh Kumar K.V } 656c797b6c6SAneesh Kumar K.V } else 657c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_OMIT; 658c797b6c6SAneesh Kumar K.V 659c797b6c6SAneesh Kumar K.V ret = utimensat(-1, fid->abs_path, times, AT_SYMLINK_NOFOLLOW); 660c797b6c6SAneesh Kumar K.V if (ret < 0) 661c797b6c6SAneesh Kumar K.V goto err_out; 662c797b6c6SAneesh Kumar K.V } 663c797b6c6SAneesh Kumar K.V /* 664c797b6c6SAneesh Kumar K.V * If the only valid entry in iattr is ctime we can call 665c797b6c6SAneesh Kumar K.V * chown(-1,-1) to update the ctime of the file 666c797b6c6SAneesh Kumar K.V */ 667c797b6c6SAneesh Kumar K.V if ((p9attr.valid & (ATTR_UID | ATTR_GID)) || 668c797b6c6SAneesh Kumar K.V ((p9attr.valid & ATTR_CTIME) 669c797b6c6SAneesh Kumar K.V && !((p9attr.valid & ATTR_MASK) & ~ATTR_CTIME))) { 670c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_UID)) 671506fd90bSSasha Levin p9attr.uid = KUIDT_INIT(-1); 672c797b6c6SAneesh Kumar K.V 673c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_GID)) 674506fd90bSSasha Levin p9attr.gid = KGIDT_INIT(-1); 675c797b6c6SAneesh Kumar K.V 676506fd90bSSasha Levin ret = lchown(fid->abs_path, __kuid_val(p9attr.uid), 677506fd90bSSasha Levin __kgid_val(p9attr.gid)); 678c797b6c6SAneesh Kumar K.V if (ret < 0) 679c797b6c6SAneesh Kumar K.V goto err_out; 680c797b6c6SAneesh Kumar K.V } 681c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_SIZE)) { 682c797b6c6SAneesh Kumar K.V ret = truncate(fid->abs_path, p9attr.size); 683c797b6c6SAneesh Kumar K.V if (ret < 0) 684c797b6c6SAneesh Kumar K.V goto err_out; 685c797b6c6SAneesh Kumar K.V } 6865529bcd7SAsias He *outlen = VIRTIO_9P_HDR_LEN; 687bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 688ead43b01SAneesh Kumar K.V return; 6894bc9734aSAneesh Kumar K.V err_out: 6904bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 6914bc9734aSAneesh Kumar K.V return; 6921c7850f9SSasha Levin } 6931c7850f9SSasha Levin 694ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev, 695af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 6961c7850f9SSasha Levin { 6974bc9734aSAneesh Kumar K.V 698bfc15268SAneesh Kumar K.V u64 offset; 699bfc15268SAneesh Kumar K.V u32 fid_val; 7004bc9734aSAneesh Kumar K.V u32 count; 7014bc9734aSAneesh Kumar K.V ssize_t res; 70250c479e0SAneesh Kumar K.V u16 iov_cnt; 70350c479e0SAneesh Kumar K.V void *iov_base; 70450c479e0SAneesh Kumar K.V size_t iov_len; 705bfc15268SAneesh Kumar K.V struct p9_fid *fid; 706b064b05aSAneesh Kumar K.V /* u32 fid + u64 offset + u32 count */ 707b064b05aSAneesh Kumar K.V int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32); 7081c7850f9SSasha Levin 709bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 71031a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 711af045e53SAneesh Kumar K.V 71250c479e0SAneesh Kumar K.V iov_base = pdu->out_iov[0].iov_base; 71350c479e0SAneesh Kumar K.V iov_len = pdu->out_iov[0].iov_len; 71450c479e0SAneesh Kumar K.V iov_cnt = pdu->out_iov_cnt; 71550c479e0SAneesh Kumar K.V 716bfc15268SAneesh Kumar K.V /* Adjust the iovec to skip the header and meta data */ 717b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size); 718b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_len -= (sizeof(struct p9_msg) + twrite_size); 719bfc15268SAneesh Kumar K.V pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count, 7206b163a87SAneesh Kumar K.V pdu->out_iov_cnt); 7214bc9734aSAneesh Kumar K.V res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset); 72250c479e0SAneesh Kumar K.V /* 72350c479e0SAneesh Kumar K.V * Update the iov_base back, so that rest of 72450c479e0SAneesh Kumar K.V * pdu_readf works correctly. 72550c479e0SAneesh Kumar K.V */ 72650c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_base = iov_base; 72750c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_len = iov_len; 72850c479e0SAneesh Kumar K.V pdu->out_iov_cnt = iov_cnt; 729c797b6c6SAneesh Kumar K.V 7304bc9734aSAneesh Kumar K.V if (res < 0) 7314bc9734aSAneesh Kumar K.V goto err_out; 7324bc9734aSAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", res); 733bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 734bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 735ead43b01SAneesh Kumar K.V return; 7364bc9734aSAneesh Kumar K.V err_out: 7374bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 7384bc9734aSAneesh Kumar K.V return; 7391c7850f9SSasha Levin } 7401c7850f9SSasha Levin 7416fc5cd9bSSasha Levin static void virtio_p9_remove(struct p9_dev *p9dev, 7426fc5cd9bSSasha Levin struct p9_pdu *pdu, u32 *outlen) 7436fc5cd9bSSasha Levin { 7446fc5cd9bSSasha Levin int ret; 7456fc5cd9bSSasha Levin u32 fid_val; 7466fc5cd9bSSasha Levin struct p9_fid *fid; 7476fc5cd9bSSasha Levin 7486fc5cd9bSSasha Levin virtio_p9_pdu_readf(pdu, "d", &fid_val); 74931a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 7506fc5cd9bSSasha Levin 7519b604a9cSSasha Levin ret = remove(fid->abs_path); 7526fc5cd9bSSasha Levin if (ret < 0) 7536fc5cd9bSSasha Levin goto err_out; 7546fc5cd9bSSasha Levin *outlen = pdu->write_offset; 7556fc5cd9bSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 7566fc5cd9bSSasha Levin return; 7576fc5cd9bSSasha Levin 7586fc5cd9bSSasha Levin err_out: 7596fc5cd9bSSasha Levin virtio_p9_error_reply(p9dev, pdu, errno, outlen); 7606fc5cd9bSSasha Levin return; 7616fc5cd9bSSasha Levin } 7626fc5cd9bSSasha Levin 763f161f28bSSasha Levin static void virtio_p9_rename(struct p9_dev *p9dev, 764f161f28bSSasha Levin struct p9_pdu *pdu, u32 *outlen) 765f161f28bSSasha Levin { 766f161f28bSSasha Levin int ret; 767f161f28bSSasha Levin u32 fid_val, new_fid_val; 768f161f28bSSasha Levin struct p9_fid *fid, *new_fid; 769f161f28bSSasha Levin char full_path[PATH_MAX], *new_name; 770f161f28bSSasha Levin 771f161f28bSSasha Levin virtio_p9_pdu_readf(pdu, "dds", &fid_val, &new_fid_val, &new_name); 77231a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 77331a6fb8dSSasha Levin new_fid = get_fid(p9dev, new_fid_val); 774f161f28bSSasha Levin 775f161f28bSSasha Levin sprintf(full_path, "%s/%s", new_fid->abs_path, new_name); 776f161f28bSSasha Levin ret = rename(fid->abs_path, full_path); 777f161f28bSSasha Levin if (ret < 0) 778f161f28bSSasha Levin goto err_out; 779f161f28bSSasha Levin *outlen = pdu->write_offset; 780f161f28bSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 781f161f28bSSasha Levin return; 782f161f28bSSasha Levin 783f161f28bSSasha Levin err_out: 784f161f28bSSasha Levin virtio_p9_error_reply(p9dev, pdu, errno, outlen); 785f161f28bSSasha Levin return; 786f161f28bSSasha Levin } 787f161f28bSSasha Levin 788c797b6c6SAneesh Kumar K.V static void virtio_p9_readlink(struct p9_dev *p9dev, 789c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 790c797b6c6SAneesh Kumar K.V { 791c797b6c6SAneesh Kumar K.V int ret; 792c797b6c6SAneesh Kumar K.V u32 fid_val; 793c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 794c797b6c6SAneesh Kumar K.V char target_path[PATH_MAX]; 795c797b6c6SAneesh Kumar K.V 796c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 79731a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 798c797b6c6SAneesh Kumar K.V 799c797b6c6SAneesh Kumar K.V memset(target_path, 0, PATH_MAX); 800c797b6c6SAneesh Kumar K.V ret = readlink(fid->abs_path, target_path, PATH_MAX - 1); 801c797b6c6SAneesh Kumar K.V if (ret < 0) 802c797b6c6SAneesh Kumar K.V goto err_out; 803c797b6c6SAneesh Kumar K.V 804c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "s", target_path); 805c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 806c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 807c797b6c6SAneesh Kumar K.V return; 808c797b6c6SAneesh Kumar K.V err_out: 809c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 810c797b6c6SAneesh Kumar K.V return; 811c797b6c6SAneesh Kumar K.V } 812c797b6c6SAneesh Kumar K.V 813c797b6c6SAneesh Kumar K.V static void virtio_p9_statfs(struct p9_dev *p9dev, 814c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 815c797b6c6SAneesh Kumar K.V { 816c797b6c6SAneesh Kumar K.V int ret; 817c797b6c6SAneesh Kumar K.V u64 fsid; 818c797b6c6SAneesh Kumar K.V u32 fid_val; 819c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 820c797b6c6SAneesh Kumar K.V struct statfs stat_buf; 821c797b6c6SAneesh Kumar K.V 822c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 82331a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 824c797b6c6SAneesh Kumar K.V 825c797b6c6SAneesh Kumar K.V ret = statfs(fid->abs_path, &stat_buf); 826c797b6c6SAneesh Kumar K.V if (ret < 0) 827c797b6c6SAneesh Kumar K.V goto err_out; 828c797b6c6SAneesh Kumar K.V /* FIXME!! f_blocks needs update based on client msize */ 829c797b6c6SAneesh Kumar K.V fsid = (unsigned int) stat_buf.f_fsid.__val[0] | 830c797b6c6SAneesh Kumar K.V (unsigned long long)stat_buf.f_fsid.__val[1] << 32; 831c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ddqqqqqqd", stat_buf.f_type, 832c797b6c6SAneesh Kumar K.V stat_buf.f_bsize, stat_buf.f_blocks, 833c797b6c6SAneesh Kumar K.V stat_buf.f_bfree, stat_buf.f_bavail, 834c797b6c6SAneesh Kumar K.V stat_buf.f_files, stat_buf.f_ffree, 835c797b6c6SAneesh Kumar K.V fsid, stat_buf.f_namelen); 836c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 837c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 838c797b6c6SAneesh Kumar K.V return; 839c797b6c6SAneesh Kumar K.V err_out: 840c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 841c797b6c6SAneesh Kumar K.V return; 842c797b6c6SAneesh Kumar K.V } 843c797b6c6SAneesh Kumar K.V 844c797b6c6SAneesh Kumar K.V static void virtio_p9_mknod(struct p9_dev *p9dev, 845c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 846c797b6c6SAneesh Kumar K.V { 847c797b6c6SAneesh Kumar K.V int ret; 848c797b6c6SAneesh Kumar K.V char *name; 849c797b6c6SAneesh Kumar K.V struct stat st; 850c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 851c797b6c6SAneesh Kumar K.V struct p9_qid qid; 852c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 853c797b6c6SAneesh Kumar K.V u32 fid_val, mode, major, minor, gid; 854c797b6c6SAneesh Kumar K.V 855c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdddd", &fid_val, &name, &mode, 856c797b6c6SAneesh Kumar K.V &major, &minor, &gid); 857c797b6c6SAneesh Kumar K.V 85831a6fb8dSSasha Levin dfid = get_fid(p9dev, fid_val); 859c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 860c797b6c6SAneesh Kumar K.V ret = mknod(full_path, mode, makedev(major, minor)); 861c797b6c6SAneesh Kumar K.V if (ret < 0) 862c797b6c6SAneesh Kumar K.V goto err_out; 863c797b6c6SAneesh Kumar K.V 864c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0) 865c797b6c6SAneesh Kumar K.V goto err_out; 866c797b6c6SAneesh Kumar K.V 867c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 868c797b6c6SAneesh Kumar K.V if (ret < 0) 869c797b6c6SAneesh Kumar K.V goto err_out; 870c797b6c6SAneesh Kumar K.V 871c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 872c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 873c797b6c6SAneesh Kumar K.V free(name); 874c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 875c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 876c797b6c6SAneesh Kumar K.V return; 877c797b6c6SAneesh Kumar K.V err_out: 878c797b6c6SAneesh Kumar K.V free(name); 879c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 880c797b6c6SAneesh Kumar K.V return; 881c797b6c6SAneesh Kumar K.V } 882c797b6c6SAneesh Kumar K.V 883c797b6c6SAneesh Kumar K.V static void virtio_p9_fsync(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 struct p9_fid *fid; 888c797b6c6SAneesh Kumar K.V u32 fid_val, datasync; 889c797b6c6SAneesh Kumar K.V 890c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid_val, &datasync); 89131a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 892c797b6c6SAneesh Kumar K.V 893c797b6c6SAneesh Kumar K.V if (datasync) 894c797b6c6SAneesh Kumar K.V ret = fdatasync(fid->fd); 895c797b6c6SAneesh Kumar K.V else 896c797b6c6SAneesh Kumar K.V ret = fsync(fid->fd); 897c797b6c6SAneesh Kumar K.V if (ret < 0) 898c797b6c6SAneesh Kumar K.V goto err_out; 899c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 900c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 901c797b6c6SAneesh Kumar K.V return; 902c797b6c6SAneesh Kumar K.V err_out: 903c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 904c797b6c6SAneesh Kumar K.V return; 905c797b6c6SAneesh Kumar K.V } 906c797b6c6SAneesh Kumar K.V 907c797b6c6SAneesh Kumar K.V static void virtio_p9_symlink(struct p9_dev *p9dev, 908c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 909c797b6c6SAneesh Kumar K.V { 910c797b6c6SAneesh Kumar K.V int ret; 911c797b6c6SAneesh Kumar K.V struct stat st; 912c797b6c6SAneesh Kumar K.V u32 fid_val, gid; 913c797b6c6SAneesh Kumar K.V struct p9_qid qid; 914c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 915c797b6c6SAneesh Kumar K.V char new_name[PATH_MAX]; 916c797b6c6SAneesh Kumar K.V char *old_path, *name; 917c797b6c6SAneesh Kumar K.V 918c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dssd", &fid_val, &name, &old_path, &gid); 919c797b6c6SAneesh Kumar K.V 92031a6fb8dSSasha Levin dfid = get_fid(p9dev, fid_val); 921c797b6c6SAneesh Kumar K.V sprintf(new_name, "%s/%s", dfid->abs_path, name); 922c797b6c6SAneesh Kumar K.V ret = symlink(old_path, new_name); 923c797b6c6SAneesh Kumar K.V if (ret < 0) 924c797b6c6SAneesh Kumar K.V goto err_out; 925c797b6c6SAneesh Kumar K.V 926c797b6c6SAneesh Kumar K.V if (lstat(new_name, &st) < 0) 927c797b6c6SAneesh Kumar K.V goto err_out; 928c797b6c6SAneesh Kumar K.V 929c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 930c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 931c797b6c6SAneesh Kumar K.V free(name); 932c797b6c6SAneesh Kumar K.V free(old_path); 933c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 934c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 935c797b6c6SAneesh Kumar K.V return; 936c797b6c6SAneesh Kumar K.V err_out: 937c797b6c6SAneesh Kumar K.V free(name); 938c797b6c6SAneesh Kumar K.V free(old_path); 939c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 940c797b6c6SAneesh Kumar K.V return; 941c797b6c6SAneesh Kumar K.V } 942c797b6c6SAneesh Kumar K.V 943c797b6c6SAneesh Kumar K.V static void virtio_p9_link(struct p9_dev *p9dev, 944c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 945c797b6c6SAneesh Kumar K.V { 946c797b6c6SAneesh Kumar K.V int ret; 947c797b6c6SAneesh Kumar K.V char *name; 948c797b6c6SAneesh Kumar K.V u32 fid_val, dfid_val; 949c797b6c6SAneesh Kumar K.V struct p9_fid *dfid, *fid; 950c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 951c797b6c6SAneesh Kumar K.V 952c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dds", &dfid_val, &fid_val, &name); 953c797b6c6SAneesh Kumar K.V 95431a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 95531a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 956c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 957c797b6c6SAneesh Kumar K.V ret = link(fid->abs_path, full_path); 958c797b6c6SAneesh Kumar K.V if (ret < 0) 959c797b6c6SAneesh Kumar K.V goto err_out; 960c797b6c6SAneesh Kumar K.V free(name); 961c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 962c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 963c797b6c6SAneesh Kumar K.V return; 964c797b6c6SAneesh Kumar K.V err_out: 965c797b6c6SAneesh Kumar K.V free(name); 966c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 967c797b6c6SAneesh Kumar K.V return; 968c797b6c6SAneesh Kumar K.V 969c797b6c6SAneesh Kumar K.V } 970c797b6c6SAneesh Kumar K.V 971c797b6c6SAneesh Kumar K.V static void virtio_p9_lock(struct p9_dev *p9dev, 972c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 973c797b6c6SAneesh Kumar K.V { 974c797b6c6SAneesh Kumar K.V u8 ret; 975c797b6c6SAneesh Kumar K.V u32 fid_val; 976c797b6c6SAneesh Kumar K.V struct p9_flock flock; 977c797b6c6SAneesh Kumar K.V 978c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbdqqds", &fid_val, &flock.type, 979c797b6c6SAneesh Kumar K.V &flock.flags, &flock.start, &flock.length, 980c797b6c6SAneesh Kumar K.V &flock.proc_id, &flock.client_id); 981c797b6c6SAneesh Kumar K.V 982c797b6c6SAneesh Kumar K.V /* Just return success */ 983c797b6c6SAneesh Kumar K.V ret = P9_LOCK_SUCCESS; 984c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", ret); 985c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 986c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 987c797b6c6SAneesh Kumar K.V free(flock.client_id); 988c797b6c6SAneesh Kumar K.V return; 989c797b6c6SAneesh Kumar K.V } 990c797b6c6SAneesh Kumar K.V 991c797b6c6SAneesh Kumar K.V static void virtio_p9_getlock(struct p9_dev *p9dev, 992c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 993c797b6c6SAneesh Kumar K.V { 994c797b6c6SAneesh Kumar K.V u32 fid_val; 995c797b6c6SAneesh Kumar K.V struct p9_getlock glock; 996c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbqqds", &fid_val, &glock.type, 997c797b6c6SAneesh Kumar K.V &glock.start, &glock.length, &glock.proc_id, 998c797b6c6SAneesh Kumar K.V &glock.client_id); 999c797b6c6SAneesh Kumar K.V 1000c797b6c6SAneesh Kumar K.V /* Just return success */ 1001c797b6c6SAneesh Kumar K.V glock.type = F_UNLCK; 1002c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "bqqds", glock.type, 1003c797b6c6SAneesh Kumar K.V glock.start, glock.length, glock.proc_id, 1004c797b6c6SAneesh Kumar K.V glock.client_id); 1005c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1006c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1007c797b6c6SAneesh Kumar K.V free(glock.client_id); 1008c797b6c6SAneesh Kumar K.V return; 1009c797b6c6SAneesh Kumar K.V } 1010c797b6c6SAneesh Kumar K.V 1011c797b6c6SAneesh Kumar K.V static int virtio_p9_ancestor(char *path, char *ancestor) 1012c797b6c6SAneesh Kumar K.V { 1013c797b6c6SAneesh Kumar K.V int size = strlen(ancestor); 1014c797b6c6SAneesh Kumar K.V if (!strncmp(path, ancestor, size)) { 1015c797b6c6SAneesh Kumar K.V /* 1016c797b6c6SAneesh Kumar K.V * Now check whether ancestor is a full name or 1017c797b6c6SAneesh Kumar K.V * or directory component and not just part 1018c797b6c6SAneesh Kumar K.V * of a name. 1019c797b6c6SAneesh Kumar K.V */ 1020c797b6c6SAneesh Kumar K.V if (path[size] == '\0' || path[size] == '/') 1021c797b6c6SAneesh Kumar K.V return 1; 1022c797b6c6SAneesh Kumar K.V } 1023c797b6c6SAneesh Kumar K.V return 0; 1024c797b6c6SAneesh Kumar K.V } 1025c797b6c6SAneesh Kumar K.V 1026c797b6c6SAneesh Kumar K.V static void virtio_p9_fix_path(char *fid_path, char *old_name, char *new_name) 1027c797b6c6SAneesh Kumar K.V { 1028c797b6c6SAneesh Kumar K.V char tmp_name[PATH_MAX]; 1029c797b6c6SAneesh Kumar K.V size_t rp_sz = strlen(old_name); 1030c797b6c6SAneesh Kumar K.V 1031c797b6c6SAneesh Kumar K.V if (rp_sz == strlen(fid_path)) { 1032c797b6c6SAneesh Kumar K.V /* replace the full name */ 1033c797b6c6SAneesh Kumar K.V strcpy(fid_path, new_name); 1034c797b6c6SAneesh Kumar K.V return; 1035c797b6c6SAneesh Kumar K.V } 1036c797b6c6SAneesh Kumar K.V /* save the trailing path details */ 1037c797b6c6SAneesh Kumar K.V strcpy(tmp_name, fid_path + rp_sz); 1038c797b6c6SAneesh Kumar K.V sprintf(fid_path, "%s%s", new_name, tmp_name); 1039c797b6c6SAneesh Kumar K.V return; 1040c797b6c6SAneesh Kumar K.V } 1041c797b6c6SAneesh Kumar K.V 1042e2341580SSasha Levin static void rename_fids(struct p9_dev *p9dev, char *old_name, char *new_name) 1043e2341580SSasha Levin { 1044e2341580SSasha Levin struct rb_node *node = rb_first(&p9dev->fids); 1045e2341580SSasha Levin 1046e2341580SSasha Levin while (node) { 1047e2341580SSasha Levin struct p9_fid *fid = rb_entry(node, struct p9_fid, node); 1048e2341580SSasha Levin 1049e2341580SSasha Levin if (fid->fid != P9_NOFID && virtio_p9_ancestor(fid->path, old_name)) { 1050e2341580SSasha Levin virtio_p9_fix_path(fid->path, old_name, new_name); 1051e2341580SSasha Levin } 1052e2341580SSasha Levin node = rb_next(node); 1053e2341580SSasha Levin } 1054e2341580SSasha Levin } 1055e2341580SSasha Levin 1056c797b6c6SAneesh Kumar K.V static void virtio_p9_renameat(struct p9_dev *p9dev, 1057c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1058c797b6c6SAneesh Kumar K.V { 1059e2341580SSasha Levin int ret; 1060c797b6c6SAneesh Kumar K.V char *old_name, *new_name; 1061c797b6c6SAneesh Kumar K.V u32 old_dfid_val, new_dfid_val; 1062c797b6c6SAneesh Kumar K.V struct p9_fid *old_dfid, *new_dfid; 1063c797b6c6SAneesh Kumar K.V char old_full_path[PATH_MAX], new_full_path[PATH_MAX]; 1064c797b6c6SAneesh Kumar K.V 1065c797b6c6SAneesh Kumar K.V 1066c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsds", &old_dfid_val, &old_name, 1067c797b6c6SAneesh Kumar K.V &new_dfid_val, &new_name); 1068c797b6c6SAneesh Kumar K.V 106931a6fb8dSSasha Levin old_dfid = get_fid(p9dev, old_dfid_val); 107031a6fb8dSSasha Levin new_dfid = get_fid(p9dev, new_dfid_val); 1071c797b6c6SAneesh Kumar K.V 1072c797b6c6SAneesh Kumar K.V sprintf(old_full_path, "%s/%s", old_dfid->abs_path, old_name); 1073c797b6c6SAneesh Kumar K.V sprintf(new_full_path, "%s/%s", new_dfid->abs_path, new_name); 1074c797b6c6SAneesh Kumar K.V ret = rename(old_full_path, new_full_path); 1075c797b6c6SAneesh Kumar K.V if (ret < 0) 1076c797b6c6SAneesh Kumar K.V goto err_out; 1077c797b6c6SAneesh Kumar K.V /* 1078c797b6c6SAneesh Kumar K.V * Now fix path in other fids, if the renamed path is part of 1079c797b6c6SAneesh Kumar K.V * that. 1080c797b6c6SAneesh Kumar K.V */ 1081e2341580SSasha Levin rename_fids(p9dev, old_name, new_name); 1082c797b6c6SAneesh Kumar K.V free(old_name); 1083c797b6c6SAneesh Kumar K.V free(new_name); 1084c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1085c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1086c797b6c6SAneesh Kumar K.V return; 1087c797b6c6SAneesh Kumar K.V err_out: 1088c797b6c6SAneesh Kumar K.V free(old_name); 1089c797b6c6SAneesh Kumar K.V free(new_name); 1090c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1091c797b6c6SAneesh Kumar K.V return; 1092c797b6c6SAneesh Kumar K.V } 1093c797b6c6SAneesh Kumar K.V 1094c797b6c6SAneesh Kumar K.V static void virtio_p9_unlinkat(struct p9_dev *p9dev, 1095c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1096c797b6c6SAneesh Kumar K.V { 1097c797b6c6SAneesh Kumar K.V int ret; 1098c797b6c6SAneesh Kumar K.V char *name; 1099c797b6c6SAneesh Kumar K.V u32 fid_val, flags; 1100c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 1101c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 1102c797b6c6SAneesh Kumar K.V 1103c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsd", &fid_val, &name, &flags); 110431a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 1105c797b6c6SAneesh Kumar K.V 1106c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", fid->abs_path, name); 1107c797b6c6SAneesh Kumar K.V ret = remove(full_path); 1108c797b6c6SAneesh Kumar K.V if (ret < 0) 1109c797b6c6SAneesh Kumar K.V goto err_out; 1110c797b6c6SAneesh Kumar K.V free(name); 1111c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1112c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1113c797b6c6SAneesh Kumar K.V return; 1114c797b6c6SAneesh Kumar K.V err_out: 1115c797b6c6SAneesh Kumar K.V free(name); 1116c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1117c797b6c6SAneesh Kumar K.V return; 1118c797b6c6SAneesh Kumar K.V } 1119c797b6c6SAneesh Kumar K.V 11205cc808aaSSasha Levin static void virtio_p9_flush(struct p9_dev *p9dev, 11215cc808aaSSasha Levin struct p9_pdu *pdu, u32 *outlen) 11225cc808aaSSasha Levin { 11235cc808aaSSasha Levin u16 tag, oldtag; 11245cc808aaSSasha Levin 11255cc808aaSSasha Levin virtio_p9_pdu_readf(pdu, "ww", &tag, &oldtag); 11265cc808aaSSasha Levin virtio_p9_pdu_writef(pdu, "w", tag); 11275cc808aaSSasha Levin *outlen = pdu->write_offset; 11285cc808aaSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 11295cc808aaSSasha Levin 11305cc808aaSSasha Levin return; 11315cc808aaSSasha Levin } 11325cc808aaSSasha Levin 1133c797b6c6SAneesh Kumar K.V static void virtio_p9_eopnotsupp(struct p9_dev *p9dev, 1134c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1135c797b6c6SAneesh Kumar K.V { 1136c797b6c6SAneesh Kumar K.V return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen); 1137c797b6c6SAneesh Kumar K.V } 1138c797b6c6SAneesh Kumar K.V 1139ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev, 1140af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen); 1141b4422bf3SAneesh Kumar K.V 1142c797b6c6SAneesh Kumar K.V /* FIXME should be removed when merging with latest linus tree */ 1143c797b6c6SAneesh Kumar K.V #define P9_TRENAMEAT 74 1144c797b6c6SAneesh Kumar K.V #define P9_TUNLINKAT 76 1145c797b6c6SAneesh Kumar K.V 1146c797b6c6SAneesh Kumar K.V static p9_handler *virtio_9p_dotl_handler [] = { 1147c797b6c6SAneesh Kumar K.V [P9_TREADDIR] = virtio_p9_readdir, 1148c797b6c6SAneesh Kumar K.V [P9_TSTATFS] = virtio_p9_statfs, 1149c797b6c6SAneesh Kumar K.V [P9_TGETATTR] = virtio_p9_getattr, 1150c797b6c6SAneesh Kumar K.V [P9_TSETATTR] = virtio_p9_setattr, 1151c797b6c6SAneesh Kumar K.V [P9_TXATTRWALK] = virtio_p9_eopnotsupp, 1152c797b6c6SAneesh Kumar K.V [P9_TXATTRCREATE] = virtio_p9_eopnotsupp, 1153c797b6c6SAneesh Kumar K.V [P9_TMKNOD] = virtio_p9_mknod, 1154c797b6c6SAneesh Kumar K.V [P9_TLOCK] = virtio_p9_lock, 1155c797b6c6SAneesh Kumar K.V [P9_TGETLOCK] = virtio_p9_getlock, 1156c797b6c6SAneesh Kumar K.V [P9_TRENAMEAT] = virtio_p9_renameat, 1157c797b6c6SAneesh Kumar K.V [P9_TREADLINK] = virtio_p9_readlink, 1158c797b6c6SAneesh Kumar K.V [P9_TUNLINKAT] = virtio_p9_unlinkat, 1159c797b6c6SAneesh Kumar K.V [P9_TMKDIR] = virtio_p9_mkdir, 1160b4422bf3SAneesh Kumar K.V [P9_TVERSION] = virtio_p9_version, 1161c797b6c6SAneesh Kumar K.V [P9_TLOPEN] = virtio_p9_open, 1162b4422bf3SAneesh Kumar K.V [P9_TATTACH] = virtio_p9_attach, 1163b4422bf3SAneesh Kumar K.V [P9_TWALK] = virtio_p9_walk, 1164c797b6c6SAneesh Kumar K.V [P9_TCLUNK] = virtio_p9_clunk, 1165c797b6c6SAneesh Kumar K.V [P9_TFSYNC] = virtio_p9_fsync, 1166b4422bf3SAneesh Kumar K.V [P9_TREAD] = virtio_p9_read, 11675cc808aaSSasha Levin [P9_TFLUSH] = virtio_p9_flush, 1168c797b6c6SAneesh Kumar K.V [P9_TLINK] = virtio_p9_link, 1169c797b6c6SAneesh Kumar K.V [P9_TSYMLINK] = virtio_p9_symlink, 1170c797b6c6SAneesh Kumar K.V [P9_TLCREATE] = virtio_p9_create, 1171b4422bf3SAneesh Kumar K.V [P9_TWRITE] = virtio_p9_write, 11726fc5cd9bSSasha Levin [P9_TREMOVE] = virtio_p9_remove, 1173f161f28bSSasha Levin [P9_TRENAME] = virtio_p9_rename, 1174b4422bf3SAneesh Kumar K.V }; 1175b4422bf3SAneesh Kumar K.V 1176af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq) 1177af045e53SAneesh Kumar K.V { 1178af045e53SAneesh Kumar K.V struct p9_pdu *pdu = calloc(1, sizeof(*pdu)); 1179af045e53SAneesh Kumar K.V if (!pdu) 1180af045e53SAneesh Kumar K.V return NULL; 1181af045e53SAneesh Kumar K.V 1182bfc15268SAneesh Kumar K.V /* skip the pdu header p9_msg */ 11835529bcd7SAsias He pdu->read_offset = VIRTIO_9P_HDR_LEN; 11845529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 1185af045e53SAneesh Kumar K.V pdu->queue_head = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov, 1186a8a44649SAsias He pdu->out_iov, &pdu->in_iov_cnt, &pdu->out_iov_cnt); 1187af045e53SAneesh Kumar K.V return pdu; 1188af045e53SAneesh Kumar K.V } 1189af045e53SAneesh Kumar K.V 1190af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu) 1191af045e53SAneesh Kumar K.V { 1192af045e53SAneesh Kumar K.V struct p9_msg *msg; 1193af045e53SAneesh Kumar K.V /* 1194af045e53SAneesh Kumar K.V * we can peek directly into pdu for a u8 1195af045e53SAneesh Kumar K.V * value. The host endianess won't be an issue 1196af045e53SAneesh Kumar K.V */ 1197af045e53SAneesh Kumar K.V msg = pdu->out_iov[0].iov_base; 1198af045e53SAneesh Kumar K.V return msg->cmd; 1199af045e53SAneesh Kumar K.V } 1200af045e53SAneesh Kumar K.V 1201b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job) 12021c7850f9SSasha Levin { 1203af045e53SAneesh Kumar K.V u8 cmd; 1204b4422bf3SAneesh Kumar K.V u32 len = 0; 1205b4422bf3SAneesh Kumar K.V p9_handler *handler; 1206b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 1207af045e53SAneesh Kumar K.V struct virt_queue *vq; 1208af045e53SAneesh Kumar K.V struct p9_pdu *p9pdu; 12091c7850f9SSasha Levin 1210b4422bf3SAneesh Kumar K.V vq = job->vq; 1211b4422bf3SAneesh Kumar K.V p9dev = job->p9dev; 12121c7850f9SSasha Levin 1213af045e53SAneesh Kumar K.V p9pdu = virtio_p9_pdu_init(kvm, vq); 1214af045e53SAneesh Kumar K.V cmd = virtio_p9_get_cmd(p9pdu); 1215af045e53SAneesh Kumar K.V 1216c797b6c6SAneesh Kumar K.V if ((cmd >= ARRAY_SIZE(virtio_9p_dotl_handler)) || 1217c797b6c6SAneesh Kumar K.V !virtio_9p_dotl_handler[cmd]) 121897b408afSAneesh Kumar K.V handler = virtio_p9_eopnotsupp; 1219dd78d9eaSAneesh Kumar K.V else 1220c797b6c6SAneesh Kumar K.V handler = virtio_9p_dotl_handler[cmd]; 1221c797b6c6SAneesh Kumar K.V 1222af045e53SAneesh Kumar K.V handler(p9dev, p9pdu, &len); 1223af045e53SAneesh Kumar K.V virt_queue__set_used_elem(vq, p9pdu->queue_head, len); 1224af045e53SAneesh Kumar K.V free(p9pdu); 12251c7850f9SSasha Levin return true; 12261c7850f9SSasha Levin } 12271c7850f9SSasha Levin 12281c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param) 12291c7850f9SSasha Levin { 1230b4422bf3SAneesh Kumar K.V struct p9_dev_job *job = (struct p9_dev_job *)param; 1231b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = job->p9dev; 1232b4422bf3SAneesh Kumar K.V struct virt_queue *vq = job->vq; 12331c7850f9SSasha Levin 12341c7850f9SSasha Levin while (virt_queue__available(vq)) { 1235b4422bf3SAneesh Kumar K.V virtio_p9_do_io_request(kvm, job); 123602eca50cSAsias He p9dev->vdev.ops->signal_vq(kvm, &p9dev->vdev, vq - p9dev->vqs); 12371c7850f9SSasha Levin } 12381c7850f9SSasha Levin } 12391c7850f9SSasha Levin 1240c5ae742bSSasha Levin static u8 *get_config(struct kvm *kvm, void *dev) 12411c7850f9SSasha Levin { 1242c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 12431c7850f9SSasha Levin 1244c5ae742bSSasha Levin return ((u8 *)(p9dev->config)); 1245c7838fbdSSasha Levin } 1246c7838fbdSSasha Levin 1247c7838fbdSSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev) 1248c7838fbdSSasha Levin { 1249c7838fbdSSasha Levin return 1 << VIRTIO_9P_MOUNT_TAG; 1250c7838fbdSSasha Levin } 1251c7838fbdSSasha Levin 1252c7838fbdSSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features) 1253c7838fbdSSasha Levin { 1254c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1255*e0ea1859SMarc Zyngier struct virtio_9p_config *conf = p9dev->config; 1256c7838fbdSSasha Levin 1257c7838fbdSSasha Levin p9dev->features = features; 1258*e0ea1859SMarc Zyngier conf->tag_len = virtio_host_to_guest_u16(&p9dev->vdev, conf->tag_len); 1259c7838fbdSSasha Levin } 1260c7838fbdSSasha Levin 1261c59ba304SWill Deacon static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 page_size, u32 align, 1262c59ba304SWill Deacon u32 pfn) 1263c7838fbdSSasha Levin { 1264c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1265b4422bf3SAneesh Kumar K.V struct p9_dev_job *job; 1266b4422bf3SAneesh Kumar K.V struct virt_queue *queue; 1267c7838fbdSSasha Levin void *p; 12681c7850f9SSasha Levin 1269312c62d1SSasha Levin compat__remove_message(compat_id); 1270e59662b3SSasha Levin 1271c7838fbdSSasha Levin queue = &p9dev->vqs[vq]; 1272c7838fbdSSasha Levin queue->pfn = pfn; 1273e7e2950aSSasha Levin p = virtio_get_vq(kvm, queue->pfn, page_size); 1274c7838fbdSSasha Levin job = &p9dev->jobs[vq]; 12751c7850f9SSasha Levin 1276c59ba304SWill Deacon vring_init(&queue->vring, VIRTQUEUE_NUM, p, align); 1277*e0ea1859SMarc Zyngier virtio_init_device_vq(&p9dev->vdev, queue); 12781c7850f9SSasha Levin 1279b4422bf3SAneesh Kumar K.V *job = (struct p9_dev_job) { 1280b4422bf3SAneesh Kumar K.V .vq = queue, 1281b4422bf3SAneesh Kumar K.V .p9dev = p9dev, 1282b4422bf3SAneesh Kumar K.V }; 1283df0c7f57SSasha Levin thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job); 128460eb42d5SSasha Levin 1285c7838fbdSSasha Levin return 0; 12861c7850f9SSasha Levin } 12871c7850f9SSasha Levin 1288c7838fbdSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 1289c7838fbdSSasha Levin { 1290c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 12911c7850f9SSasha Levin 1292c7838fbdSSasha Levin thread_pool__do_job(&p9dev->jobs[vq].job_id); 1293c7838fbdSSasha Levin 1294c7838fbdSSasha Levin return 0; 1295c7838fbdSSasha Levin } 1296c7838fbdSSasha Levin 1297c7838fbdSSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq) 1298c7838fbdSSasha Levin { 1299c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1300c7838fbdSSasha Levin 1301c7838fbdSSasha Levin return p9dev->vqs[vq].pfn; 1302c7838fbdSSasha Levin } 1303c7838fbdSSasha Levin 1304c7838fbdSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 1305c7838fbdSSasha Levin { 1306c7838fbdSSasha Levin return VIRTQUEUE_NUM; 1307c7838fbdSSasha Levin } 1308c7838fbdSSasha Levin 13097aba29c1SWill Deacon static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size) 13107aba29c1SWill Deacon { 13117aba29c1SWill Deacon /* FIXME: dynamic */ 13127aba29c1SWill Deacon return size; 13137aba29c1SWill Deacon } 13147aba29c1SWill Deacon 13151c47ce69SSasha Levin struct virtio_ops p9_dev_virtio_ops = (struct virtio_ops) { 1316c7838fbdSSasha Levin .get_config = get_config, 1317c7838fbdSSasha Levin .get_host_features = get_host_features, 1318c7838fbdSSasha Levin .set_guest_features = set_guest_features, 1319c7838fbdSSasha Levin .init_vq = init_vq, 1320c7838fbdSSasha Levin .notify_vq = notify_vq, 1321c7838fbdSSasha Levin .get_pfn_vq = get_pfn_vq, 1322c7838fbdSSasha Levin .get_size_vq = get_size_vq, 13237aba29c1SWill Deacon .set_size_vq = set_size_vq, 1324c7838fbdSSasha Levin }; 13251c47ce69SSasha Levin 1326cac9e8fdSSasha Levin int virtio_9p_rootdir_parser(const struct option *opt, const char *arg, int unset) 1327cac9e8fdSSasha Levin { 1328cac9e8fdSSasha Levin char *tag_name; 1329cac9e8fdSSasha Levin char tmp[PATH_MAX]; 1330cac9e8fdSSasha Levin struct kvm *kvm = opt->ptr; 1331cac9e8fdSSasha Levin 1332cac9e8fdSSasha Levin /* 1333cac9e8fdSSasha Levin * 9p dir can be of the form dirname,tag_name or 1334cac9e8fdSSasha Levin * just dirname. In the later case we use the 1335cac9e8fdSSasha Levin * default tag name 1336cac9e8fdSSasha Levin */ 1337cac9e8fdSSasha Levin tag_name = strstr(arg, ","); 1338cac9e8fdSSasha Levin if (tag_name) { 1339cac9e8fdSSasha Levin *tag_name = '\0'; 1340cac9e8fdSSasha Levin tag_name++; 1341cac9e8fdSSasha Levin } 1342cac9e8fdSSasha Levin if (realpath(arg, tmp)) { 1343cac9e8fdSSasha Levin if (virtio_9p__register(kvm, tmp, tag_name) < 0) 1344cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1345cac9e8fdSSasha Levin } else 1346cac9e8fdSSasha Levin die("Failed resolving 9p path"); 1347cac9e8fdSSasha Levin return 0; 1348cac9e8fdSSasha Levin } 1349cac9e8fdSSasha Levin 1350cac9e8fdSSasha Levin int virtio_9p_img_name_parser(const struct option *opt, const char *arg, int unset) 1351cac9e8fdSSasha Levin { 1352cac9e8fdSSasha Levin char path[PATH_MAX]; 1353cac9e8fdSSasha Levin struct stat st; 1354cac9e8fdSSasha Levin struct kvm *kvm = opt->ptr; 1355cac9e8fdSSasha Levin 1356cac9e8fdSSasha Levin if (stat(arg, &st) == 0 && 1357cac9e8fdSSasha Levin S_ISDIR(st.st_mode)) { 1358cac9e8fdSSasha Levin char tmp[PATH_MAX]; 1359cac9e8fdSSasha Levin 1360cac9e8fdSSasha Levin if (kvm->cfg.using_rootfs) 1361cac9e8fdSSasha Levin die("Please use only one rootfs directory atmost"); 1362cac9e8fdSSasha Levin 1363cac9e8fdSSasha Levin if (realpath(arg, tmp) == 0 || 1364cac9e8fdSSasha Levin virtio_9p__register(kvm, tmp, "/dev/root") < 0) 1365cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1366cac9e8fdSSasha Levin kvm->cfg.using_rootfs = 1; 1367cac9e8fdSSasha Levin return 0; 1368cac9e8fdSSasha Levin } 1369cac9e8fdSSasha Levin 1370cac9e8fdSSasha Levin snprintf(path, PATH_MAX, "%s%s", kvm__get_dir(), arg); 1371cac9e8fdSSasha Levin 1372cac9e8fdSSasha Levin if (stat(path, &st) == 0 && 1373cac9e8fdSSasha Levin S_ISDIR(st.st_mode)) { 1374cac9e8fdSSasha Levin char tmp[PATH_MAX]; 1375cac9e8fdSSasha Levin 1376cac9e8fdSSasha Levin if (kvm->cfg.using_rootfs) 1377cac9e8fdSSasha Levin die("Please use only one rootfs directory atmost"); 1378cac9e8fdSSasha Levin 1379cac9e8fdSSasha Levin if (realpath(path, tmp) == 0 || 1380cac9e8fdSSasha Levin virtio_9p__register(kvm, tmp, "/dev/root") < 0) 1381cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1382cac9e8fdSSasha Levin if (virtio_9p__register(kvm, "/", "hostfs") < 0) 1383cac9e8fdSSasha Levin die("Unable to initialize virtio 9p"); 1384cac9e8fdSSasha Levin kvm_setup_resolv(arg); 1385cac9e8fdSSasha Levin kvm->cfg.using_rootfs = kvm->cfg.custom_rootfs = 1; 1386cac9e8fdSSasha Levin kvm->cfg.custom_rootfs_name = arg; 1387cac9e8fdSSasha Levin return 0; 1388cac9e8fdSSasha Levin } 1389cac9e8fdSSasha Levin 1390cac9e8fdSSasha Levin return -1; 1391cac9e8fdSSasha Levin } 1392cac9e8fdSSasha Levin 13931c47ce69SSasha Levin int virtio_9p__init(struct kvm *kvm) 13941c47ce69SSasha Levin { 13951c47ce69SSasha Levin struct p9_dev *p9dev; 13961c47ce69SSasha Levin 13971c47ce69SSasha Levin list_for_each_entry(p9dev, &devs, list) { 139802eca50cSAsias He virtio_init(kvm, p9dev, &p9dev->vdev, &p9_dev_virtio_ops, 1399d97dadecSWill Deacon VIRTIO_DEFAULT_TRANS(kvm), PCI_DEVICE_ID_VIRTIO_9P, 1400ae06ce71SWill Deacon VIRTIO_ID_9P, PCI_CLASS_9P); 1401c7838fbdSSasha Levin } 1402c7838fbdSSasha Levin 1403c7838fbdSSasha Levin return 0; 1404c7838fbdSSasha Levin } 140549a8afd1SSasha Levin virtio_dev_init(virtio_9p__init); 1406c7838fbdSSasha Levin 1407c7838fbdSSasha Levin int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name) 1408c7838fbdSSasha Levin { 1409c7838fbdSSasha Levin struct p9_dev *p9dev; 141054f6802dSPekka Enberg int err = 0; 14111c7850f9SSasha Levin 1412b4422bf3SAneesh Kumar K.V p9dev = calloc(1, sizeof(*p9dev)); 1413b4422bf3SAneesh Kumar K.V if (!p9dev) 141454f6802dSPekka Enberg return -ENOMEM; 141554f6802dSPekka Enberg 1416b4422bf3SAneesh Kumar K.V if (!tag_name) 14175529bcd7SAsias He tag_name = VIRTIO_9P_DEFAULT_TAG; 141854f6802dSPekka Enberg 1419b4422bf3SAneesh Kumar K.V p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1); 142054f6802dSPekka Enberg if (p9dev->config == NULL) { 142154f6802dSPekka Enberg err = -ENOMEM; 1422b4422bf3SAneesh Kumar K.V goto free_p9dev; 142354f6802dSPekka Enberg } 14241c7850f9SSasha Levin 1425b4422bf3SAneesh Kumar K.V strcpy(p9dev->root_dir, root); 1426b4422bf3SAneesh Kumar K.V p9dev->config->tag_len = strlen(tag_name); 142754f6802dSPekka Enberg if (p9dev->config->tag_len > MAX_TAG_LEN) { 142854f6802dSPekka Enberg err = -EINVAL; 1429b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 143054f6802dSPekka Enberg } 14311c7850f9SSasha Levin 1432c7838fbdSSasha Levin memcpy(&p9dev->config->tag, tag_name, strlen(tag_name)); 14331c7850f9SSasha Levin 1434c7838fbdSSasha Levin list_add(&p9dev->list, &devs); 1435b4422bf3SAneesh Kumar K.V 1436d278197dSAsias He if (compat_id == -1) 143752f34d2cSAsias He compat_id = virtio_compat_add_message("virtio-9p", "CONFIG_NET_9P_VIRTIO"); 1438e59662b3SSasha Levin 143954f6802dSPekka Enberg return err; 144054f6802dSPekka Enberg 1441b4422bf3SAneesh Kumar K.V free_p9dev_config: 1442b4422bf3SAneesh Kumar K.V free(p9dev->config); 1443b4422bf3SAneesh Kumar K.V free_p9dev: 1444b4422bf3SAneesh Kumar K.V free(p9dev); 144554f6802dSPekka Enberg return err; 14461c7850f9SSasha Levin } 1447