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" 81c7850f9SSasha Levin 9bfc15268SAneesh Kumar K.V #include <stdio.h> 10bfc15268SAneesh Kumar K.V #include <stdlib.h> 111c7850f9SSasha Levin #include <fcntl.h> 121c7850f9SSasha Levin #include <sys/stat.h> 13bfc15268SAneesh Kumar K.V #include <unistd.h> 14bfc15268SAneesh Kumar K.V #include <string.h> 15bfc15268SAneesh Kumar K.V #include <errno.h> 16c797b6c6SAneesh Kumar K.V #include <sys/vfs.h> 171c7850f9SSasha Levin 182daa28d4SAneesh Kumar K.V #include <linux/virtio_ring.h> 192daa28d4SAneesh Kumar K.V #include <linux/virtio_9p.h> 202daa28d4SAneesh Kumar K.V #include <net/9p/9p.h> 212daa28d4SAneesh Kumar K.V 22c7838fbdSSasha Levin static LIST_HEAD(devs); 23312c62d1SSasha Levin static int compat_id = -1; 24c7838fbdSSasha Levin 25e2341580SSasha Levin static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid); 26e2341580SSasha Levin static struct p9_fid *find_or_create_fid(struct p9_dev *dev, u32 fid) 27e2341580SSasha Levin { 28e2341580SSasha Levin struct rb_node *node = dev->fids.rb_node; 29e2341580SSasha Levin struct p9_fid *pfid = NULL; 30e2341580SSasha Levin 31e2341580SSasha Levin while (node) { 32e2341580SSasha Levin struct p9_fid *cur = rb_entry(node, struct p9_fid, node); 33e2341580SSasha Levin 34e2341580SSasha Levin if (fid < cur->fid) { 35e2341580SSasha Levin node = node->rb_left; 36e2341580SSasha Levin } else if (fid > cur->fid) { 37e2341580SSasha Levin node = node->rb_right; 38e2341580SSasha Levin } else { 39e2341580SSasha Levin return cur; 40e2341580SSasha Levin } 41e2341580SSasha Levin } 42e2341580SSasha Levin 43e2341580SSasha Levin pfid = calloc(sizeof(*pfid), 1); 44e2341580SSasha Levin if (!pfid) 45e2341580SSasha Levin return NULL; 46e2341580SSasha Levin 47e2341580SSasha Levin pfid->fid = fid; 48e2341580SSasha Levin strcpy(pfid->abs_path, dev->root_dir); 49e2341580SSasha Levin pfid->path = pfid->abs_path + strlen(dev->root_dir); 50e2341580SSasha Levin 51e2341580SSasha Levin insert_new_fid(dev, pfid); 52e2341580SSasha Levin 53e2341580SSasha Levin return pfid; 54e2341580SSasha Levin } 55e2341580SSasha Levin 56e2341580SSasha Levin static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid) 57e2341580SSasha Levin { 58e2341580SSasha Levin struct rb_node **node = &(dev->fids.rb_node), *parent = NULL; 59e2341580SSasha Levin 60e2341580SSasha Levin while (*node) { 61e2341580SSasha Levin int result = fid->fid - rb_entry(*node, struct p9_fid, node)->fid; 62e2341580SSasha Levin 63e2341580SSasha Levin parent = *node; 64e2341580SSasha Levin if (result < 0) 65e2341580SSasha Levin node = &((*node)->rb_left); 66e2341580SSasha Levin else if (result > 0) 67e2341580SSasha Levin node = &((*node)->rb_right); 68e2341580SSasha Levin else 69e2341580SSasha Levin return -EEXIST; 70e2341580SSasha Levin } 71e2341580SSasha Levin 72e2341580SSasha Levin rb_link_node(&fid->node, parent, node); 73e2341580SSasha Levin rb_insert_color(&fid->node, &dev->fids); 74e2341580SSasha Levin return 0; 75e2341580SSasha Levin } 76e2341580SSasha Levin 7731a6fb8dSSasha Levin static struct p9_fid *get_fid(struct p9_dev *p9dev, int fid) 7831a6fb8dSSasha Levin { 79e2341580SSasha Levin struct p9_fid *new; 8031a6fb8dSSasha Levin 81e2341580SSasha Levin new = find_or_create_fid(p9dev, fid); 82e2341580SSasha Levin 83e2341580SSasha Levin return new; 8431a6fb8dSSasha Levin } 8531a6fb8dSSasha Levin 861c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */ 87b4422bf3SAneesh Kumar K.V static const char *rel_to_abs(struct p9_dev *p9dev, 88b4422bf3SAneesh Kumar K.V const char *path, char *abs_path) 891c7850f9SSasha Levin { 90b4422bf3SAneesh Kumar K.V sprintf(abs_path, "%s/%s", p9dev->root_dir, path); 911c7850f9SSasha Levin 921c7850f9SSasha Levin return abs_path; 931c7850f9SSasha Levin } 941c7850f9SSasha Levin 95c797b6c6SAneesh Kumar K.V static void stat2qid(struct stat *st, struct p9_qid *qid) 961c7850f9SSasha Levin { 971c7850f9SSasha Levin *qid = (struct p9_qid) { 981c7850f9SSasha Levin .path = st->st_ino, 991c7850f9SSasha Levin .version = st->st_mtime, 1001c7850f9SSasha Levin }; 1011c7850f9SSasha Levin 1021c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) 1031c7850f9SSasha Levin qid->type |= P9_QTDIR; 1041c7850f9SSasha Levin } 1051c7850f9SSasha Levin 106b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid) 1071c7850f9SSasha Levin { 108e2341580SSasha Levin struct p9_fid *pfid = get_fid(p9dev, fid); 109e2341580SSasha Levin 110e2341580SSasha Levin if (pfid->fd > 0) 111e2341580SSasha Levin close(pfid->fd); 112e2341580SSasha Levin 113e2341580SSasha Levin if (pfid->dir) 114e2341580SSasha Levin closedir(pfid->dir); 115e2341580SSasha Levin 116e2341580SSasha Levin rb_erase(&pfid->node, &p9dev->fids); 117e2341580SSasha Levin free(pfid); 1181c7850f9SSasha Levin } 119e2341580SSasha Levin 120e2341580SSasha Levin static void clear_all_fids(struct p9_dev *p9dev) 121e2341580SSasha Levin { 122e2341580SSasha Levin struct rb_node *node = rb_first(&p9dev->fids); 123e2341580SSasha Levin 124e2341580SSasha Levin while (node) { 125e2341580SSasha Levin struct p9_fid *fid = rb_entry(node, struct p9_fid, node); 126e2341580SSasha Levin 127e2341580SSasha Levin if (fid->fd > 0) 128e2341580SSasha Levin close(fid->fd); 129e2341580SSasha Levin 130e2341580SSasha Levin if (fid->dir) 131e2341580SSasha Levin closedir(fid->dir); 132e2341580SSasha Levin 133e2341580SSasha Levin rb_erase(&fid->node, &p9dev->fids); 134e2341580SSasha Levin free(fid); 135e2341580SSasha Levin 136e2341580SSasha Levin node = rb_first(&p9dev->fids); 1371c7850f9SSasha Levin } 1381c7850f9SSasha Levin } 1391c7850f9SSasha Levin 140bfc15268SAneesh Kumar K.V static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size) 1411c7850f9SSasha Levin { 142bfc15268SAneesh Kumar K.V u8 cmd; 143bfc15268SAneesh Kumar K.V u16 tag; 144bfc15268SAneesh Kumar K.V 145bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32); 146bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag); 147bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 148bfc15268SAneesh Kumar K.V /* cmd + 1 is the reply message */ 149bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag); 1501c7850f9SSasha Levin } 1511c7850f9SSasha Levin 1526b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt) 1536b163a87SAneesh Kumar K.V { 1546b163a87SAneesh Kumar K.V int i; 1556b163a87SAneesh Kumar K.V u32 total = 0; 1566b163a87SAneesh Kumar K.V for (i = 0; (i < iov_cnt) && (total < count); i++) { 1576b163a87SAneesh Kumar K.V if (total + iov[i].iov_len > count) { 1586b163a87SAneesh Kumar K.V /* we don't need this iov fully */ 1596b163a87SAneesh Kumar K.V iov[i].iov_len -= ((total + iov[i].iov_len) - count); 1606b163a87SAneesh Kumar K.V i++; 1616b163a87SAneesh Kumar K.V break; 1626b163a87SAneesh Kumar K.V } 1636b163a87SAneesh Kumar K.V total += iov[i].iov_len; 1646b163a87SAneesh Kumar K.V } 1656b163a87SAneesh Kumar K.V return i; 1666b163a87SAneesh Kumar K.V } 1676b163a87SAneesh Kumar K.V 168eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev, 169eee1ba8eSAneesh Kumar K.V struct p9_pdu *pdu, int err, u32 *outlen) 170eee1ba8eSAneesh Kumar K.V { 171bfc15268SAneesh Kumar K.V u16 tag; 172eee1ba8eSAneesh Kumar K.V 1735529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 174c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", err); 175bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 176eee1ba8eSAneesh Kumar K.V 177c797b6c6SAneesh Kumar K.V /* read the tag from input */ 178bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32) + sizeof(u8); 179bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "w", &tag); 180bfc15268SAneesh Kumar K.V 181c797b6c6SAneesh Kumar K.V /* Update the header */ 182bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 183c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RLERROR, tag); 184eee1ba8eSAneesh Kumar K.V } 185eee1ba8eSAneesh Kumar K.V 186ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev, 187af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1881c7850f9SSasha Levin { 189c797b6c6SAneesh Kumar K.V u32 msize; 190c797b6c6SAneesh Kumar K.V char *version; 191c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ds", &msize, &version); 192c797b6c6SAneesh Kumar K.V /* 193c797b6c6SAneesh Kumar K.V * reply with the same msize the client sent us 194c797b6c6SAneesh Kumar K.V * Error out if the request is not for 9P2000.L 195c797b6c6SAneesh Kumar K.V */ 1965529bcd7SAsias He if (!strcmp(version, VIRTIO_9P_VERSION_DOTL)) 197c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, version); 198c797b6c6SAneesh Kumar K.V else 199c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, "unknown"); 2001c7850f9SSasha Levin 201bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 202bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 203c797b6c6SAneesh Kumar K.V free(version); 204ead43b01SAneesh Kumar K.V return; 2051c7850f9SSasha Levin } 2061c7850f9SSasha Levin 207ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev, 208af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2091c7850f9SSasha Levin { 210bfc15268SAneesh Kumar K.V u32 fid; 2111c7850f9SSasha Levin 212bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid); 213bfc15268SAneesh Kumar K.V close_fid(p9dev, fid); 2141c7850f9SSasha Levin 215bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 216bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 217ead43b01SAneesh Kumar K.V return; 2181c7850f9SSasha Levin } 2191c7850f9SSasha Levin 220c797b6c6SAneesh Kumar K.V /* 221c797b6c6SAneesh Kumar K.V * FIXME!! Need to map to protocol independent value. Upstream 222c797b6c6SAneesh Kumar K.V * 9p also have the same BUG 223c797b6c6SAneesh Kumar K.V */ 224c797b6c6SAneesh Kumar K.V static int virtio_p9_openflags(int flags) 225c797b6c6SAneesh Kumar K.V { 226c797b6c6SAneesh Kumar K.V flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT | O_DIRECT); 227c797b6c6SAneesh Kumar K.V flags |= O_NOFOLLOW; 228c797b6c6SAneesh Kumar K.V return flags; 229c797b6c6SAneesh Kumar K.V } 230c797b6c6SAneesh Kumar K.V 231ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev, 232af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2331c7850f9SSasha Levin { 234c797b6c6SAneesh Kumar K.V u32 fid, flags; 2351c7850f9SSasha Levin struct stat st; 236bfc15268SAneesh Kumar K.V struct p9_qid qid; 237bfc15268SAneesh Kumar K.V struct p9_fid *new_fid; 238bfc15268SAneesh Kumar K.V 239c797b6c6SAneesh Kumar K.V 240c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid, &flags); 24131a6fb8dSSasha Levin new_fid = get_fid(p9dev, fid); 2421c7850f9SSasha Levin 24330204a77SAneesh Kumar K.V if (lstat(new_fid->abs_path, &st) < 0) 244eee1ba8eSAneesh Kumar K.V goto err_out; 2451c7850f9SSasha Levin 246c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 2471c7850f9SSasha Levin 248eee1ba8eSAneesh Kumar K.V if (new_fid->is_dir) { 2491c7850f9SSasha Levin new_fid->dir = opendir(new_fid->abs_path); 250eee1ba8eSAneesh Kumar K.V if (!new_fid->dir) 251eee1ba8eSAneesh Kumar K.V goto err_out; 252eee1ba8eSAneesh Kumar K.V } else { 253eee1ba8eSAneesh Kumar K.V new_fid->fd = open(new_fid->abs_path, 254c797b6c6SAneesh Kumar K.V virtio_p9_openflags(flags)); 255eee1ba8eSAneesh Kumar K.V if (new_fid->fd < 0) 256eee1ba8eSAneesh Kumar K.V goto err_out; 257eee1ba8eSAneesh Kumar K.V } 258c797b6c6SAneesh Kumar K.V /* FIXME!! need ot send proper iounit */ 259bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 260bfc15268SAneesh Kumar K.V 261bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 262bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 263ead43b01SAneesh Kumar K.V return; 264eee1ba8eSAneesh Kumar K.V err_out: 265eee1ba8eSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 266ead43b01SAneesh Kumar K.V return; 2671c7850f9SSasha Levin } 2681c7850f9SSasha Levin 269ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev, 270af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2711c7850f9SSasha Levin { 272c797b6c6SAneesh Kumar K.V int fd, ret; 273bfc15268SAneesh Kumar K.V char *name; 274af045e53SAneesh Kumar K.V struct stat st; 275bfc15268SAneesh Kumar K.V struct p9_qid qid; 276c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 2774bc9734aSAneesh Kumar K.V char full_path[PATH_MAX]; 278c797b6c6SAneesh Kumar K.V u32 dfid_val, flags, mode, gid; 279af045e53SAneesh Kumar K.V 280c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsddd", &dfid_val, 281c797b6c6SAneesh Kumar K.V &name, &flags, &mode, &gid); 28231a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 2831c7850f9SSasha Levin 284c797b6c6SAneesh Kumar K.V flags = virtio_p9_openflags(flags); 2855f900f6dSSasha Levin 286c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 287c797b6c6SAneesh Kumar K.V fd = open(full_path, flags | O_CREAT, mode); 2884bc9734aSAneesh Kumar K.V if (fd < 0) 2894bc9734aSAneesh Kumar K.V goto err_out; 290c797b6c6SAneesh Kumar K.V dfid->fd = fd; 291c797b6c6SAneesh Kumar K.V 2924bc9734aSAneesh Kumar K.V if (lstat(full_path, &st) < 0) 2936c8ca053SAneesh Kumar K.V goto err_out; 2941c7850f9SSasha Levin 295c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 296c797b6c6SAneesh Kumar K.V if (ret < 0) 297c797b6c6SAneesh Kumar K.V goto err_out; 298c797b6c6SAneesh Kumar K.V 299c797b6c6SAneesh Kumar K.V ret = lchown(full_path, dfid->uid, gid); 300c797b6c6SAneesh Kumar K.V if (ret < 0) 301c797b6c6SAneesh Kumar K.V goto err_out; 302c797b6c6SAneesh Kumar K.V 303c797b6c6SAneesh Kumar K.V sprintf(dfid->path, "%s/%s", dfid->path, name); 304c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 305bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 306bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 307bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 3085f900f6dSSasha Levin free(name); 3096c8ca053SAneesh Kumar K.V return; 3106c8ca053SAneesh Kumar K.V err_out: 3115f900f6dSSasha Levin free(name); 312c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 313c797b6c6SAneesh Kumar K.V return; 314c797b6c6SAneesh Kumar K.V } 315c797b6c6SAneesh Kumar K.V 316c797b6c6SAneesh Kumar K.V static void virtio_p9_mkdir(struct p9_dev *p9dev, 317c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 318c797b6c6SAneesh Kumar K.V { 319c797b6c6SAneesh Kumar K.V int ret; 320c797b6c6SAneesh Kumar K.V char *name; 321c797b6c6SAneesh Kumar K.V struct stat st; 322c797b6c6SAneesh Kumar K.V struct p9_qid qid; 323c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 324c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 325c797b6c6SAneesh Kumar K.V u32 dfid_val, mode, gid; 326c797b6c6SAneesh Kumar K.V 327c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdd", &dfid_val, 328c797b6c6SAneesh Kumar K.V &name, &mode, &gid); 32931a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 330c797b6c6SAneesh Kumar K.V 331c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 332c797b6c6SAneesh Kumar K.V ret = mkdir(full_path, mode); 333c797b6c6SAneesh Kumar K.V if (ret < 0) 334c797b6c6SAneesh Kumar K.V goto err_out; 335c797b6c6SAneesh Kumar K.V 336c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0) 337c797b6c6SAneesh Kumar K.V goto err_out; 338c797b6c6SAneesh Kumar K.V 339c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 340c797b6c6SAneesh Kumar K.V if (ret < 0) 341c797b6c6SAneesh Kumar K.V goto err_out; 342c797b6c6SAneesh Kumar K.V 343c797b6c6SAneesh Kumar K.V ret = lchown(full_path, dfid->uid, gid); 344c797b6c6SAneesh Kumar K.V if (ret < 0) 345c797b6c6SAneesh Kumar K.V goto err_out; 346c797b6c6SAneesh Kumar K.V 347c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 348c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 349c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 350c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 351c797b6c6SAneesh Kumar K.V free(name); 352c797b6c6SAneesh Kumar K.V return; 353c797b6c6SAneesh Kumar K.V err_out: 354c797b6c6SAneesh Kumar K.V free(name); 355c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 356ead43b01SAneesh Kumar K.V return; 3571c7850f9SSasha Levin } 3581c7850f9SSasha Levin 359ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev, 360af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 3611c7850f9SSasha Levin { 362af045e53SAneesh Kumar K.V u8 i; 363bfc15268SAneesh Kumar K.V u16 nwqid; 364bfc15268SAneesh Kumar K.V u16 nwname; 365bfc15268SAneesh Kumar K.V struct p9_qid wqid; 366e2341580SSasha Levin struct p9_fid *new_fid, *old_fid; 367c797b6c6SAneesh Kumar K.V u32 fid_val, newfid_val; 368c797b6c6SAneesh Kumar K.V 3691c7850f9SSasha Levin 370bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname); 37131a6fb8dSSasha Levin new_fid = get_fid(p9dev, newfid_val); 3721c7850f9SSasha Levin 373bfc15268SAneesh Kumar K.V nwqid = 0; 374bfc15268SAneesh Kumar K.V if (nwname) { 37531a6fb8dSSasha Levin struct p9_fid *fid = get_fid(p9dev, fid_val); 376bfc15268SAneesh Kumar K.V 377baac79a5SAneesh Kumar K.V strcpy(new_fid->path, fid->path); 378bfc15268SAneesh Kumar K.V /* skip the space for count */ 379bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 380bfc15268SAneesh Kumar K.V for (i = 0; i < nwname; i++) { 381bfc15268SAneesh Kumar K.V struct stat st; 3821c7850f9SSasha Levin char tmp[PATH_MAX] = {0}; 3831c7850f9SSasha Levin char full_path[PATH_MAX]; 384e55ed135SPekka Enberg char *str; 385bfc15268SAneesh Kumar K.V 386bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "s", &str); 3871c7850f9SSasha Levin 3881c7850f9SSasha Levin /* Format the new path we're 'walk'ing into */ 389baac79a5SAneesh Kumar K.V sprintf(tmp, "%s/%s", new_fid->path, str); 390e55ed135SPekka Enberg 391e55ed135SPekka Enberg free(str); 392e55ed135SPekka Enberg 393c797b6c6SAneesh Kumar K.V if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0) 3946c8ca053SAneesh Kumar K.V goto err_out; 3951c7850f9SSasha Levin 396c797b6c6SAneesh Kumar K.V stat2qid(&st, &wqid); 3971c7850f9SSasha Levin new_fid->is_dir = S_ISDIR(st.st_mode); 3981c7850f9SSasha Levin strcpy(new_fid->path, tmp); 399c797b6c6SAneesh Kumar K.V new_fid->uid = fid->uid; 400bfc15268SAneesh Kumar K.V nwqid++; 401bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &wqid); 4021c7850f9SSasha Levin } 4031c7850f9SSasha Levin } else { 404bfc15268SAneesh Kumar K.V /* 405bfc15268SAneesh Kumar K.V * update write_offset so our outlen get correct value 406bfc15268SAneesh Kumar K.V */ 407bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 408e2341580SSasha Levin old_fid = get_fid(p9dev, fid_val); 409e2341580SSasha Levin new_fid->is_dir = old_fid->is_dir; 410e2341580SSasha Levin strcpy(new_fid->path, old_fid->path); 411e2341580SSasha Levin new_fid->uid = old_fid->uid; 4121c7850f9SSasha Levin } 413bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 4145529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 415bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", nwqid); 416bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 4176c8ca053SAneesh Kumar K.V return; 4186c8ca053SAneesh Kumar K.V err_out: 4196c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 420ead43b01SAneesh Kumar K.V return; 4211c7850f9SSasha Levin } 4221c7850f9SSasha Levin 423ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev, 424af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4251c7850f9SSasha Levin { 426bfc15268SAneesh Kumar K.V char *uname; 427bfc15268SAneesh Kumar K.V char *aname; 4281c7850f9SSasha Levin struct stat st; 429bfc15268SAneesh Kumar K.V struct p9_qid qid; 4301c7850f9SSasha Levin struct p9_fid *fid; 431c797b6c6SAneesh Kumar K.V u32 fid_val, afid, uid; 432bfc15268SAneesh Kumar K.V 433c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddssd", &fid_val, &afid, 434c797b6c6SAneesh Kumar K.V &uname, &aname, &uid); 4351c7850f9SSasha Levin 43639257180SPekka Enberg free(uname); 43739257180SPekka Enberg free(aname); 43839257180SPekka Enberg 439e2341580SSasha Levin clear_all_fids(p9dev); 4401c7850f9SSasha Levin 44130204a77SAneesh Kumar K.V if (lstat(p9dev->root_dir, &st) < 0) 4426c8ca053SAneesh Kumar K.V goto err_out; 4431c7850f9SSasha Levin 444c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 4451c7850f9SSasha Levin 44631a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 447c797b6c6SAneesh Kumar K.V fid->uid = uid; 4481c7850f9SSasha Levin fid->is_dir = 1; 4491c7850f9SSasha Levin strcpy(fid->path, "/"); 4501c7850f9SSasha Levin 451bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 452bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 453bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 4546c8ca053SAneesh Kumar K.V return; 4556c8ca053SAneesh Kumar K.V err_out: 4566c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 457ead43b01SAneesh Kumar K.V return; 4581c7850f9SSasha Levin } 4591c7850f9SSasha Levin 460c797b6c6SAneesh Kumar K.V static void virtio_p9_fill_stat(struct p9_dev *p9dev, 461c797b6c6SAneesh Kumar K.V struct stat *st, struct p9_stat_dotl *statl) 4625f900f6dSSasha Levin { 463c797b6c6SAneesh Kumar K.V memset(statl, 0, sizeof(*statl)); 464c797b6c6SAneesh Kumar K.V statl->st_mode = st->st_mode; 465c797b6c6SAneesh Kumar K.V statl->st_nlink = st->st_nlink; 466c797b6c6SAneesh Kumar K.V statl->st_uid = st->st_uid; 467c797b6c6SAneesh Kumar K.V statl->st_gid = st->st_gid; 468c797b6c6SAneesh Kumar K.V statl->st_rdev = st->st_rdev; 469c797b6c6SAneesh Kumar K.V statl->st_size = st->st_size; 470c797b6c6SAneesh Kumar K.V statl->st_blksize = st->st_blksize; 471c797b6c6SAneesh Kumar K.V statl->st_blocks = st->st_blocks; 472c797b6c6SAneesh Kumar K.V statl->st_atime_sec = st->st_atime; 473c797b6c6SAneesh Kumar K.V statl->st_atime_nsec = st->st_atim.tv_nsec; 474c797b6c6SAneesh Kumar K.V statl->st_mtime_sec = st->st_mtime; 475c797b6c6SAneesh Kumar K.V statl->st_mtime_nsec = st->st_mtim.tv_nsec; 476c797b6c6SAneesh Kumar K.V statl->st_ctime_sec = st->st_ctime; 477c797b6c6SAneesh Kumar K.V statl->st_ctime_nsec = st->st_ctim.tv_nsec; 478c797b6c6SAneesh Kumar K.V /* Currently we only support BASIC fields in stat */ 479c797b6c6SAneesh Kumar K.V statl->st_result_mask = P9_STATS_BASIC; 480c797b6c6SAneesh Kumar K.V stat2qid(st, &statl->qid); 4811c7850f9SSasha Levin } 4821c7850f9SSasha Levin 483ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev, 484af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4851c7850f9SSasha Levin { 486bfc15268SAneesh Kumar K.V u64 offset; 487bfc15268SAneesh Kumar K.V u32 fid_val; 488c797b6c6SAneesh Kumar K.V u16 iov_cnt; 489c797b6c6SAneesh Kumar K.V void *iov_base; 490c797b6c6SAneesh Kumar K.V size_t iov_len; 491bfc15268SAneesh Kumar K.V u32 count, rcount; 492bfc15268SAneesh Kumar K.V struct p9_fid *fid; 493c797b6c6SAneesh Kumar K.V 4941c7850f9SSasha Levin 495bfc15268SAneesh Kumar K.V rcount = 0; 496bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 49731a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 49850c479e0SAneesh Kumar K.V 49950c479e0SAneesh Kumar K.V iov_base = pdu->in_iov[0].iov_base; 50050c479e0SAneesh Kumar K.V iov_len = pdu->in_iov[0].iov_len; 50150c479e0SAneesh Kumar K.V iov_cnt = pdu->in_iov_cnt; 5025529bcd7SAsias He pdu->in_iov[0].iov_base += VIRTIO_9P_HDR_LEN + sizeof(u32); 5035529bcd7SAsias He pdu->in_iov[0].iov_len -= VIRTIO_9P_HDR_LEN + sizeof(u32); 5046b163a87SAneesh Kumar K.V pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov, 505bfc15268SAneesh Kumar K.V count, 5066b163a87SAneesh Kumar K.V pdu->in_iov_cnt); 507bfc15268SAneesh Kumar K.V rcount = preadv(fid->fd, pdu->in_iov, 508bfc15268SAneesh Kumar K.V pdu->in_iov_cnt, offset); 509bfc15268SAneesh Kumar K.V if (rcount > count) 510bfc15268SAneesh Kumar K.V rcount = count; 511bfc15268SAneesh Kumar K.V /* 512bfc15268SAneesh Kumar K.V * Update the iov_base back, so that rest of 513bfc15268SAneesh Kumar K.V * pdu_writef works correctly. 514bfc15268SAneesh Kumar K.V */ 51550c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_base = iov_base; 51650c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_len = iov_len; 51750c479e0SAneesh Kumar K.V pdu->in_iov_cnt = iov_cnt; 518c797b6c6SAneesh Kumar K.V 5195529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 520bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 521bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 522bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 523ead43b01SAneesh Kumar K.V return; 5241c7850f9SSasha Levin } 5251c7850f9SSasha Levin 526c797b6c6SAneesh Kumar K.V static int virtio_p9_dentry_size(struct dirent *dent) 527c797b6c6SAneesh Kumar K.V { 528c797b6c6SAneesh Kumar K.V /* 529c797b6c6SAneesh Kumar K.V * Size of each dirent: 530c797b6c6SAneesh Kumar K.V * qid(13) + offset(8) + type(1) + name_len(2) + name 531c797b6c6SAneesh Kumar K.V */ 532c797b6c6SAneesh Kumar K.V return 24 + strlen(dent->d_name); 533c797b6c6SAneesh Kumar K.V } 534c797b6c6SAneesh Kumar K.V 535c797b6c6SAneesh Kumar K.V static void virtio_p9_readdir(struct p9_dev *p9dev, 536c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 537c797b6c6SAneesh Kumar K.V { 538c797b6c6SAneesh Kumar K.V u32 fid_val; 539c797b6c6SAneesh Kumar K.V u32 count, rcount; 540c797b6c6SAneesh Kumar K.V struct stat st; 541c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 542c797b6c6SAneesh Kumar K.V struct dirent *dent; 543c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 544c797b6c6SAneesh Kumar K.V u64 offset, old_offset; 545c797b6c6SAneesh Kumar K.V 546c797b6c6SAneesh Kumar K.V rcount = 0; 547c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 54831a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 549c797b6c6SAneesh Kumar K.V 550c797b6c6SAneesh Kumar K.V if (!fid->is_dir) { 551*69bb4278SSasha Levin errno = EINVAL; 552c797b6c6SAneesh Kumar K.V goto err_out; 553c797b6c6SAneesh Kumar K.V } 554c797b6c6SAneesh Kumar K.V 555c797b6c6SAneesh Kumar K.V /* Move the offset specified */ 556c797b6c6SAneesh Kumar K.V seekdir(fid->dir, offset); 557c797b6c6SAneesh Kumar K.V 558c797b6c6SAneesh Kumar K.V old_offset = offset; 559c797b6c6SAneesh Kumar K.V /* If reading a dir, fill the buffer with p9_stat entries */ 560c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir); 561c797b6c6SAneesh Kumar K.V 562c797b6c6SAneesh Kumar K.V /* Skip the space for writing count */ 563c797b6c6SAneesh Kumar K.V pdu->write_offset += sizeof(u32); 564c797b6c6SAneesh Kumar K.V while (dent) { 565c797b6c6SAneesh Kumar K.V u32 read; 566c797b6c6SAneesh Kumar K.V struct p9_qid qid; 567c797b6c6SAneesh Kumar K.V 568c797b6c6SAneesh Kumar K.V if ((rcount + virtio_p9_dentry_size(dent)) > count) { 569c797b6c6SAneesh Kumar K.V /* seek to the previous offset and return */ 570c797b6c6SAneesh Kumar K.V seekdir(fid->dir, old_offset); 571c797b6c6SAneesh Kumar K.V break; 572c797b6c6SAneesh Kumar K.V } 573c797b6c6SAneesh Kumar K.V old_offset = dent->d_off; 574c797b6c6SAneesh Kumar K.V lstat(rel_to_abs(p9dev, dent->d_name, full_path), &st); 575c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 576c797b6c6SAneesh Kumar K.V read = pdu->write_offset; 577c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qqbs", &qid, dent->d_off, 578c797b6c6SAneesh Kumar K.V dent->d_type, dent->d_name); 579c797b6c6SAneesh Kumar K.V rcount += pdu->write_offset - read; 580c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir); 581c797b6c6SAneesh Kumar K.V } 582c797b6c6SAneesh Kumar K.V 5835529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 584c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 585c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 586c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 587c797b6c6SAneesh Kumar K.V return; 588c797b6c6SAneesh Kumar K.V err_out: 589c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 590c797b6c6SAneesh Kumar K.V return; 591c797b6c6SAneesh Kumar K.V } 592c797b6c6SAneesh Kumar K.V 593c797b6c6SAneesh Kumar K.V 594c797b6c6SAneesh Kumar K.V static void virtio_p9_getattr(struct p9_dev *p9dev, 595af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5961c7850f9SSasha Levin { 597bfc15268SAneesh Kumar K.V u32 fid_val; 598af045e53SAneesh Kumar K.V struct stat st; 599c797b6c6SAneesh Kumar K.V u64 request_mask; 600bfc15268SAneesh Kumar K.V struct p9_fid *fid; 601c797b6c6SAneesh Kumar K.V struct p9_stat_dotl statl; 6021c7850f9SSasha Levin 603c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dq", &fid_val, &request_mask); 60431a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 60530204a77SAneesh Kumar K.V if (lstat(fid->abs_path, &st) < 0) 6066c8ca053SAneesh Kumar K.V goto err_out; 6071c7850f9SSasha Levin 608c797b6c6SAneesh Kumar K.V virtio_p9_fill_stat(p9dev, &st, &statl); 609c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "A", &statl); 610bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 611bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 612ead43b01SAneesh Kumar K.V return; 6136c8ca053SAneesh Kumar K.V err_out: 6146c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 6156c8ca053SAneesh Kumar K.V return; 6161c7850f9SSasha Levin } 6171c7850f9SSasha Levin 618c797b6c6SAneesh Kumar K.V /* FIXME!! from linux/fs.h */ 619c797b6c6SAneesh Kumar K.V /* 620c797b6c6SAneesh Kumar K.V * Attribute flags. These should be or-ed together to figure out what 621c797b6c6SAneesh Kumar K.V * has been changed! 622c797b6c6SAneesh Kumar K.V */ 623c797b6c6SAneesh Kumar K.V #define ATTR_MODE (1 << 0) 624c797b6c6SAneesh Kumar K.V #define ATTR_UID (1 << 1) 625c797b6c6SAneesh Kumar K.V #define ATTR_GID (1 << 2) 626c797b6c6SAneesh Kumar K.V #define ATTR_SIZE (1 << 3) 627c797b6c6SAneesh Kumar K.V #define ATTR_ATIME (1 << 4) 628c797b6c6SAneesh Kumar K.V #define ATTR_MTIME (1 << 5) 629c797b6c6SAneesh Kumar K.V #define ATTR_CTIME (1 << 6) 630c797b6c6SAneesh Kumar K.V #define ATTR_ATIME_SET (1 << 7) 631c797b6c6SAneesh Kumar K.V #define ATTR_MTIME_SET (1 << 8) 632c797b6c6SAneesh Kumar K.V #define ATTR_FORCE (1 << 9) /* Not a change, but a change it */ 633c797b6c6SAneesh Kumar K.V #define ATTR_ATTR_FLAG (1 << 10) 634c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SUID (1 << 11) 635c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SGID (1 << 12) 636c797b6c6SAneesh Kumar K.V #define ATTR_FILE (1 << 13) 637c797b6c6SAneesh Kumar K.V #define ATTR_KILL_PRIV (1 << 14) 638c797b6c6SAneesh Kumar K.V #define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ 639c797b6c6SAneesh Kumar K.V #define ATTR_TIMES_SET (1 << 16) 640c797b6c6SAneesh Kumar K.V 641c797b6c6SAneesh Kumar K.V #define ATTR_MASK 127 642c797b6c6SAneesh Kumar K.V 643c797b6c6SAneesh Kumar K.V static void virtio_p9_setattr(struct p9_dev *p9dev, 644af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 6451c7850f9SSasha Levin { 646c797b6c6SAneesh Kumar K.V int ret = 0; 647bfc15268SAneesh Kumar K.V u32 fid_val; 648bfc15268SAneesh Kumar K.V struct p9_fid *fid; 649c797b6c6SAneesh Kumar K.V struct p9_iattr_dotl p9attr; 6501c7850f9SSasha Levin 651c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dI", &fid_val, &p9attr); 65231a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 6531c7850f9SSasha Levin 654c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MODE) { 655c797b6c6SAneesh Kumar K.V ret = chmod(fid->abs_path, p9attr.mode); 656c797b6c6SAneesh Kumar K.V if (ret < 0) 657c797b6c6SAneesh Kumar K.V goto err_out; 658c797b6c6SAneesh Kumar K.V } 659c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_ATIME | ATTR_MTIME)) { 660c797b6c6SAneesh Kumar K.V struct timespec times[2]; 661c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME) { 662c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME_SET) { 663c797b6c6SAneesh Kumar K.V times[0].tv_sec = p9attr.atime_sec; 664c797b6c6SAneesh Kumar K.V times[0].tv_nsec = p9attr.atime_nsec; 665c797b6c6SAneesh Kumar K.V } else { 666c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_NOW; 667c797b6c6SAneesh Kumar K.V } 668c797b6c6SAneesh Kumar K.V } else { 669c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_OMIT; 670c797b6c6SAneesh Kumar K.V } 671c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME) { 672c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME_SET) { 673c797b6c6SAneesh Kumar K.V times[1].tv_sec = p9attr.mtime_sec; 674c797b6c6SAneesh Kumar K.V times[1].tv_nsec = p9attr.mtime_nsec; 675c797b6c6SAneesh Kumar K.V } else { 676c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_NOW; 677c797b6c6SAneesh Kumar K.V } 678c797b6c6SAneesh Kumar K.V } else 679c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_OMIT; 680c797b6c6SAneesh Kumar K.V 681c797b6c6SAneesh Kumar K.V ret = utimensat(-1, fid->abs_path, times, AT_SYMLINK_NOFOLLOW); 682c797b6c6SAneesh Kumar K.V if (ret < 0) 683c797b6c6SAneesh Kumar K.V goto err_out; 684c797b6c6SAneesh Kumar K.V } 685c797b6c6SAneesh Kumar K.V /* 686c797b6c6SAneesh Kumar K.V * If the only valid entry in iattr is ctime we can call 687c797b6c6SAneesh Kumar K.V * chown(-1,-1) to update the ctime of the file 688c797b6c6SAneesh Kumar K.V */ 689c797b6c6SAneesh Kumar K.V if ((p9attr.valid & (ATTR_UID | ATTR_GID)) || 690c797b6c6SAneesh Kumar K.V ((p9attr.valid & ATTR_CTIME) 691c797b6c6SAneesh Kumar K.V && !((p9attr.valid & ATTR_MASK) & ~ATTR_CTIME))) { 692c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_UID)) 693c797b6c6SAneesh Kumar K.V p9attr.uid = -1; 694c797b6c6SAneesh Kumar K.V 695c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_GID)) 696c797b6c6SAneesh Kumar K.V p9attr.gid = -1; 697c797b6c6SAneesh Kumar K.V 698c797b6c6SAneesh Kumar K.V ret = lchown(fid->abs_path, p9attr.uid, p9attr.gid); 699c797b6c6SAneesh Kumar K.V if (ret < 0) 700c797b6c6SAneesh Kumar K.V goto err_out; 701c797b6c6SAneesh Kumar K.V } 702c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_SIZE)) { 703c797b6c6SAneesh Kumar K.V ret = truncate(fid->abs_path, p9attr.size); 704c797b6c6SAneesh Kumar K.V if (ret < 0) 705c797b6c6SAneesh Kumar K.V goto err_out; 706c797b6c6SAneesh Kumar K.V } 7075529bcd7SAsias He *outlen = VIRTIO_9P_HDR_LEN; 708bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 709ead43b01SAneesh Kumar K.V return; 7104bc9734aSAneesh Kumar K.V err_out: 7114bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 7124bc9734aSAneesh Kumar K.V return; 7131c7850f9SSasha Levin } 7141c7850f9SSasha Levin 715ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev, 716af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 7171c7850f9SSasha Levin { 7184bc9734aSAneesh Kumar K.V 719bfc15268SAneesh Kumar K.V u64 offset; 720bfc15268SAneesh Kumar K.V u32 fid_val; 7214bc9734aSAneesh Kumar K.V u32 count; 7224bc9734aSAneesh Kumar K.V ssize_t res; 72350c479e0SAneesh Kumar K.V u16 iov_cnt; 72450c479e0SAneesh Kumar K.V void *iov_base; 72550c479e0SAneesh Kumar K.V size_t iov_len; 726bfc15268SAneesh Kumar K.V struct p9_fid *fid; 727b064b05aSAneesh Kumar K.V /* u32 fid + u64 offset + u32 count */ 728b064b05aSAneesh Kumar K.V int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32); 7291c7850f9SSasha Levin 730bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 73131a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 732af045e53SAneesh Kumar K.V 73350c479e0SAneesh Kumar K.V iov_base = pdu->out_iov[0].iov_base; 73450c479e0SAneesh Kumar K.V iov_len = pdu->out_iov[0].iov_len; 73550c479e0SAneesh Kumar K.V iov_cnt = pdu->out_iov_cnt; 73650c479e0SAneesh Kumar K.V 737bfc15268SAneesh Kumar K.V /* Adjust the iovec to skip the header and meta data */ 738b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size); 739b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_len -= (sizeof(struct p9_msg) + twrite_size); 740bfc15268SAneesh Kumar K.V pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count, 7416b163a87SAneesh Kumar K.V pdu->out_iov_cnt); 7424bc9734aSAneesh Kumar K.V res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset); 74350c479e0SAneesh Kumar K.V /* 74450c479e0SAneesh Kumar K.V * Update the iov_base back, so that rest of 74550c479e0SAneesh Kumar K.V * pdu_readf works correctly. 74650c479e0SAneesh Kumar K.V */ 74750c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_base = iov_base; 74850c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_len = iov_len; 74950c479e0SAneesh Kumar K.V pdu->out_iov_cnt = iov_cnt; 750c797b6c6SAneesh Kumar K.V 7514bc9734aSAneesh Kumar K.V if (res < 0) 7524bc9734aSAneesh Kumar K.V goto err_out; 7534bc9734aSAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", res); 754bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 755bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 756ead43b01SAneesh Kumar K.V return; 7574bc9734aSAneesh Kumar K.V err_out: 7584bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 7594bc9734aSAneesh Kumar K.V return; 7601c7850f9SSasha Levin } 7611c7850f9SSasha Levin 7626fc5cd9bSSasha Levin static void virtio_p9_remove(struct p9_dev *p9dev, 7636fc5cd9bSSasha Levin struct p9_pdu *pdu, u32 *outlen) 7646fc5cd9bSSasha Levin { 7656fc5cd9bSSasha Levin int ret; 7666fc5cd9bSSasha Levin u32 fid_val; 7676fc5cd9bSSasha Levin struct p9_fid *fid; 7686fc5cd9bSSasha Levin 7696fc5cd9bSSasha Levin virtio_p9_pdu_readf(pdu, "d", &fid_val); 77031a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 7716fc5cd9bSSasha Levin 7729b604a9cSSasha Levin ret = remove(fid->abs_path); 7736fc5cd9bSSasha Levin if (ret < 0) 7746fc5cd9bSSasha Levin goto err_out; 7756fc5cd9bSSasha Levin *outlen = pdu->write_offset; 7766fc5cd9bSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 7776fc5cd9bSSasha Levin return; 7786fc5cd9bSSasha Levin 7796fc5cd9bSSasha Levin err_out: 7806fc5cd9bSSasha Levin virtio_p9_error_reply(p9dev, pdu, errno, outlen); 7816fc5cd9bSSasha Levin return; 7826fc5cd9bSSasha Levin } 7836fc5cd9bSSasha Levin 784f161f28bSSasha Levin static void virtio_p9_rename(struct p9_dev *p9dev, 785f161f28bSSasha Levin struct p9_pdu *pdu, u32 *outlen) 786f161f28bSSasha Levin { 787f161f28bSSasha Levin int ret; 788f161f28bSSasha Levin u32 fid_val, new_fid_val; 789f161f28bSSasha Levin struct p9_fid *fid, *new_fid; 790f161f28bSSasha Levin char full_path[PATH_MAX], *new_name; 791f161f28bSSasha Levin 792f161f28bSSasha Levin virtio_p9_pdu_readf(pdu, "dds", &fid_val, &new_fid_val, &new_name); 79331a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 79431a6fb8dSSasha Levin new_fid = get_fid(p9dev, new_fid_val); 795f161f28bSSasha Levin 796f161f28bSSasha Levin sprintf(full_path, "%s/%s", new_fid->abs_path, new_name); 797f161f28bSSasha Levin ret = rename(fid->abs_path, full_path); 798f161f28bSSasha Levin if (ret < 0) 799f161f28bSSasha Levin goto err_out; 800f161f28bSSasha Levin *outlen = pdu->write_offset; 801f161f28bSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 802f161f28bSSasha Levin return; 803f161f28bSSasha Levin 804f161f28bSSasha Levin err_out: 805f161f28bSSasha Levin virtio_p9_error_reply(p9dev, pdu, errno, outlen); 806f161f28bSSasha Levin return; 807f161f28bSSasha Levin } 808f161f28bSSasha Levin 809c797b6c6SAneesh Kumar K.V static void virtio_p9_readlink(struct p9_dev *p9dev, 810c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 811c797b6c6SAneesh Kumar K.V { 812c797b6c6SAneesh Kumar K.V int ret; 813c797b6c6SAneesh Kumar K.V u32 fid_val; 814c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 815c797b6c6SAneesh Kumar K.V char target_path[PATH_MAX]; 816c797b6c6SAneesh Kumar K.V 817c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 81831a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 819c797b6c6SAneesh Kumar K.V 820c797b6c6SAneesh Kumar K.V memset(target_path, 0, PATH_MAX); 821c797b6c6SAneesh Kumar K.V ret = readlink(fid->abs_path, target_path, PATH_MAX - 1); 822c797b6c6SAneesh Kumar K.V if (ret < 0) 823c797b6c6SAneesh Kumar K.V goto err_out; 824c797b6c6SAneesh Kumar K.V 825c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "s", target_path); 826c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 827c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 828c797b6c6SAneesh Kumar K.V return; 829c797b6c6SAneesh Kumar K.V err_out: 830c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 831c797b6c6SAneesh Kumar K.V return; 832c797b6c6SAneesh Kumar K.V } 833c797b6c6SAneesh Kumar K.V 834c797b6c6SAneesh Kumar K.V static void virtio_p9_statfs(struct p9_dev *p9dev, 835c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 836c797b6c6SAneesh Kumar K.V { 837c797b6c6SAneesh Kumar K.V int ret; 838c797b6c6SAneesh Kumar K.V u64 fsid; 839c797b6c6SAneesh Kumar K.V u32 fid_val; 840c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 841c797b6c6SAneesh Kumar K.V struct statfs stat_buf; 842c797b6c6SAneesh Kumar K.V 843c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 84431a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 845c797b6c6SAneesh Kumar K.V 846c797b6c6SAneesh Kumar K.V ret = statfs(fid->abs_path, &stat_buf); 847c797b6c6SAneesh Kumar K.V if (ret < 0) 848c797b6c6SAneesh Kumar K.V goto err_out; 849c797b6c6SAneesh Kumar K.V /* FIXME!! f_blocks needs update based on client msize */ 850c797b6c6SAneesh Kumar K.V fsid = (unsigned int) stat_buf.f_fsid.__val[0] | 851c797b6c6SAneesh Kumar K.V (unsigned long long)stat_buf.f_fsid.__val[1] << 32; 852c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ddqqqqqqd", stat_buf.f_type, 853c797b6c6SAneesh Kumar K.V stat_buf.f_bsize, stat_buf.f_blocks, 854c797b6c6SAneesh Kumar K.V stat_buf.f_bfree, stat_buf.f_bavail, 855c797b6c6SAneesh Kumar K.V stat_buf.f_files, stat_buf.f_ffree, 856c797b6c6SAneesh Kumar K.V fsid, stat_buf.f_namelen); 857c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 858c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 859c797b6c6SAneesh Kumar K.V return; 860c797b6c6SAneesh Kumar K.V err_out: 861c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 862c797b6c6SAneesh Kumar K.V return; 863c797b6c6SAneesh Kumar K.V } 864c797b6c6SAneesh Kumar K.V 865c797b6c6SAneesh Kumar K.V static void virtio_p9_mknod(struct p9_dev *p9dev, 866c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 867c797b6c6SAneesh Kumar K.V { 868c797b6c6SAneesh Kumar K.V int ret; 869c797b6c6SAneesh Kumar K.V char *name; 870c797b6c6SAneesh Kumar K.V struct stat st; 871c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 872c797b6c6SAneesh Kumar K.V struct p9_qid qid; 873c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 874c797b6c6SAneesh Kumar K.V u32 fid_val, mode, major, minor, gid; 875c797b6c6SAneesh Kumar K.V 876c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdddd", &fid_val, &name, &mode, 877c797b6c6SAneesh Kumar K.V &major, &minor, &gid); 878c797b6c6SAneesh Kumar K.V 87931a6fb8dSSasha Levin dfid = get_fid(p9dev, fid_val); 880c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 881c797b6c6SAneesh Kumar K.V ret = mknod(full_path, mode, makedev(major, minor)); 882c797b6c6SAneesh Kumar K.V if (ret < 0) 883c797b6c6SAneesh Kumar K.V goto err_out; 884c797b6c6SAneesh Kumar K.V 885c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0) 886c797b6c6SAneesh Kumar K.V goto err_out; 887c797b6c6SAneesh Kumar K.V 888c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 889c797b6c6SAneesh Kumar K.V if (ret < 0) 890c797b6c6SAneesh Kumar K.V goto err_out; 891c797b6c6SAneesh Kumar K.V 892c797b6c6SAneesh Kumar K.V ret = lchown(full_path, dfid->uid, gid); 893c797b6c6SAneesh Kumar K.V if (ret < 0) 894c797b6c6SAneesh Kumar K.V goto err_out; 895c797b6c6SAneesh Kumar K.V 896c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 897c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 898c797b6c6SAneesh Kumar K.V free(name); 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 free(name); 904c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 905c797b6c6SAneesh Kumar K.V return; 906c797b6c6SAneesh Kumar K.V } 907c797b6c6SAneesh Kumar K.V 908c797b6c6SAneesh Kumar K.V static void virtio_p9_fsync(struct p9_dev *p9dev, 909c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 910c797b6c6SAneesh Kumar K.V { 911c797b6c6SAneesh Kumar K.V int ret; 912c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 913c797b6c6SAneesh Kumar K.V u32 fid_val, datasync; 914c797b6c6SAneesh Kumar K.V 915c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid_val, &datasync); 91631a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 917c797b6c6SAneesh Kumar K.V 918c797b6c6SAneesh Kumar K.V if (datasync) 919c797b6c6SAneesh Kumar K.V ret = fdatasync(fid->fd); 920c797b6c6SAneesh Kumar K.V else 921c797b6c6SAneesh Kumar K.V ret = fsync(fid->fd); 922c797b6c6SAneesh Kumar K.V if (ret < 0) 923c797b6c6SAneesh Kumar K.V goto err_out; 924c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 925c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 926c797b6c6SAneesh Kumar K.V return; 927c797b6c6SAneesh Kumar K.V err_out: 928c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 929c797b6c6SAneesh Kumar K.V return; 930c797b6c6SAneesh Kumar K.V } 931c797b6c6SAneesh Kumar K.V 932c797b6c6SAneesh Kumar K.V static void virtio_p9_symlink(struct p9_dev *p9dev, 933c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 934c797b6c6SAneesh Kumar K.V { 935c797b6c6SAneesh Kumar K.V int ret; 936c797b6c6SAneesh Kumar K.V struct stat st; 937c797b6c6SAneesh Kumar K.V u32 fid_val, gid; 938c797b6c6SAneesh Kumar K.V struct p9_qid qid; 939c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 940c797b6c6SAneesh Kumar K.V char new_name[PATH_MAX]; 941c797b6c6SAneesh Kumar K.V char *old_path, *name; 942c797b6c6SAneesh Kumar K.V 943c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dssd", &fid_val, &name, &old_path, &gid); 944c797b6c6SAneesh Kumar K.V 94531a6fb8dSSasha Levin dfid = get_fid(p9dev, fid_val); 946c797b6c6SAneesh Kumar K.V sprintf(new_name, "%s/%s", dfid->abs_path, name); 947c797b6c6SAneesh Kumar K.V ret = symlink(old_path, new_name); 948c797b6c6SAneesh Kumar K.V if (ret < 0) 949c797b6c6SAneesh Kumar K.V goto err_out; 950c797b6c6SAneesh Kumar K.V 951c797b6c6SAneesh Kumar K.V if (lstat(new_name, &st) < 0) 952c797b6c6SAneesh Kumar K.V goto err_out; 953c797b6c6SAneesh Kumar K.V 954c797b6c6SAneesh Kumar K.V ret = lchown(new_name, dfid->uid, gid); 955c797b6c6SAneesh Kumar K.V if (ret < 0) 956c797b6c6SAneesh Kumar K.V goto err_out; 957c797b6c6SAneesh Kumar K.V 958c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 959c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 960c797b6c6SAneesh Kumar K.V free(name); 961c797b6c6SAneesh Kumar K.V free(old_path); 962c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 963c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 964c797b6c6SAneesh Kumar K.V return; 965c797b6c6SAneesh Kumar K.V err_out: 966c797b6c6SAneesh Kumar K.V free(name); 967c797b6c6SAneesh Kumar K.V free(old_path); 968c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 969c797b6c6SAneesh Kumar K.V return; 970c797b6c6SAneesh Kumar K.V } 971c797b6c6SAneesh Kumar K.V 972c797b6c6SAneesh Kumar K.V static void virtio_p9_link(struct p9_dev *p9dev, 973c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 974c797b6c6SAneesh Kumar K.V { 975c797b6c6SAneesh Kumar K.V int ret; 976c797b6c6SAneesh Kumar K.V char *name; 977c797b6c6SAneesh Kumar K.V u32 fid_val, dfid_val; 978c797b6c6SAneesh Kumar K.V struct p9_fid *dfid, *fid; 979c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 980c797b6c6SAneesh Kumar K.V 981c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dds", &dfid_val, &fid_val, &name); 982c797b6c6SAneesh Kumar K.V 98331a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 98431a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 985c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 986c797b6c6SAneesh Kumar K.V ret = link(fid->abs_path, full_path); 987c797b6c6SAneesh Kumar K.V if (ret < 0) 988c797b6c6SAneesh Kumar K.V goto err_out; 989c797b6c6SAneesh Kumar K.V free(name); 990c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 991c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 992c797b6c6SAneesh Kumar K.V return; 993c797b6c6SAneesh Kumar K.V err_out: 994c797b6c6SAneesh Kumar K.V free(name); 995c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 996c797b6c6SAneesh Kumar K.V return; 997c797b6c6SAneesh Kumar K.V 998c797b6c6SAneesh Kumar K.V } 999c797b6c6SAneesh Kumar K.V 1000c797b6c6SAneesh Kumar K.V static void virtio_p9_lock(struct p9_dev *p9dev, 1001c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1002c797b6c6SAneesh Kumar K.V { 1003c797b6c6SAneesh Kumar K.V u8 ret; 1004c797b6c6SAneesh Kumar K.V u32 fid_val; 1005c797b6c6SAneesh Kumar K.V struct p9_flock flock; 1006c797b6c6SAneesh Kumar K.V 1007c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbdqqds", &fid_val, &flock.type, 1008c797b6c6SAneesh Kumar K.V &flock.flags, &flock.start, &flock.length, 1009c797b6c6SAneesh Kumar K.V &flock.proc_id, &flock.client_id); 1010c797b6c6SAneesh Kumar K.V 1011c797b6c6SAneesh Kumar K.V /* Just return success */ 1012c797b6c6SAneesh Kumar K.V ret = P9_LOCK_SUCCESS; 1013c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", ret); 1014c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1015c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1016c797b6c6SAneesh Kumar K.V free(flock.client_id); 1017c797b6c6SAneesh Kumar K.V return; 1018c797b6c6SAneesh Kumar K.V } 1019c797b6c6SAneesh Kumar K.V 1020c797b6c6SAneesh Kumar K.V static void virtio_p9_getlock(struct p9_dev *p9dev, 1021c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1022c797b6c6SAneesh Kumar K.V { 1023c797b6c6SAneesh Kumar K.V u32 fid_val; 1024c797b6c6SAneesh Kumar K.V struct p9_getlock glock; 1025c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbqqds", &fid_val, &glock.type, 1026c797b6c6SAneesh Kumar K.V &glock.start, &glock.length, &glock.proc_id, 1027c797b6c6SAneesh Kumar K.V &glock.client_id); 1028c797b6c6SAneesh Kumar K.V 1029c797b6c6SAneesh Kumar K.V /* Just return success */ 1030c797b6c6SAneesh Kumar K.V glock.type = F_UNLCK; 1031c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "bqqds", glock.type, 1032c797b6c6SAneesh Kumar K.V glock.start, glock.length, glock.proc_id, 1033c797b6c6SAneesh Kumar K.V glock.client_id); 1034c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1035c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1036c797b6c6SAneesh Kumar K.V free(glock.client_id); 1037c797b6c6SAneesh Kumar K.V return; 1038c797b6c6SAneesh Kumar K.V } 1039c797b6c6SAneesh Kumar K.V 1040c797b6c6SAneesh Kumar K.V static int virtio_p9_ancestor(char *path, char *ancestor) 1041c797b6c6SAneesh Kumar K.V { 1042c797b6c6SAneesh Kumar K.V int size = strlen(ancestor); 1043c797b6c6SAneesh Kumar K.V if (!strncmp(path, ancestor, size)) { 1044c797b6c6SAneesh Kumar K.V /* 1045c797b6c6SAneesh Kumar K.V * Now check whether ancestor is a full name or 1046c797b6c6SAneesh Kumar K.V * or directory component and not just part 1047c797b6c6SAneesh Kumar K.V * of a name. 1048c797b6c6SAneesh Kumar K.V */ 1049c797b6c6SAneesh Kumar K.V if (path[size] == '\0' || path[size] == '/') 1050c797b6c6SAneesh Kumar K.V return 1; 1051c797b6c6SAneesh Kumar K.V } 1052c797b6c6SAneesh Kumar K.V return 0; 1053c797b6c6SAneesh Kumar K.V } 1054c797b6c6SAneesh Kumar K.V 1055c797b6c6SAneesh Kumar K.V static void virtio_p9_fix_path(char *fid_path, char *old_name, char *new_name) 1056c797b6c6SAneesh Kumar K.V { 1057c797b6c6SAneesh Kumar K.V char tmp_name[PATH_MAX]; 1058c797b6c6SAneesh Kumar K.V size_t rp_sz = strlen(old_name); 1059c797b6c6SAneesh Kumar K.V 1060c797b6c6SAneesh Kumar K.V if (rp_sz == strlen(fid_path)) { 1061c797b6c6SAneesh Kumar K.V /* replace the full name */ 1062c797b6c6SAneesh Kumar K.V strcpy(fid_path, new_name); 1063c797b6c6SAneesh Kumar K.V return; 1064c797b6c6SAneesh Kumar K.V } 1065c797b6c6SAneesh Kumar K.V /* save the trailing path details */ 1066c797b6c6SAneesh Kumar K.V strcpy(tmp_name, fid_path + rp_sz); 1067c797b6c6SAneesh Kumar K.V sprintf(fid_path, "%s%s", new_name, tmp_name); 1068c797b6c6SAneesh Kumar K.V return; 1069c797b6c6SAneesh Kumar K.V } 1070c797b6c6SAneesh Kumar K.V 1071e2341580SSasha Levin static void rename_fids(struct p9_dev *p9dev, char *old_name, char *new_name) 1072e2341580SSasha Levin { 1073e2341580SSasha Levin struct rb_node *node = rb_first(&p9dev->fids); 1074e2341580SSasha Levin 1075e2341580SSasha Levin while (node) { 1076e2341580SSasha Levin struct p9_fid *fid = rb_entry(node, struct p9_fid, node); 1077e2341580SSasha Levin 1078e2341580SSasha Levin if (fid->fid != P9_NOFID && virtio_p9_ancestor(fid->path, old_name)) { 1079e2341580SSasha Levin virtio_p9_fix_path(fid->path, old_name, new_name); 1080e2341580SSasha Levin } 1081e2341580SSasha Levin node = rb_next(node); 1082e2341580SSasha Levin } 1083e2341580SSasha Levin } 1084e2341580SSasha Levin 1085c797b6c6SAneesh Kumar K.V static void virtio_p9_renameat(struct p9_dev *p9dev, 1086c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1087c797b6c6SAneesh Kumar K.V { 1088e2341580SSasha Levin int ret; 1089c797b6c6SAneesh Kumar K.V char *old_name, *new_name; 1090c797b6c6SAneesh Kumar K.V u32 old_dfid_val, new_dfid_val; 1091c797b6c6SAneesh Kumar K.V struct p9_fid *old_dfid, *new_dfid; 1092c797b6c6SAneesh Kumar K.V char old_full_path[PATH_MAX], new_full_path[PATH_MAX]; 1093c797b6c6SAneesh Kumar K.V 1094c797b6c6SAneesh Kumar K.V 1095c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsds", &old_dfid_val, &old_name, 1096c797b6c6SAneesh Kumar K.V &new_dfid_val, &new_name); 1097c797b6c6SAneesh Kumar K.V 109831a6fb8dSSasha Levin old_dfid = get_fid(p9dev, old_dfid_val); 109931a6fb8dSSasha Levin new_dfid = get_fid(p9dev, new_dfid_val); 1100c797b6c6SAneesh Kumar K.V 1101c797b6c6SAneesh Kumar K.V sprintf(old_full_path, "%s/%s", old_dfid->abs_path, old_name); 1102c797b6c6SAneesh Kumar K.V sprintf(new_full_path, "%s/%s", new_dfid->abs_path, new_name); 1103c797b6c6SAneesh Kumar K.V ret = rename(old_full_path, new_full_path); 1104c797b6c6SAneesh Kumar K.V if (ret < 0) 1105c797b6c6SAneesh Kumar K.V goto err_out; 1106c797b6c6SAneesh Kumar K.V /* 1107c797b6c6SAneesh Kumar K.V * Now fix path in other fids, if the renamed path is part of 1108c797b6c6SAneesh Kumar K.V * that. 1109c797b6c6SAneesh Kumar K.V */ 1110e2341580SSasha Levin rename_fids(p9dev, old_name, new_name); 1111c797b6c6SAneesh Kumar K.V free(old_name); 1112c797b6c6SAneesh Kumar K.V free(new_name); 1113c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1114c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1115c797b6c6SAneesh Kumar K.V return; 1116c797b6c6SAneesh Kumar K.V err_out: 1117c797b6c6SAneesh Kumar K.V free(old_name); 1118c797b6c6SAneesh Kumar K.V free(new_name); 1119c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1120c797b6c6SAneesh Kumar K.V return; 1121c797b6c6SAneesh Kumar K.V } 1122c797b6c6SAneesh Kumar K.V 1123c797b6c6SAneesh Kumar K.V static void virtio_p9_unlinkat(struct p9_dev *p9dev, 1124c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1125c797b6c6SAneesh Kumar K.V { 1126c797b6c6SAneesh Kumar K.V int ret; 1127c797b6c6SAneesh Kumar K.V char *name; 1128c797b6c6SAneesh Kumar K.V u32 fid_val, flags; 1129c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 1130c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 1131c797b6c6SAneesh Kumar K.V 1132c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsd", &fid_val, &name, &flags); 113331a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 1134c797b6c6SAneesh Kumar K.V 1135c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", fid->abs_path, name); 1136c797b6c6SAneesh Kumar K.V ret = remove(full_path); 1137c797b6c6SAneesh Kumar K.V if (ret < 0) 1138c797b6c6SAneesh Kumar K.V goto err_out; 1139c797b6c6SAneesh Kumar K.V free(name); 1140c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1141c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1142c797b6c6SAneesh Kumar K.V return; 1143c797b6c6SAneesh Kumar K.V err_out: 1144c797b6c6SAneesh Kumar K.V free(name); 1145c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1146c797b6c6SAneesh Kumar K.V return; 1147c797b6c6SAneesh Kumar K.V } 1148c797b6c6SAneesh Kumar K.V 11495cc808aaSSasha Levin static void virtio_p9_flush(struct p9_dev *p9dev, 11505cc808aaSSasha Levin struct p9_pdu *pdu, u32 *outlen) 11515cc808aaSSasha Levin { 11525cc808aaSSasha Levin u16 tag, oldtag; 11535cc808aaSSasha Levin 11545cc808aaSSasha Levin virtio_p9_pdu_readf(pdu, "ww", &tag, &oldtag); 11555cc808aaSSasha Levin virtio_p9_pdu_writef(pdu, "w", tag); 11565cc808aaSSasha Levin *outlen = pdu->write_offset; 11575cc808aaSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 11585cc808aaSSasha Levin 11595cc808aaSSasha Levin return; 11605cc808aaSSasha Levin } 11615cc808aaSSasha Levin 1162c797b6c6SAneesh Kumar K.V static void virtio_p9_eopnotsupp(struct p9_dev *p9dev, 1163c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1164c797b6c6SAneesh Kumar K.V { 1165c797b6c6SAneesh Kumar K.V return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen); 1166c797b6c6SAneesh Kumar K.V } 1167c797b6c6SAneesh Kumar K.V 1168ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev, 1169af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen); 1170b4422bf3SAneesh Kumar K.V 1171c797b6c6SAneesh Kumar K.V /* FIXME should be removed when merging with latest linus tree */ 1172c797b6c6SAneesh Kumar K.V #define P9_TRENAMEAT 74 1173c797b6c6SAneesh Kumar K.V #define P9_TUNLINKAT 76 1174c797b6c6SAneesh Kumar K.V 1175c797b6c6SAneesh Kumar K.V static p9_handler *virtio_9p_dotl_handler [] = { 1176c797b6c6SAneesh Kumar K.V [P9_TREADDIR] = virtio_p9_readdir, 1177c797b6c6SAneesh Kumar K.V [P9_TSTATFS] = virtio_p9_statfs, 1178c797b6c6SAneesh Kumar K.V [P9_TGETATTR] = virtio_p9_getattr, 1179c797b6c6SAneesh Kumar K.V [P9_TSETATTR] = virtio_p9_setattr, 1180c797b6c6SAneesh Kumar K.V [P9_TXATTRWALK] = virtio_p9_eopnotsupp, 1181c797b6c6SAneesh Kumar K.V [P9_TXATTRCREATE] = virtio_p9_eopnotsupp, 1182c797b6c6SAneesh Kumar K.V [P9_TMKNOD] = virtio_p9_mknod, 1183c797b6c6SAneesh Kumar K.V [P9_TLOCK] = virtio_p9_lock, 1184c797b6c6SAneesh Kumar K.V [P9_TGETLOCK] = virtio_p9_getlock, 1185c797b6c6SAneesh Kumar K.V [P9_TRENAMEAT] = virtio_p9_renameat, 1186c797b6c6SAneesh Kumar K.V [P9_TREADLINK] = virtio_p9_readlink, 1187c797b6c6SAneesh Kumar K.V [P9_TUNLINKAT] = virtio_p9_unlinkat, 1188c797b6c6SAneesh Kumar K.V [P9_TMKDIR] = virtio_p9_mkdir, 1189b4422bf3SAneesh Kumar K.V [P9_TVERSION] = virtio_p9_version, 1190c797b6c6SAneesh Kumar K.V [P9_TLOPEN] = virtio_p9_open, 1191b4422bf3SAneesh Kumar K.V [P9_TATTACH] = virtio_p9_attach, 1192b4422bf3SAneesh Kumar K.V [P9_TWALK] = virtio_p9_walk, 1193c797b6c6SAneesh Kumar K.V [P9_TCLUNK] = virtio_p9_clunk, 1194c797b6c6SAneesh Kumar K.V [P9_TFSYNC] = virtio_p9_fsync, 1195b4422bf3SAneesh Kumar K.V [P9_TREAD] = virtio_p9_read, 11965cc808aaSSasha Levin [P9_TFLUSH] = virtio_p9_flush, 1197c797b6c6SAneesh Kumar K.V [P9_TLINK] = virtio_p9_link, 1198c797b6c6SAneesh Kumar K.V [P9_TSYMLINK] = virtio_p9_symlink, 1199c797b6c6SAneesh Kumar K.V [P9_TLCREATE] = virtio_p9_create, 1200b4422bf3SAneesh Kumar K.V [P9_TWRITE] = virtio_p9_write, 12016fc5cd9bSSasha Levin [P9_TREMOVE] = virtio_p9_remove, 1202f161f28bSSasha Levin [P9_TRENAME] = virtio_p9_rename, 1203b4422bf3SAneesh Kumar K.V }; 1204b4422bf3SAneesh Kumar K.V 1205af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq) 1206af045e53SAneesh Kumar K.V { 1207af045e53SAneesh Kumar K.V struct p9_pdu *pdu = calloc(1, sizeof(*pdu)); 1208af045e53SAneesh Kumar K.V if (!pdu) 1209af045e53SAneesh Kumar K.V return NULL; 1210af045e53SAneesh Kumar K.V 1211bfc15268SAneesh Kumar K.V /* skip the pdu header p9_msg */ 12125529bcd7SAsias He pdu->read_offset = VIRTIO_9P_HDR_LEN; 12135529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 1214af045e53SAneesh Kumar K.V pdu->queue_head = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov, 1215a8a44649SAsias He pdu->out_iov, &pdu->in_iov_cnt, &pdu->out_iov_cnt); 1216af045e53SAneesh Kumar K.V return pdu; 1217af045e53SAneesh Kumar K.V } 1218af045e53SAneesh Kumar K.V 1219af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu) 1220af045e53SAneesh Kumar K.V { 1221af045e53SAneesh Kumar K.V struct p9_msg *msg; 1222af045e53SAneesh Kumar K.V /* 1223af045e53SAneesh Kumar K.V * we can peek directly into pdu for a u8 1224af045e53SAneesh Kumar K.V * value. The host endianess won't be an issue 1225af045e53SAneesh Kumar K.V */ 1226af045e53SAneesh Kumar K.V msg = pdu->out_iov[0].iov_base; 1227af045e53SAneesh Kumar K.V return msg->cmd; 1228af045e53SAneesh Kumar K.V } 1229af045e53SAneesh Kumar K.V 1230b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job) 12311c7850f9SSasha Levin { 1232af045e53SAneesh Kumar K.V u8 cmd; 1233b4422bf3SAneesh Kumar K.V u32 len = 0; 1234b4422bf3SAneesh Kumar K.V p9_handler *handler; 1235b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 1236af045e53SAneesh Kumar K.V struct virt_queue *vq; 1237af045e53SAneesh Kumar K.V struct p9_pdu *p9pdu; 12381c7850f9SSasha Levin 1239b4422bf3SAneesh Kumar K.V vq = job->vq; 1240b4422bf3SAneesh Kumar K.V p9dev = job->p9dev; 12411c7850f9SSasha Levin 1242af045e53SAneesh Kumar K.V p9pdu = virtio_p9_pdu_init(kvm, vq); 1243af045e53SAneesh Kumar K.V cmd = virtio_p9_get_cmd(p9pdu); 1244af045e53SAneesh Kumar K.V 1245c797b6c6SAneesh Kumar K.V if ((cmd >= ARRAY_SIZE(virtio_9p_dotl_handler)) || 1246c797b6c6SAneesh Kumar K.V !virtio_9p_dotl_handler[cmd]) 124797b408afSAneesh Kumar K.V handler = virtio_p9_eopnotsupp; 1248dd78d9eaSAneesh Kumar K.V else 1249c797b6c6SAneesh Kumar K.V handler = virtio_9p_dotl_handler[cmd]; 1250c797b6c6SAneesh Kumar K.V 1251af045e53SAneesh Kumar K.V handler(p9dev, p9pdu, &len); 1252af045e53SAneesh Kumar K.V virt_queue__set_used_elem(vq, p9pdu->queue_head, len); 1253af045e53SAneesh Kumar K.V free(p9pdu); 12541c7850f9SSasha Levin return true; 12551c7850f9SSasha Levin } 12561c7850f9SSasha Levin 12571c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param) 12581c7850f9SSasha Levin { 1259b4422bf3SAneesh Kumar K.V struct p9_dev_job *job = (struct p9_dev_job *)param; 1260b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = job->p9dev; 1261b4422bf3SAneesh Kumar K.V struct virt_queue *vq = job->vq; 12621c7850f9SSasha Levin 12631c7850f9SSasha Levin while (virt_queue__available(vq)) { 1264b4422bf3SAneesh Kumar K.V virtio_p9_do_io_request(kvm, job); 126502eca50cSAsias He p9dev->vdev.ops->signal_vq(kvm, &p9dev->vdev, vq - p9dev->vqs); 12661c7850f9SSasha Levin } 12671c7850f9SSasha Levin } 12681c7850f9SSasha Levin 1269c7838fbdSSasha Levin static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset) 12701c7850f9SSasha Levin { 1271c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 12721c7850f9SSasha Levin 1273c7838fbdSSasha Levin ((u8 *)(p9dev->config))[offset] = data; 1274c7838fbdSSasha Levin } 12751c7850f9SSasha Levin 1276c7838fbdSSasha Levin static u8 get_config(struct kvm *kvm, void *dev, u32 offset) 1277c7838fbdSSasha Levin { 1278c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1279c7838fbdSSasha Levin 1280c7838fbdSSasha Levin return ((u8 *)(p9dev->config))[offset]; 1281c7838fbdSSasha Levin } 1282c7838fbdSSasha Levin 1283c7838fbdSSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev) 1284c7838fbdSSasha Levin { 1285c7838fbdSSasha Levin return 1 << VIRTIO_9P_MOUNT_TAG; 1286c7838fbdSSasha Levin } 1287c7838fbdSSasha Levin 1288c7838fbdSSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features) 1289c7838fbdSSasha Levin { 1290c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1291c7838fbdSSasha Levin 1292c7838fbdSSasha Levin p9dev->features = features; 1293c7838fbdSSasha Levin } 1294c7838fbdSSasha Levin 1295c7838fbdSSasha Levin static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn) 1296c7838fbdSSasha Levin { 1297c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1298b4422bf3SAneesh Kumar K.V struct p9_dev_job *job; 1299b4422bf3SAneesh Kumar K.V struct virt_queue *queue; 1300c7838fbdSSasha Levin void *p; 13011c7850f9SSasha Levin 1302312c62d1SSasha Levin compat__remove_message(compat_id); 1303e59662b3SSasha Levin 1304c7838fbdSSasha Levin queue = &p9dev->vqs[vq]; 1305c7838fbdSSasha Levin queue->pfn = pfn; 13061c7850f9SSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 1307c7838fbdSSasha Levin job = &p9dev->jobs[vq]; 13081c7850f9SSasha Levin 1309c7838fbdSSasha Levin vring_init(&queue->vring, VIRTQUEUE_NUM, p, VIRTIO_PCI_VRING_ALIGN); 13101c7850f9SSasha Levin 1311b4422bf3SAneesh Kumar K.V *job = (struct p9_dev_job) { 1312b4422bf3SAneesh Kumar K.V .vq = queue, 1313b4422bf3SAneesh Kumar K.V .p9dev = p9dev, 1314b4422bf3SAneesh Kumar K.V }; 1315df0c7f57SSasha Levin thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job); 131660eb42d5SSasha Levin 1317c7838fbdSSasha Levin return 0; 13181c7850f9SSasha Levin } 13191c7850f9SSasha Levin 1320c7838fbdSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 1321c7838fbdSSasha Levin { 1322c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 13231c7850f9SSasha Levin 1324c7838fbdSSasha Levin thread_pool__do_job(&p9dev->jobs[vq].job_id); 1325c7838fbdSSasha Levin 1326c7838fbdSSasha Levin return 0; 1327c7838fbdSSasha Levin } 1328c7838fbdSSasha Levin 1329c7838fbdSSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq) 1330c7838fbdSSasha Levin { 1331c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1332c7838fbdSSasha Levin 1333c7838fbdSSasha Levin return p9dev->vqs[vq].pfn; 1334c7838fbdSSasha Levin } 1335c7838fbdSSasha Levin 1336c7838fbdSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 1337c7838fbdSSasha Levin { 1338c7838fbdSSasha Levin return VIRTQUEUE_NUM; 1339c7838fbdSSasha Levin } 1340c7838fbdSSasha Levin 13411c47ce69SSasha Levin struct virtio_ops p9_dev_virtio_ops = (struct virtio_ops) { 1342c7838fbdSSasha Levin .set_config = set_config, 1343c7838fbdSSasha Levin .get_config = get_config, 1344c7838fbdSSasha Levin .get_host_features = get_host_features, 1345c7838fbdSSasha Levin .set_guest_features = set_guest_features, 1346c7838fbdSSasha Levin .init_vq = init_vq, 1347c7838fbdSSasha Levin .notify_vq = notify_vq, 1348c7838fbdSSasha Levin .get_pfn_vq = get_pfn_vq, 1349c7838fbdSSasha Levin .get_size_vq = get_size_vq, 1350c7838fbdSSasha Levin }; 13511c47ce69SSasha Levin 13521c47ce69SSasha Levin int virtio_9p__init(struct kvm *kvm) 13531c47ce69SSasha Levin { 13541c47ce69SSasha Levin struct p9_dev *p9dev; 13551c47ce69SSasha Levin 13561c47ce69SSasha Levin list_for_each_entry(p9dev, &devs, list) { 135702eca50cSAsias He virtio_init(kvm, p9dev, &p9dev->vdev, &p9_dev_virtio_ops, 13585529bcd7SAsias He VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_9P, VIRTIO_ID_9P, PCI_CLASS_9P); 1359c7838fbdSSasha Levin } 1360c7838fbdSSasha Levin 1361c7838fbdSSasha Levin return 0; 1362c7838fbdSSasha Levin } 1363c7838fbdSSasha Levin 1364c7838fbdSSasha Levin int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name) 1365c7838fbdSSasha Levin { 1366c7838fbdSSasha Levin struct p9_dev *p9dev; 136754f6802dSPekka Enberg int err = 0; 13681c7850f9SSasha Levin 1369b4422bf3SAneesh Kumar K.V p9dev = calloc(1, sizeof(*p9dev)); 1370b4422bf3SAneesh Kumar K.V if (!p9dev) 137154f6802dSPekka Enberg return -ENOMEM; 137254f6802dSPekka Enberg 1373b4422bf3SAneesh Kumar K.V if (!tag_name) 13745529bcd7SAsias He tag_name = VIRTIO_9P_DEFAULT_TAG; 137554f6802dSPekka Enberg 1376b4422bf3SAneesh Kumar K.V p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1); 137754f6802dSPekka Enberg if (p9dev->config == NULL) { 137854f6802dSPekka Enberg err = -ENOMEM; 1379b4422bf3SAneesh Kumar K.V goto free_p9dev; 138054f6802dSPekka Enberg } 13811c7850f9SSasha Levin 1382b4422bf3SAneesh Kumar K.V strcpy(p9dev->root_dir, root); 1383b4422bf3SAneesh Kumar K.V p9dev->config->tag_len = strlen(tag_name); 138454f6802dSPekka Enberg if (p9dev->config->tag_len > MAX_TAG_LEN) { 138554f6802dSPekka Enberg err = -EINVAL; 1386b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 138754f6802dSPekka Enberg } 13881c7850f9SSasha Levin 1389c7838fbdSSasha Levin memcpy(&p9dev->config->tag, tag_name, strlen(tag_name)); 13901c7850f9SSasha Levin 1391c7838fbdSSasha Levin list_add(&p9dev->list, &devs); 1392b4422bf3SAneesh Kumar K.V 1393d278197dSAsias He if (compat_id == -1) 139452f34d2cSAsias He compat_id = virtio_compat_add_message("virtio-9p", "CONFIG_NET_9P_VIRTIO"); 1395e59662b3SSasha Levin 139654f6802dSPekka Enberg return err; 139754f6802dSPekka Enberg 1398b4422bf3SAneesh Kumar K.V free_p9dev_config: 1399b4422bf3SAneesh Kumar K.V free(p9dev->config); 1400b4422bf3SAneesh Kumar K.V free_p9dev: 1401b4422bf3SAneesh Kumar K.V free(p9dev); 140254f6802dSPekka Enberg return err; 14031c7850f9SSasha Levin } 1404