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" 560eb42d5SSasha Levin #include "kvm/ioeventfd.h" 6bfc15268SAneesh Kumar K.V #include "kvm/irq.h" 7bfc15268SAneesh Kumar K.V #include "kvm/virtio-9p.h" 8e59662b3SSasha Levin #include "kvm/guest_compat.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> 212daa28d4SAneesh Kumar K.V #include <net/9p/9p.h> 222daa28d4SAneesh Kumar K.V 23c7838fbdSSasha Levin static LIST_HEAD(devs); 24c7838fbdSSasha Levin 251c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */ 26b4422bf3SAneesh Kumar K.V static const char *rel_to_abs(struct p9_dev *p9dev, 27b4422bf3SAneesh Kumar K.V const char *path, char *abs_path) 281c7850f9SSasha Levin { 29b4422bf3SAneesh Kumar K.V sprintf(abs_path, "%s/%s", p9dev->root_dir, path); 301c7850f9SSasha Levin 311c7850f9SSasha Levin return abs_path; 321c7850f9SSasha Levin } 331c7850f9SSasha Levin 34c797b6c6SAneesh Kumar K.V static void stat2qid(struct stat *st, struct p9_qid *qid) 351c7850f9SSasha Levin { 361c7850f9SSasha Levin *qid = (struct p9_qid) { 371c7850f9SSasha Levin .path = st->st_ino, 381c7850f9SSasha Levin .version = st->st_mtime, 391c7850f9SSasha Levin }; 401c7850f9SSasha Levin 411c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) 421c7850f9SSasha Levin qid->type |= P9_QTDIR; 431c7850f9SSasha Levin } 441c7850f9SSasha Levin 45b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid) 461c7850f9SSasha Levin { 47b4422bf3SAneesh Kumar K.V if (p9dev->fids[fid].fd > 0) { 48b4422bf3SAneesh Kumar K.V close(p9dev->fids[fid].fd); 49b4422bf3SAneesh Kumar K.V p9dev->fids[fid].fd = -1; 501c7850f9SSasha Levin } 51b4422bf3SAneesh Kumar K.V if (p9dev->fids[fid].dir) { 52b4422bf3SAneesh Kumar K.V closedir(p9dev->fids[fid].dir); 53b4422bf3SAneesh Kumar K.V p9dev->fids[fid].dir = NULL; 541c7850f9SSasha Levin } 55c797b6c6SAneesh Kumar K.V p9dev->fids[fid].fid = P9_NOFID; 561c7850f9SSasha Levin } 571c7850f9SSasha Levin 58bfc15268SAneesh Kumar K.V static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size) 591c7850f9SSasha Levin { 60bfc15268SAneesh Kumar K.V u8 cmd; 61bfc15268SAneesh Kumar K.V u16 tag; 62bfc15268SAneesh Kumar K.V 63bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32); 64bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag); 65bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 66bfc15268SAneesh Kumar K.V /* cmd + 1 is the reply message */ 67bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag); 681c7850f9SSasha Levin } 691c7850f9SSasha Levin 706b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt) 716b163a87SAneesh Kumar K.V { 726b163a87SAneesh Kumar K.V int i; 736b163a87SAneesh Kumar K.V u32 total = 0; 746b163a87SAneesh Kumar K.V for (i = 0; (i < iov_cnt) && (total < count); i++) { 756b163a87SAneesh Kumar K.V if (total + iov[i].iov_len > count) { 766b163a87SAneesh Kumar K.V /* we don't need this iov fully */ 776b163a87SAneesh Kumar K.V iov[i].iov_len -= ((total + iov[i].iov_len) - count); 786b163a87SAneesh Kumar K.V i++; 796b163a87SAneesh Kumar K.V break; 806b163a87SAneesh Kumar K.V } 816b163a87SAneesh Kumar K.V total += iov[i].iov_len; 826b163a87SAneesh Kumar K.V } 836b163a87SAneesh Kumar K.V return i; 846b163a87SAneesh Kumar K.V } 856b163a87SAneesh Kumar K.V 86eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev, 87eee1ba8eSAneesh Kumar K.V struct p9_pdu *pdu, int err, u32 *outlen) 88eee1ba8eSAneesh Kumar K.V { 89bfc15268SAneesh Kumar K.V u16 tag; 90eee1ba8eSAneesh Kumar K.V 91bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 92c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", err); 93bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 94eee1ba8eSAneesh Kumar K.V 95c797b6c6SAneesh Kumar K.V /* read the tag from input */ 96bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32) + sizeof(u8); 97bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "w", &tag); 98bfc15268SAneesh Kumar K.V 99c797b6c6SAneesh Kumar K.V /* Update the header */ 100bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 101c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RLERROR, tag); 102eee1ba8eSAneesh Kumar K.V } 103eee1ba8eSAneesh Kumar K.V 104ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev, 105af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1061c7850f9SSasha Levin { 107c797b6c6SAneesh Kumar K.V u32 msize; 108c797b6c6SAneesh Kumar K.V char *version; 109c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ds", &msize, &version); 110c797b6c6SAneesh Kumar K.V /* 111c797b6c6SAneesh Kumar K.V * reply with the same msize the client sent us 112c797b6c6SAneesh Kumar K.V * Error out if the request is not for 9P2000.L 113c797b6c6SAneesh Kumar K.V */ 114c797b6c6SAneesh Kumar K.V if (!strcmp(version, VIRTIO_P9_VERSION_DOTL)) 115c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, version); 116c797b6c6SAneesh Kumar K.V else 117c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, "unknown"); 1181c7850f9SSasha Levin 119bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 120bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 121c797b6c6SAneesh Kumar K.V free(version); 122ead43b01SAneesh Kumar K.V return; 1231c7850f9SSasha Levin } 1241c7850f9SSasha Levin 125ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev, 126af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1271c7850f9SSasha Levin { 128bfc15268SAneesh Kumar K.V u32 fid; 1291c7850f9SSasha Levin 130bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid); 131bfc15268SAneesh Kumar K.V close_fid(p9dev, fid); 1321c7850f9SSasha Levin 133bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 134bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 135ead43b01SAneesh Kumar K.V return; 1361c7850f9SSasha Levin } 1371c7850f9SSasha Levin 138c797b6c6SAneesh Kumar K.V /* 139c797b6c6SAneesh Kumar K.V * FIXME!! Need to map to protocol independent value. Upstream 140c797b6c6SAneesh Kumar K.V * 9p also have the same BUG 141c797b6c6SAneesh Kumar K.V */ 142c797b6c6SAneesh Kumar K.V static int virtio_p9_openflags(int flags) 143c797b6c6SAneesh Kumar K.V { 144c797b6c6SAneesh Kumar K.V flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT | O_DIRECT); 145c797b6c6SAneesh Kumar K.V flags |= O_NOFOLLOW; 146c797b6c6SAneesh Kumar K.V return flags; 147c797b6c6SAneesh Kumar K.V } 148c797b6c6SAneesh Kumar K.V 149ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev, 150af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1511c7850f9SSasha Levin { 152c797b6c6SAneesh Kumar K.V u32 fid, flags; 1531c7850f9SSasha Levin struct stat st; 154bfc15268SAneesh Kumar K.V struct p9_qid qid; 155bfc15268SAneesh Kumar K.V struct p9_fid *new_fid; 156bfc15268SAneesh Kumar K.V 157c797b6c6SAneesh Kumar K.V 158c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid, &flags); 159bfc15268SAneesh Kumar K.V new_fid = &p9dev->fids[fid]; 1601c7850f9SSasha Levin 16130204a77SAneesh Kumar K.V if (lstat(new_fid->abs_path, &st) < 0) 162eee1ba8eSAneesh Kumar K.V goto err_out; 1631c7850f9SSasha Levin 164c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 1651c7850f9SSasha Levin 166eee1ba8eSAneesh Kumar K.V if (new_fid->is_dir) { 1671c7850f9SSasha Levin new_fid->dir = opendir(new_fid->abs_path); 168eee1ba8eSAneesh Kumar K.V if (!new_fid->dir) 169eee1ba8eSAneesh Kumar K.V goto err_out; 170eee1ba8eSAneesh Kumar K.V } else { 171eee1ba8eSAneesh Kumar K.V new_fid->fd = open(new_fid->abs_path, 172c797b6c6SAneesh Kumar K.V virtio_p9_openflags(flags)); 173eee1ba8eSAneesh Kumar K.V if (new_fid->fd < 0) 174eee1ba8eSAneesh Kumar K.V goto err_out; 175eee1ba8eSAneesh Kumar K.V } 176c797b6c6SAneesh Kumar K.V /* FIXME!! need ot send proper iounit */ 177bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 178bfc15268SAneesh Kumar K.V 179bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 180bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 181ead43b01SAneesh Kumar K.V return; 182eee1ba8eSAneesh Kumar K.V err_out: 183eee1ba8eSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 184ead43b01SAneesh Kumar K.V return; 1851c7850f9SSasha Levin } 1861c7850f9SSasha Levin 187ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev, 188af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1891c7850f9SSasha Levin { 190c797b6c6SAneesh Kumar K.V int fd, ret; 191bfc15268SAneesh Kumar K.V char *name; 192af045e53SAneesh Kumar K.V struct stat st; 193bfc15268SAneesh Kumar K.V struct p9_qid qid; 194c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 1954bc9734aSAneesh Kumar K.V char full_path[PATH_MAX]; 196c797b6c6SAneesh Kumar K.V u32 dfid_val, flags, mode, gid; 197af045e53SAneesh Kumar K.V 198c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsddd", &dfid_val, 199c797b6c6SAneesh Kumar K.V &name, &flags, &mode, &gid); 200c797b6c6SAneesh Kumar K.V dfid = &p9dev->fids[dfid_val]; 2011c7850f9SSasha Levin 202c797b6c6SAneesh Kumar K.V flags = virtio_p9_openflags(flags); 2035f900f6dSSasha Levin 204c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 205c797b6c6SAneesh Kumar K.V fd = open(full_path, flags | O_CREAT, mode); 2064bc9734aSAneesh Kumar K.V if (fd < 0) 2074bc9734aSAneesh Kumar K.V goto err_out; 208c797b6c6SAneesh Kumar K.V close_fid(p9dev, dfid_val); 209c797b6c6SAneesh Kumar K.V dfid->fd = fd; 210c797b6c6SAneesh Kumar K.V 2114bc9734aSAneesh Kumar K.V if (lstat(full_path, &st) < 0) 2126c8ca053SAneesh Kumar K.V goto err_out; 2131c7850f9SSasha Levin 214c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 215c797b6c6SAneesh Kumar K.V if (ret < 0) 216c797b6c6SAneesh Kumar K.V goto err_out; 217c797b6c6SAneesh Kumar K.V 218c797b6c6SAneesh Kumar K.V ret = lchown(full_path, dfid->uid, gid); 219c797b6c6SAneesh Kumar K.V if (ret < 0) 220c797b6c6SAneesh Kumar K.V goto err_out; 221c797b6c6SAneesh Kumar K.V 222c797b6c6SAneesh Kumar K.V sprintf(dfid->path, "%s/%s", dfid->path, name); 223c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 224bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 225bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 226bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 2275f900f6dSSasha Levin free(name); 2286c8ca053SAneesh Kumar K.V return; 2296c8ca053SAneesh Kumar K.V err_out: 2305f900f6dSSasha Levin free(name); 231c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 232c797b6c6SAneesh Kumar K.V return; 233c797b6c6SAneesh Kumar K.V } 234c797b6c6SAneesh Kumar K.V 235c797b6c6SAneesh Kumar K.V static void virtio_p9_mkdir(struct p9_dev *p9dev, 236c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 237c797b6c6SAneesh Kumar K.V { 238c797b6c6SAneesh Kumar K.V int ret; 239c797b6c6SAneesh Kumar K.V char *name; 240c797b6c6SAneesh Kumar K.V struct stat st; 241c797b6c6SAneesh Kumar K.V struct p9_qid qid; 242c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 243c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 244c797b6c6SAneesh Kumar K.V u32 dfid_val, mode, gid; 245c797b6c6SAneesh Kumar K.V 246c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdd", &dfid_val, 247c797b6c6SAneesh Kumar K.V &name, &mode, &gid); 248c797b6c6SAneesh Kumar K.V dfid = &p9dev->fids[dfid_val]; 249c797b6c6SAneesh Kumar K.V 250c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 251c797b6c6SAneesh Kumar K.V ret = mkdir(full_path, mode); 252c797b6c6SAneesh Kumar K.V if (ret < 0) 253c797b6c6SAneesh Kumar K.V goto err_out; 254c797b6c6SAneesh Kumar K.V 255c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0) 256c797b6c6SAneesh Kumar K.V goto err_out; 257c797b6c6SAneesh Kumar K.V 258c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 259c797b6c6SAneesh Kumar K.V if (ret < 0) 260c797b6c6SAneesh Kumar K.V goto err_out; 261c797b6c6SAneesh Kumar K.V 262c797b6c6SAneesh Kumar K.V ret = lchown(full_path, dfid->uid, gid); 263c797b6c6SAneesh Kumar K.V if (ret < 0) 264c797b6c6SAneesh Kumar K.V goto err_out; 265c797b6c6SAneesh Kumar K.V 266c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 267c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 268c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 269c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 270c797b6c6SAneesh Kumar K.V free(name); 271c797b6c6SAneesh Kumar K.V return; 272c797b6c6SAneesh Kumar K.V err_out: 273c797b6c6SAneesh Kumar K.V free(name); 274c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 275ead43b01SAneesh Kumar K.V return; 2761c7850f9SSasha Levin } 2771c7850f9SSasha Levin 278ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev, 279af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2801c7850f9SSasha Levin { 281af045e53SAneesh Kumar K.V u8 i; 282bfc15268SAneesh Kumar K.V u16 nwqid; 283bfc15268SAneesh Kumar K.V char *str; 284bfc15268SAneesh Kumar K.V u16 nwname; 285bfc15268SAneesh Kumar K.V struct p9_qid wqid; 286bfc15268SAneesh Kumar K.V struct p9_fid *new_fid; 287c797b6c6SAneesh Kumar K.V u32 fid_val, newfid_val; 288c797b6c6SAneesh Kumar K.V 2891c7850f9SSasha Levin 290bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname); 291bfc15268SAneesh Kumar K.V new_fid = &p9dev->fids[newfid_val]; 2921c7850f9SSasha Levin 293bfc15268SAneesh Kumar K.V nwqid = 0; 294bfc15268SAneesh Kumar K.V if (nwname) { 295bfc15268SAneesh Kumar K.V struct p9_fid *fid = &p9dev->fids[fid_val]; 296bfc15268SAneesh Kumar K.V 297*baac79a5SAneesh Kumar K.V strcpy(new_fid->path, fid->path); 298bfc15268SAneesh Kumar K.V /* skip the space for count */ 299bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 300bfc15268SAneesh Kumar K.V for (i = 0; i < nwname; i++) { 301bfc15268SAneesh Kumar K.V struct stat st; 3021c7850f9SSasha Levin char tmp[PATH_MAX] = {0}; 3031c7850f9SSasha Levin char full_path[PATH_MAX]; 304bfc15268SAneesh Kumar K.V 305bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "s", &str); 3061c7850f9SSasha Levin 3071c7850f9SSasha Levin /* Format the new path we're 'walk'ing into */ 308*baac79a5SAneesh Kumar K.V sprintf(tmp, "%s/%s", new_fid->path, str); 309c797b6c6SAneesh Kumar K.V if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0) 3106c8ca053SAneesh Kumar K.V goto err_out; 3111c7850f9SSasha Levin 312c797b6c6SAneesh Kumar K.V stat2qid(&st, &wqid); 3131c7850f9SSasha Levin new_fid->is_dir = S_ISDIR(st.st_mode); 3141c7850f9SSasha Levin strcpy(new_fid->path, tmp); 315bfc15268SAneesh Kumar K.V new_fid->fid = newfid_val; 316c797b6c6SAneesh Kumar K.V new_fid->uid = fid->uid; 317bfc15268SAneesh Kumar K.V nwqid++; 318bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &wqid); 3191c7850f9SSasha Levin } 3201c7850f9SSasha Levin } else { 321bfc15268SAneesh Kumar K.V /* 322bfc15268SAneesh Kumar K.V * update write_offset so our outlen get correct value 323bfc15268SAneesh Kumar K.V */ 324bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 325bfc15268SAneesh Kumar K.V new_fid->is_dir = p9dev->fids[fid_val].is_dir; 326bfc15268SAneesh Kumar K.V strcpy(new_fid->path, p9dev->fids[fid_val].path); 327bfc15268SAneesh Kumar K.V new_fid->fid = newfid_val; 328c797b6c6SAneesh Kumar K.V new_fid->uid = p9dev->fids[fid_val].uid; 3291c7850f9SSasha Levin } 330bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 331bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 332bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", nwqid); 333bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 3346c8ca053SAneesh Kumar K.V return; 3356c8ca053SAneesh Kumar K.V err_out: 3366c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 337ead43b01SAneesh Kumar K.V return; 3381c7850f9SSasha Levin } 3391c7850f9SSasha Levin 340ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev, 341af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 3421c7850f9SSasha Levin { 343c797b6c6SAneesh Kumar K.V int i; 344bfc15268SAneesh Kumar K.V char *uname; 345bfc15268SAneesh Kumar K.V char *aname; 3461c7850f9SSasha Levin struct stat st; 347bfc15268SAneesh Kumar K.V struct p9_qid qid; 3481c7850f9SSasha Levin struct p9_fid *fid; 349c797b6c6SAneesh Kumar K.V u32 fid_val, afid, uid; 350bfc15268SAneesh Kumar K.V 351c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddssd", &fid_val, &afid, 352c797b6c6SAneesh Kumar K.V &uname, &aname, &uid); 3531c7850f9SSasha Levin 3541c7850f9SSasha Levin /* Reset everything */ 3551c7850f9SSasha Levin for (i = 0; i < VIRTIO_P9_MAX_FID; i++) 356b4422bf3SAneesh Kumar K.V p9dev->fids[i].fid = P9_NOFID; 3571c7850f9SSasha Levin 35830204a77SAneesh Kumar K.V if (lstat(p9dev->root_dir, &st) < 0) 3596c8ca053SAneesh Kumar K.V goto err_out; 3601c7850f9SSasha Levin 361c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 3621c7850f9SSasha Levin 363bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 364bfc15268SAneesh Kumar K.V fid->fid = fid_val; 365c797b6c6SAneesh Kumar K.V fid->uid = uid; 3661c7850f9SSasha Levin fid->is_dir = 1; 3671c7850f9SSasha Levin strcpy(fid->path, "/"); 3681c7850f9SSasha Levin 369bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 370bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 371bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 3726c8ca053SAneesh Kumar K.V return; 3736c8ca053SAneesh Kumar K.V err_out: 3746c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 375ead43b01SAneesh Kumar K.V return; 3761c7850f9SSasha Levin } 3771c7850f9SSasha Levin 378c797b6c6SAneesh Kumar K.V static void virtio_p9_fill_stat(struct p9_dev *p9dev, 379c797b6c6SAneesh Kumar K.V struct stat *st, struct p9_stat_dotl *statl) 3805f900f6dSSasha Levin { 381c797b6c6SAneesh Kumar K.V memset(statl, 0, sizeof(*statl)); 382c797b6c6SAneesh Kumar K.V statl->st_mode = st->st_mode; 383c797b6c6SAneesh Kumar K.V statl->st_nlink = st->st_nlink; 384c797b6c6SAneesh Kumar K.V statl->st_uid = st->st_uid; 385c797b6c6SAneesh Kumar K.V statl->st_gid = st->st_gid; 386c797b6c6SAneesh Kumar K.V statl->st_rdev = st->st_rdev; 387c797b6c6SAneesh Kumar K.V statl->st_size = st->st_size; 388c797b6c6SAneesh Kumar K.V statl->st_blksize = st->st_blksize; 389c797b6c6SAneesh Kumar K.V statl->st_blocks = st->st_blocks; 390c797b6c6SAneesh Kumar K.V statl->st_atime_sec = st->st_atime; 391c797b6c6SAneesh Kumar K.V statl->st_atime_nsec = st->st_atim.tv_nsec; 392c797b6c6SAneesh Kumar K.V statl->st_mtime_sec = st->st_mtime; 393c797b6c6SAneesh Kumar K.V statl->st_mtime_nsec = st->st_mtim.tv_nsec; 394c797b6c6SAneesh Kumar K.V statl->st_ctime_sec = st->st_ctime; 395c797b6c6SAneesh Kumar K.V statl->st_ctime_nsec = st->st_ctim.tv_nsec; 396c797b6c6SAneesh Kumar K.V /* Currently we only support BASIC fields in stat */ 397c797b6c6SAneesh Kumar K.V statl->st_result_mask = P9_STATS_BASIC; 398c797b6c6SAneesh Kumar K.V stat2qid(st, &statl->qid); 3991c7850f9SSasha Levin } 4001c7850f9SSasha Levin 401ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev, 402af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4031c7850f9SSasha Levin { 404bfc15268SAneesh Kumar K.V u64 offset; 405bfc15268SAneesh Kumar K.V u32 fid_val; 406c797b6c6SAneesh Kumar K.V u16 iov_cnt; 407c797b6c6SAneesh Kumar K.V void *iov_base; 408c797b6c6SAneesh Kumar K.V size_t iov_len; 409bfc15268SAneesh Kumar K.V u32 count, rcount; 410bfc15268SAneesh Kumar K.V struct p9_fid *fid; 411c797b6c6SAneesh Kumar K.V 4121c7850f9SSasha Levin 413bfc15268SAneesh Kumar K.V rcount = 0; 414bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 415bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 41650c479e0SAneesh Kumar K.V 41750c479e0SAneesh Kumar K.V iov_base = pdu->in_iov[0].iov_base; 41850c479e0SAneesh Kumar K.V iov_len = pdu->in_iov[0].iov_len; 41950c479e0SAneesh Kumar K.V iov_cnt = pdu->in_iov_cnt; 420af045e53SAneesh Kumar K.V pdu->in_iov[0].iov_base += VIRTIO_P9_HDR_LEN + sizeof(u32); 421af045e53SAneesh Kumar K.V pdu->in_iov[0].iov_len -= VIRTIO_P9_HDR_LEN + sizeof(u32); 4226b163a87SAneesh Kumar K.V pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov, 423bfc15268SAneesh Kumar K.V count, 4246b163a87SAneesh Kumar K.V pdu->in_iov_cnt); 425bfc15268SAneesh Kumar K.V rcount = preadv(fid->fd, pdu->in_iov, 426bfc15268SAneesh Kumar K.V pdu->in_iov_cnt, offset); 427bfc15268SAneesh Kumar K.V if (rcount > count) 428bfc15268SAneesh Kumar K.V rcount = count; 429bfc15268SAneesh Kumar K.V /* 430bfc15268SAneesh Kumar K.V * Update the iov_base back, so that rest of 431bfc15268SAneesh Kumar K.V * pdu_writef works correctly. 432bfc15268SAneesh Kumar K.V */ 43350c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_base = iov_base; 43450c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_len = iov_len; 43550c479e0SAneesh Kumar K.V pdu->in_iov_cnt = iov_cnt; 436c797b6c6SAneesh Kumar K.V 437bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 438bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 439bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 440bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 441ead43b01SAneesh Kumar K.V return; 4421c7850f9SSasha Levin } 4431c7850f9SSasha Levin 444c797b6c6SAneesh Kumar K.V static int virtio_p9_dentry_size(struct dirent *dent) 445c797b6c6SAneesh Kumar K.V { 446c797b6c6SAneesh Kumar K.V /* 447c797b6c6SAneesh Kumar K.V * Size of each dirent: 448c797b6c6SAneesh Kumar K.V * qid(13) + offset(8) + type(1) + name_len(2) + name 449c797b6c6SAneesh Kumar K.V */ 450c797b6c6SAneesh Kumar K.V return 24 + strlen(dent->d_name); 451c797b6c6SAneesh Kumar K.V } 452c797b6c6SAneesh Kumar K.V 453c797b6c6SAneesh Kumar K.V static void virtio_p9_readdir(struct p9_dev *p9dev, 454c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 455c797b6c6SAneesh Kumar K.V { 456c797b6c6SAneesh Kumar K.V u32 fid_val; 457c797b6c6SAneesh Kumar K.V u32 count, rcount; 458c797b6c6SAneesh Kumar K.V struct stat st; 459c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 460c797b6c6SAneesh Kumar K.V struct dirent *dent; 461c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 462c797b6c6SAneesh Kumar K.V u64 offset, old_offset; 463c797b6c6SAneesh Kumar K.V 464c797b6c6SAneesh Kumar K.V rcount = 0; 465c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 466c797b6c6SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 467c797b6c6SAneesh Kumar K.V 468c797b6c6SAneesh Kumar K.V if (!fid->is_dir) { 469c797b6c6SAneesh Kumar K.V errno = -EINVAL; 470c797b6c6SAneesh Kumar K.V goto err_out; 471c797b6c6SAneesh Kumar K.V } 472c797b6c6SAneesh Kumar K.V 473c797b6c6SAneesh Kumar K.V /* Move the offset specified */ 474c797b6c6SAneesh Kumar K.V seekdir(fid->dir, offset); 475c797b6c6SAneesh Kumar K.V 476c797b6c6SAneesh Kumar K.V old_offset = offset; 477c797b6c6SAneesh Kumar K.V /* If reading a dir, fill the buffer with p9_stat entries */ 478c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir); 479c797b6c6SAneesh Kumar K.V 480c797b6c6SAneesh Kumar K.V /* Skip the space for writing count */ 481c797b6c6SAneesh Kumar K.V pdu->write_offset += sizeof(u32); 482c797b6c6SAneesh Kumar K.V while (dent) { 483c797b6c6SAneesh Kumar K.V u32 read; 484c797b6c6SAneesh Kumar K.V struct p9_qid qid; 485c797b6c6SAneesh Kumar K.V 486c797b6c6SAneesh Kumar K.V if ((rcount + virtio_p9_dentry_size(dent)) > count) { 487c797b6c6SAneesh Kumar K.V /* seek to the previous offset and return */ 488c797b6c6SAneesh Kumar K.V seekdir(fid->dir, old_offset); 489c797b6c6SAneesh Kumar K.V break; 490c797b6c6SAneesh Kumar K.V } 491c797b6c6SAneesh Kumar K.V old_offset = dent->d_off; 492c797b6c6SAneesh Kumar K.V lstat(rel_to_abs(p9dev, dent->d_name, full_path), &st); 493c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 494c797b6c6SAneesh Kumar K.V read = pdu->write_offset; 495c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qqbs", &qid, dent->d_off, 496c797b6c6SAneesh Kumar K.V dent->d_type, dent->d_name); 497c797b6c6SAneesh Kumar K.V rcount += pdu->write_offset - read; 498c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir); 499c797b6c6SAneesh Kumar K.V } 500c797b6c6SAneesh Kumar K.V 501c797b6c6SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 502c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 503c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 504c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 505c797b6c6SAneesh Kumar K.V return; 506c797b6c6SAneesh Kumar K.V err_out: 507c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 508c797b6c6SAneesh Kumar K.V return; 509c797b6c6SAneesh Kumar K.V } 510c797b6c6SAneesh Kumar K.V 511c797b6c6SAneesh Kumar K.V 512c797b6c6SAneesh Kumar K.V static void virtio_p9_getattr(struct p9_dev *p9dev, 513af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5141c7850f9SSasha Levin { 515bfc15268SAneesh Kumar K.V u32 fid_val; 516af045e53SAneesh Kumar K.V struct stat st; 517c797b6c6SAneesh Kumar K.V u64 request_mask; 518bfc15268SAneesh Kumar K.V struct p9_fid *fid; 519c797b6c6SAneesh Kumar K.V struct p9_stat_dotl statl; 5201c7850f9SSasha Levin 521c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dq", &fid_val, &request_mask); 522bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 52330204a77SAneesh Kumar K.V if (lstat(fid->abs_path, &st) < 0) 5246c8ca053SAneesh Kumar K.V goto err_out; 5251c7850f9SSasha Levin 526c797b6c6SAneesh Kumar K.V virtio_p9_fill_stat(p9dev, &st, &statl); 527c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "A", &statl); 528bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 529bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 530ead43b01SAneesh Kumar K.V return; 5316c8ca053SAneesh Kumar K.V err_out: 5326c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 5336c8ca053SAneesh Kumar K.V return; 5341c7850f9SSasha Levin } 5351c7850f9SSasha Levin 536c797b6c6SAneesh Kumar K.V /* FIXME!! from linux/fs.h */ 537c797b6c6SAneesh Kumar K.V /* 538c797b6c6SAneesh Kumar K.V * Attribute flags. These should be or-ed together to figure out what 539c797b6c6SAneesh Kumar K.V * has been changed! 540c797b6c6SAneesh Kumar K.V */ 541c797b6c6SAneesh Kumar K.V #define ATTR_MODE (1 << 0) 542c797b6c6SAneesh Kumar K.V #define ATTR_UID (1 << 1) 543c797b6c6SAneesh Kumar K.V #define ATTR_GID (1 << 2) 544c797b6c6SAneesh Kumar K.V #define ATTR_SIZE (1 << 3) 545c797b6c6SAneesh Kumar K.V #define ATTR_ATIME (1 << 4) 546c797b6c6SAneesh Kumar K.V #define ATTR_MTIME (1 << 5) 547c797b6c6SAneesh Kumar K.V #define ATTR_CTIME (1 << 6) 548c797b6c6SAneesh Kumar K.V #define ATTR_ATIME_SET (1 << 7) 549c797b6c6SAneesh Kumar K.V #define ATTR_MTIME_SET (1 << 8) 550c797b6c6SAneesh Kumar K.V #define ATTR_FORCE (1 << 9) /* Not a change, but a change it */ 551c797b6c6SAneesh Kumar K.V #define ATTR_ATTR_FLAG (1 << 10) 552c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SUID (1 << 11) 553c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SGID (1 << 12) 554c797b6c6SAneesh Kumar K.V #define ATTR_FILE (1 << 13) 555c797b6c6SAneesh Kumar K.V #define ATTR_KILL_PRIV (1 << 14) 556c797b6c6SAneesh Kumar K.V #define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ 557c797b6c6SAneesh Kumar K.V #define ATTR_TIMES_SET (1 << 16) 558c797b6c6SAneesh Kumar K.V 559c797b6c6SAneesh Kumar K.V #define ATTR_MASK 127 560c797b6c6SAneesh Kumar K.V 561c797b6c6SAneesh Kumar K.V static void virtio_p9_setattr(struct p9_dev *p9dev, 562af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5631c7850f9SSasha Levin { 564c797b6c6SAneesh Kumar K.V int ret = 0; 565bfc15268SAneesh Kumar K.V u32 fid_val; 566bfc15268SAneesh Kumar K.V struct p9_fid *fid; 567c797b6c6SAneesh Kumar K.V struct p9_iattr_dotl p9attr; 5681c7850f9SSasha Levin 569c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dI", &fid_val, &p9attr); 570bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 5711c7850f9SSasha Levin 572c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MODE) { 573c797b6c6SAneesh Kumar K.V ret = chmod(fid->abs_path, p9attr.mode); 574c797b6c6SAneesh Kumar K.V if (ret < 0) 575c797b6c6SAneesh Kumar K.V goto err_out; 576c797b6c6SAneesh Kumar K.V } 577c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_ATIME | ATTR_MTIME)) { 578c797b6c6SAneesh Kumar K.V struct timespec times[2]; 579c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME) { 580c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME_SET) { 581c797b6c6SAneesh Kumar K.V times[0].tv_sec = p9attr.atime_sec; 582c797b6c6SAneesh Kumar K.V times[0].tv_nsec = p9attr.atime_nsec; 583c797b6c6SAneesh Kumar K.V } else { 584c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_NOW; 585c797b6c6SAneesh Kumar K.V } 586c797b6c6SAneesh Kumar K.V } else { 587c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_OMIT; 588c797b6c6SAneesh Kumar K.V } 589c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME) { 590c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME_SET) { 591c797b6c6SAneesh Kumar K.V times[1].tv_sec = p9attr.mtime_sec; 592c797b6c6SAneesh Kumar K.V times[1].tv_nsec = p9attr.mtime_nsec; 593c797b6c6SAneesh Kumar K.V } else { 594c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_NOW; 595c797b6c6SAneesh Kumar K.V } 596c797b6c6SAneesh Kumar K.V } else 597c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_OMIT; 598c797b6c6SAneesh Kumar K.V 599c797b6c6SAneesh Kumar K.V ret = utimensat(-1, fid->abs_path, times, AT_SYMLINK_NOFOLLOW); 600c797b6c6SAneesh Kumar K.V if (ret < 0) 601c797b6c6SAneesh Kumar K.V goto err_out; 602c797b6c6SAneesh Kumar K.V } 603c797b6c6SAneesh Kumar K.V /* 604c797b6c6SAneesh Kumar K.V * If the only valid entry in iattr is ctime we can call 605c797b6c6SAneesh Kumar K.V * chown(-1,-1) to update the ctime of the file 606c797b6c6SAneesh Kumar K.V */ 607c797b6c6SAneesh Kumar K.V if ((p9attr.valid & (ATTR_UID | ATTR_GID)) || 608c797b6c6SAneesh Kumar K.V ((p9attr.valid & ATTR_CTIME) 609c797b6c6SAneesh Kumar K.V && !((p9attr.valid & ATTR_MASK) & ~ATTR_CTIME))) { 610c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_UID)) 611c797b6c6SAneesh Kumar K.V p9attr.uid = -1; 612c797b6c6SAneesh Kumar K.V 613c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_GID)) 614c797b6c6SAneesh Kumar K.V p9attr.gid = -1; 615c797b6c6SAneesh Kumar K.V 616c797b6c6SAneesh Kumar K.V ret = lchown(fid->abs_path, p9attr.uid, p9attr.gid); 617c797b6c6SAneesh Kumar K.V if (ret < 0) 618c797b6c6SAneesh Kumar K.V goto err_out; 619c797b6c6SAneesh Kumar K.V } 620c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_SIZE)) { 621c797b6c6SAneesh Kumar K.V ret = truncate(fid->abs_path, p9attr.size); 622c797b6c6SAneesh Kumar K.V if (ret < 0) 623c797b6c6SAneesh Kumar K.V goto err_out; 624c797b6c6SAneesh Kumar K.V } 6251c7850f9SSasha Levin *outlen = VIRTIO_P9_HDR_LEN; 626bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 627ead43b01SAneesh Kumar K.V return; 6284bc9734aSAneesh Kumar K.V err_out: 6294bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 6304bc9734aSAneesh Kumar K.V return; 6311c7850f9SSasha Levin } 6321c7850f9SSasha Levin 633ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev, 634af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 6351c7850f9SSasha Levin { 6364bc9734aSAneesh Kumar K.V 637bfc15268SAneesh Kumar K.V u64 offset; 638bfc15268SAneesh Kumar K.V u32 fid_val; 6394bc9734aSAneesh Kumar K.V u32 count; 6404bc9734aSAneesh Kumar K.V ssize_t res; 64150c479e0SAneesh Kumar K.V u16 iov_cnt; 64250c479e0SAneesh Kumar K.V void *iov_base; 64350c479e0SAneesh Kumar K.V size_t iov_len; 644bfc15268SAneesh Kumar K.V struct p9_fid *fid; 645b064b05aSAneesh Kumar K.V /* u32 fid + u64 offset + u32 count */ 646b064b05aSAneesh Kumar K.V int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32); 6471c7850f9SSasha Levin 648bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 649bfc15268SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 650af045e53SAneesh Kumar K.V 65150c479e0SAneesh Kumar K.V iov_base = pdu->out_iov[0].iov_base; 65250c479e0SAneesh Kumar K.V iov_len = pdu->out_iov[0].iov_len; 65350c479e0SAneesh Kumar K.V iov_cnt = pdu->out_iov_cnt; 65450c479e0SAneesh Kumar K.V 655bfc15268SAneesh Kumar K.V /* Adjust the iovec to skip the header and meta data */ 656b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size); 657b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_len -= (sizeof(struct p9_msg) + twrite_size); 658bfc15268SAneesh Kumar K.V pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count, 6596b163a87SAneesh Kumar K.V pdu->out_iov_cnt); 6604bc9734aSAneesh Kumar K.V res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset); 66150c479e0SAneesh Kumar K.V /* 66250c479e0SAneesh Kumar K.V * Update the iov_base back, so that rest of 66350c479e0SAneesh Kumar K.V * pdu_readf works correctly. 66450c479e0SAneesh Kumar K.V */ 66550c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_base = iov_base; 66650c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_len = iov_len; 66750c479e0SAneesh Kumar K.V pdu->out_iov_cnt = iov_cnt; 668c797b6c6SAneesh Kumar K.V 6694bc9734aSAneesh Kumar K.V if (res < 0) 6704bc9734aSAneesh Kumar K.V goto err_out; 6714bc9734aSAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", res); 672bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 673bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 674ead43b01SAneesh Kumar K.V return; 6754bc9734aSAneesh Kumar K.V err_out: 6764bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 6774bc9734aSAneesh Kumar K.V return; 6781c7850f9SSasha Levin } 6791c7850f9SSasha Levin 680c797b6c6SAneesh Kumar K.V static void virtio_p9_readlink(struct p9_dev *p9dev, 681c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 682c797b6c6SAneesh Kumar K.V { 683c797b6c6SAneesh Kumar K.V int ret; 684c797b6c6SAneesh Kumar K.V u32 fid_val; 685c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 686c797b6c6SAneesh Kumar K.V char target_path[PATH_MAX]; 687c797b6c6SAneesh Kumar K.V 688c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 689c797b6c6SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 690c797b6c6SAneesh Kumar K.V 691c797b6c6SAneesh Kumar K.V memset(target_path, 0, PATH_MAX); 692c797b6c6SAneesh Kumar K.V ret = readlink(fid->abs_path, target_path, PATH_MAX - 1); 693c797b6c6SAneesh Kumar K.V if (ret < 0) 694c797b6c6SAneesh Kumar K.V goto err_out; 695c797b6c6SAneesh Kumar K.V 696c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "s", target_path); 697c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 698c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 699c797b6c6SAneesh Kumar K.V return; 700c797b6c6SAneesh Kumar K.V err_out: 701c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 702c797b6c6SAneesh Kumar K.V return; 703c797b6c6SAneesh Kumar K.V } 704c797b6c6SAneesh Kumar K.V 705c797b6c6SAneesh Kumar K.V static void virtio_p9_statfs(struct p9_dev *p9dev, 706c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 707c797b6c6SAneesh Kumar K.V { 708c797b6c6SAneesh Kumar K.V int ret; 709c797b6c6SAneesh Kumar K.V u64 fsid; 710c797b6c6SAneesh Kumar K.V u32 fid_val; 711c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 712c797b6c6SAneesh Kumar K.V struct statfs stat_buf; 713c797b6c6SAneesh Kumar K.V 714c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 715c797b6c6SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 716c797b6c6SAneesh Kumar K.V 717c797b6c6SAneesh Kumar K.V ret = statfs(fid->abs_path, &stat_buf); 718c797b6c6SAneesh Kumar K.V if (ret < 0) 719c797b6c6SAneesh Kumar K.V goto err_out; 720c797b6c6SAneesh Kumar K.V /* FIXME!! f_blocks needs update based on client msize */ 721c797b6c6SAneesh Kumar K.V fsid = (unsigned int) stat_buf.f_fsid.__val[0] | 722c797b6c6SAneesh Kumar K.V (unsigned long long)stat_buf.f_fsid.__val[1] << 32; 723c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ddqqqqqqd", stat_buf.f_type, 724c797b6c6SAneesh Kumar K.V stat_buf.f_bsize, stat_buf.f_blocks, 725c797b6c6SAneesh Kumar K.V stat_buf.f_bfree, stat_buf.f_bavail, 726c797b6c6SAneesh Kumar K.V stat_buf.f_files, stat_buf.f_ffree, 727c797b6c6SAneesh Kumar K.V fsid, stat_buf.f_namelen); 728c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 729c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 730c797b6c6SAneesh Kumar K.V return; 731c797b6c6SAneesh Kumar K.V err_out: 732c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 733c797b6c6SAneesh Kumar K.V return; 734c797b6c6SAneesh Kumar K.V } 735c797b6c6SAneesh Kumar K.V 736c797b6c6SAneesh Kumar K.V static void virtio_p9_mknod(struct p9_dev *p9dev, 737c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 738c797b6c6SAneesh Kumar K.V { 739c797b6c6SAneesh Kumar K.V int ret; 740c797b6c6SAneesh Kumar K.V char *name; 741c797b6c6SAneesh Kumar K.V struct stat st; 742c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 743c797b6c6SAneesh Kumar K.V struct p9_qid qid; 744c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 745c797b6c6SAneesh Kumar K.V u32 fid_val, mode, major, minor, gid; 746c797b6c6SAneesh Kumar K.V 747c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdddd", &fid_val, &name, &mode, 748c797b6c6SAneesh Kumar K.V &major, &minor, &gid); 749c797b6c6SAneesh Kumar K.V 750c797b6c6SAneesh Kumar K.V dfid = &p9dev->fids[fid_val]; 751c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 752c797b6c6SAneesh Kumar K.V ret = mknod(full_path, mode, makedev(major, minor)); 753c797b6c6SAneesh Kumar K.V if (ret < 0) 754c797b6c6SAneesh Kumar K.V goto err_out; 755c797b6c6SAneesh Kumar K.V 756c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0) 757c797b6c6SAneesh Kumar K.V goto err_out; 758c797b6c6SAneesh Kumar K.V 759c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 760c797b6c6SAneesh Kumar K.V if (ret < 0) 761c797b6c6SAneesh Kumar K.V goto err_out; 762c797b6c6SAneesh Kumar K.V 763c797b6c6SAneesh Kumar K.V ret = lchown(full_path, dfid->uid, gid); 764c797b6c6SAneesh Kumar K.V if (ret < 0) 765c797b6c6SAneesh Kumar K.V goto err_out; 766c797b6c6SAneesh Kumar K.V 767c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 768c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 769c797b6c6SAneesh Kumar K.V free(name); 770c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 771c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 772c797b6c6SAneesh Kumar K.V return; 773c797b6c6SAneesh Kumar K.V err_out: 774c797b6c6SAneesh Kumar K.V free(name); 775c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 776c797b6c6SAneesh Kumar K.V return; 777c797b6c6SAneesh Kumar K.V } 778c797b6c6SAneesh Kumar K.V 779c797b6c6SAneesh Kumar K.V static void virtio_p9_fsync(struct p9_dev *p9dev, 780c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 781c797b6c6SAneesh Kumar K.V { 782c797b6c6SAneesh Kumar K.V int ret; 783c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 784c797b6c6SAneesh Kumar K.V u32 fid_val, datasync; 785c797b6c6SAneesh Kumar K.V 786c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid_val, &datasync); 787c797b6c6SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 788c797b6c6SAneesh Kumar K.V 789c797b6c6SAneesh Kumar K.V if (datasync) 790c797b6c6SAneesh Kumar K.V ret = fdatasync(fid->fd); 791c797b6c6SAneesh Kumar K.V else 792c797b6c6SAneesh Kumar K.V ret = fsync(fid->fd); 793c797b6c6SAneesh Kumar K.V if (ret < 0) 794c797b6c6SAneesh Kumar K.V goto err_out; 795c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 796c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 797c797b6c6SAneesh Kumar K.V return; 798c797b6c6SAneesh Kumar K.V err_out: 799c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 800c797b6c6SAneesh Kumar K.V return; 801c797b6c6SAneesh Kumar K.V } 802c797b6c6SAneesh Kumar K.V 803c797b6c6SAneesh Kumar K.V static void virtio_p9_symlink(struct p9_dev *p9dev, 804c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 805c797b6c6SAneesh Kumar K.V { 806c797b6c6SAneesh Kumar K.V int ret; 807c797b6c6SAneesh Kumar K.V struct stat st; 808c797b6c6SAneesh Kumar K.V u32 fid_val, gid; 809c797b6c6SAneesh Kumar K.V struct p9_qid qid; 810c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 811c797b6c6SAneesh Kumar K.V char new_name[PATH_MAX]; 812c797b6c6SAneesh Kumar K.V char *old_path, *name; 813c797b6c6SAneesh Kumar K.V 814c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dssd", &fid_val, &name, &old_path, &gid); 815c797b6c6SAneesh Kumar K.V 816c797b6c6SAneesh Kumar K.V dfid = &p9dev->fids[fid_val]; 817c797b6c6SAneesh Kumar K.V sprintf(new_name, "%s/%s", dfid->abs_path, name); 818c797b6c6SAneesh Kumar K.V ret = symlink(old_path, new_name); 819c797b6c6SAneesh Kumar K.V if (ret < 0) 820c797b6c6SAneesh Kumar K.V goto err_out; 821c797b6c6SAneesh Kumar K.V 822c797b6c6SAneesh Kumar K.V if (lstat(new_name, &st) < 0) 823c797b6c6SAneesh Kumar K.V goto err_out; 824c797b6c6SAneesh Kumar K.V 825c797b6c6SAneesh Kumar K.V ret = lchown(new_name, dfid->uid, gid); 826c797b6c6SAneesh Kumar K.V if (ret < 0) 827c797b6c6SAneesh Kumar K.V goto err_out; 828c797b6c6SAneesh Kumar K.V 829c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 830c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 831c797b6c6SAneesh Kumar K.V free(name); 832c797b6c6SAneesh Kumar K.V free(old_path); 833c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 834c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 835c797b6c6SAneesh Kumar K.V return; 836c797b6c6SAneesh Kumar K.V err_out: 837c797b6c6SAneesh Kumar K.V free(name); 838c797b6c6SAneesh Kumar K.V free(old_path); 839c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 840c797b6c6SAneesh Kumar K.V return; 841c797b6c6SAneesh Kumar K.V } 842c797b6c6SAneesh Kumar K.V 843c797b6c6SAneesh Kumar K.V static void virtio_p9_link(struct p9_dev *p9dev, 844c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 845c797b6c6SAneesh Kumar K.V { 846c797b6c6SAneesh Kumar K.V int ret; 847c797b6c6SAneesh Kumar K.V char *name; 848c797b6c6SAneesh Kumar K.V u32 fid_val, dfid_val; 849c797b6c6SAneesh Kumar K.V struct p9_fid *dfid, *fid; 850c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 851c797b6c6SAneesh Kumar K.V 852c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dds", &dfid_val, &fid_val, &name); 853c797b6c6SAneesh Kumar K.V 854c797b6c6SAneesh Kumar K.V dfid = &p9dev->fids[dfid_val]; 855c797b6c6SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 856c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 857c797b6c6SAneesh Kumar K.V ret = link(fid->abs_path, full_path); 858c797b6c6SAneesh Kumar K.V if (ret < 0) 859c797b6c6SAneesh Kumar K.V goto err_out; 860c797b6c6SAneesh Kumar K.V free(name); 861c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 862c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 863c797b6c6SAneesh Kumar K.V return; 864c797b6c6SAneesh Kumar K.V err_out: 865c797b6c6SAneesh Kumar K.V free(name); 866c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 867c797b6c6SAneesh Kumar K.V return; 868c797b6c6SAneesh Kumar K.V 869c797b6c6SAneesh Kumar K.V } 870c797b6c6SAneesh Kumar K.V 871c797b6c6SAneesh Kumar K.V static void virtio_p9_lock(struct p9_dev *p9dev, 872c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 873c797b6c6SAneesh Kumar K.V { 874c797b6c6SAneesh Kumar K.V u8 ret; 875c797b6c6SAneesh Kumar K.V u32 fid_val; 876c797b6c6SAneesh Kumar K.V struct p9_flock flock; 877c797b6c6SAneesh Kumar K.V 878c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbdqqds", &fid_val, &flock.type, 879c797b6c6SAneesh Kumar K.V &flock.flags, &flock.start, &flock.length, 880c797b6c6SAneesh Kumar K.V &flock.proc_id, &flock.client_id); 881c797b6c6SAneesh Kumar K.V 882c797b6c6SAneesh Kumar K.V /* Just return success */ 883c797b6c6SAneesh Kumar K.V ret = P9_LOCK_SUCCESS; 884c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", ret); 885c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 886c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 887c797b6c6SAneesh Kumar K.V free(flock.client_id); 888c797b6c6SAneesh Kumar K.V return; 889c797b6c6SAneesh Kumar K.V } 890c797b6c6SAneesh Kumar K.V 891c797b6c6SAneesh Kumar K.V static void virtio_p9_getlock(struct p9_dev *p9dev, 892c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 893c797b6c6SAneesh Kumar K.V { 894c797b6c6SAneesh Kumar K.V u32 fid_val; 895c797b6c6SAneesh Kumar K.V struct p9_getlock glock; 896c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbqqds", &fid_val, &glock.type, 897c797b6c6SAneesh Kumar K.V &glock.start, &glock.length, &glock.proc_id, 898c797b6c6SAneesh Kumar K.V &glock.client_id); 899c797b6c6SAneesh Kumar K.V 900c797b6c6SAneesh Kumar K.V /* Just return success */ 901c797b6c6SAneesh Kumar K.V glock.type = F_UNLCK; 902c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "bqqds", glock.type, 903c797b6c6SAneesh Kumar K.V glock.start, glock.length, glock.proc_id, 904c797b6c6SAneesh Kumar K.V glock.client_id); 905c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 906c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 907c797b6c6SAneesh Kumar K.V free(glock.client_id); 908c797b6c6SAneesh Kumar K.V return; 909c797b6c6SAneesh Kumar K.V } 910c797b6c6SAneesh Kumar K.V 911c797b6c6SAneesh Kumar K.V static int virtio_p9_ancestor(char *path, char *ancestor) 912c797b6c6SAneesh Kumar K.V { 913c797b6c6SAneesh Kumar K.V int size = strlen(ancestor); 914c797b6c6SAneesh Kumar K.V if (!strncmp(path, ancestor, size)) { 915c797b6c6SAneesh Kumar K.V /* 916c797b6c6SAneesh Kumar K.V * Now check whether ancestor is a full name or 917c797b6c6SAneesh Kumar K.V * or directory component and not just part 918c797b6c6SAneesh Kumar K.V * of a name. 919c797b6c6SAneesh Kumar K.V */ 920c797b6c6SAneesh Kumar K.V if (path[size] == '\0' || path[size] == '/') 921c797b6c6SAneesh Kumar K.V return 1; 922c797b6c6SAneesh Kumar K.V } 923c797b6c6SAneesh Kumar K.V return 0; 924c797b6c6SAneesh Kumar K.V } 925c797b6c6SAneesh Kumar K.V 926c797b6c6SAneesh Kumar K.V static void virtio_p9_fix_path(char *fid_path, char *old_name, char *new_name) 927c797b6c6SAneesh Kumar K.V { 928c797b6c6SAneesh Kumar K.V char tmp_name[PATH_MAX]; 929c797b6c6SAneesh Kumar K.V size_t rp_sz = strlen(old_name); 930c797b6c6SAneesh Kumar K.V 931c797b6c6SAneesh Kumar K.V if (rp_sz == strlen(fid_path)) { 932c797b6c6SAneesh Kumar K.V /* replace the full name */ 933c797b6c6SAneesh Kumar K.V strcpy(fid_path, new_name); 934c797b6c6SAneesh Kumar K.V return; 935c797b6c6SAneesh Kumar K.V } 936c797b6c6SAneesh Kumar K.V /* save the trailing path details */ 937c797b6c6SAneesh Kumar K.V strcpy(tmp_name, fid_path + rp_sz); 938c797b6c6SAneesh Kumar K.V sprintf(fid_path, "%s%s", new_name, tmp_name); 939c797b6c6SAneesh Kumar K.V return; 940c797b6c6SAneesh Kumar K.V } 941c797b6c6SAneesh Kumar K.V 942c797b6c6SAneesh Kumar K.V static void virtio_p9_renameat(struct p9_dev *p9dev, 943c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 944c797b6c6SAneesh Kumar K.V { 945c797b6c6SAneesh Kumar K.V int i, ret; 946c797b6c6SAneesh Kumar K.V char *old_name, *new_name; 947c797b6c6SAneesh Kumar K.V u32 old_dfid_val, new_dfid_val; 948c797b6c6SAneesh Kumar K.V struct p9_fid *old_dfid, *new_dfid; 949c797b6c6SAneesh Kumar K.V char old_full_path[PATH_MAX], new_full_path[PATH_MAX]; 950c797b6c6SAneesh Kumar K.V 951c797b6c6SAneesh Kumar K.V 952c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsds", &old_dfid_val, &old_name, 953c797b6c6SAneesh Kumar K.V &new_dfid_val, &new_name); 954c797b6c6SAneesh Kumar K.V 955c797b6c6SAneesh Kumar K.V old_dfid = &p9dev->fids[old_dfid_val]; 956c797b6c6SAneesh Kumar K.V new_dfid = &p9dev->fids[new_dfid_val]; 957c797b6c6SAneesh Kumar K.V 958c797b6c6SAneesh Kumar K.V sprintf(old_full_path, "%s/%s", old_dfid->abs_path, old_name); 959c797b6c6SAneesh Kumar K.V sprintf(new_full_path, "%s/%s", new_dfid->abs_path, new_name); 960c797b6c6SAneesh Kumar K.V ret = rename(old_full_path, new_full_path); 961c797b6c6SAneesh Kumar K.V if (ret < 0) 962c797b6c6SAneesh Kumar K.V goto err_out; 963c797b6c6SAneesh Kumar K.V /* 964c797b6c6SAneesh Kumar K.V * Now fix path in other fids, if the renamed path is part of 965c797b6c6SAneesh Kumar K.V * that. 966c797b6c6SAneesh Kumar K.V */ 967c797b6c6SAneesh Kumar K.V for (i = 0; i < VIRTIO_P9_MAX_FID; i++) { 968c797b6c6SAneesh Kumar K.V if (p9dev->fids[i].fid != P9_NOFID && 969c797b6c6SAneesh Kumar K.V virtio_p9_ancestor(p9dev->fids[i].path, old_name)) { 970c797b6c6SAneesh Kumar K.V virtio_p9_fix_path(p9dev->fids[i].path, old_name, 971c797b6c6SAneesh Kumar K.V new_name); 972c797b6c6SAneesh Kumar K.V } 973c797b6c6SAneesh Kumar K.V } 974c797b6c6SAneesh Kumar K.V free(old_name); 975c797b6c6SAneesh Kumar K.V free(new_name); 976c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 977c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 978c797b6c6SAneesh Kumar K.V return; 979c797b6c6SAneesh Kumar K.V err_out: 980c797b6c6SAneesh Kumar K.V free(old_name); 981c797b6c6SAneesh Kumar K.V free(new_name); 982c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 983c797b6c6SAneesh Kumar K.V return; 984c797b6c6SAneesh Kumar K.V } 985c797b6c6SAneesh Kumar K.V 986c797b6c6SAneesh Kumar K.V static void virtio_p9_unlinkat(struct p9_dev *p9dev, 987c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 988c797b6c6SAneesh Kumar K.V { 989c797b6c6SAneesh Kumar K.V int ret; 990c797b6c6SAneesh Kumar K.V char *name; 991c797b6c6SAneesh Kumar K.V u32 fid_val, flags; 992c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 993c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 994c797b6c6SAneesh Kumar K.V 995c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsd", &fid_val, &name, &flags); 996c797b6c6SAneesh Kumar K.V fid = &p9dev->fids[fid_val]; 997c797b6c6SAneesh Kumar K.V 998c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", fid->abs_path, name); 999c797b6c6SAneesh Kumar K.V ret = remove(full_path); 1000c797b6c6SAneesh Kumar K.V if (ret < 0) 1001c797b6c6SAneesh Kumar K.V goto err_out; 1002c797b6c6SAneesh Kumar K.V free(name); 1003c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1004c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1005c797b6c6SAneesh Kumar K.V return; 1006c797b6c6SAneesh Kumar K.V err_out: 1007c797b6c6SAneesh Kumar K.V free(name); 1008c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1009c797b6c6SAneesh Kumar K.V return; 1010c797b6c6SAneesh Kumar K.V } 1011c797b6c6SAneesh Kumar K.V 1012c797b6c6SAneesh Kumar K.V static void virtio_p9_eopnotsupp(struct p9_dev *p9dev, 1013c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1014c797b6c6SAneesh Kumar K.V { 1015c797b6c6SAneesh Kumar K.V return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen); 1016c797b6c6SAneesh Kumar K.V } 1017c797b6c6SAneesh Kumar K.V 1018ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev, 1019af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen); 1020b4422bf3SAneesh Kumar K.V 1021c797b6c6SAneesh Kumar K.V /* FIXME should be removed when merging with latest linus tree */ 1022c797b6c6SAneesh Kumar K.V #define P9_TRENAMEAT 74 1023c797b6c6SAneesh Kumar K.V #define P9_TUNLINKAT 76 1024c797b6c6SAneesh Kumar K.V 1025c797b6c6SAneesh Kumar K.V static p9_handler *virtio_9p_dotl_handler [] = { 1026c797b6c6SAneesh Kumar K.V [P9_TREADDIR] = virtio_p9_readdir, 1027c797b6c6SAneesh Kumar K.V [P9_TSTATFS] = virtio_p9_statfs, 1028c797b6c6SAneesh Kumar K.V [P9_TGETATTR] = virtio_p9_getattr, 1029c797b6c6SAneesh Kumar K.V [P9_TSETATTR] = virtio_p9_setattr, 1030c797b6c6SAneesh Kumar K.V [P9_TXATTRWALK] = virtio_p9_eopnotsupp, 1031c797b6c6SAneesh Kumar K.V [P9_TXATTRCREATE] = virtio_p9_eopnotsupp, 1032c797b6c6SAneesh Kumar K.V [P9_TMKNOD] = virtio_p9_mknod, 1033c797b6c6SAneesh Kumar K.V [P9_TLOCK] = virtio_p9_lock, 1034c797b6c6SAneesh Kumar K.V [P9_TGETLOCK] = virtio_p9_getlock, 1035c797b6c6SAneesh Kumar K.V [P9_TRENAMEAT] = virtio_p9_renameat, 1036c797b6c6SAneesh Kumar K.V [P9_TREADLINK] = virtio_p9_readlink, 1037c797b6c6SAneesh Kumar K.V [P9_TUNLINKAT] = virtio_p9_unlinkat, 1038c797b6c6SAneesh Kumar K.V [P9_TMKDIR] = virtio_p9_mkdir, 1039b4422bf3SAneesh Kumar K.V [P9_TVERSION] = virtio_p9_version, 1040c797b6c6SAneesh Kumar K.V [P9_TLOPEN] = virtio_p9_open, 1041b4422bf3SAneesh Kumar K.V [P9_TATTACH] = virtio_p9_attach, 1042b4422bf3SAneesh Kumar K.V [P9_TWALK] = virtio_p9_walk, 1043c797b6c6SAneesh Kumar K.V [P9_TCLUNK] = virtio_p9_clunk, 1044c797b6c6SAneesh Kumar K.V [P9_TFSYNC] = virtio_p9_fsync, 1045b4422bf3SAneesh Kumar K.V [P9_TREAD] = virtio_p9_read, 1046c797b6c6SAneesh Kumar K.V [P9_TFLUSH] = virtio_p9_eopnotsupp, 1047c797b6c6SAneesh Kumar K.V [P9_TLINK] = virtio_p9_link, 1048c797b6c6SAneesh Kumar K.V [P9_TSYMLINK] = virtio_p9_symlink, 1049c797b6c6SAneesh Kumar K.V [P9_TLCREATE] = virtio_p9_create, 1050b4422bf3SAneesh Kumar K.V [P9_TWRITE] = virtio_p9_write, 1051b4422bf3SAneesh Kumar K.V }; 1052b4422bf3SAneesh Kumar K.V 1053af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq) 1054af045e53SAneesh Kumar K.V { 1055af045e53SAneesh Kumar K.V struct p9_pdu *pdu = calloc(1, sizeof(*pdu)); 1056af045e53SAneesh Kumar K.V if (!pdu) 1057af045e53SAneesh Kumar K.V return NULL; 1058af045e53SAneesh Kumar K.V 1059bfc15268SAneesh Kumar K.V /* skip the pdu header p9_msg */ 1060bfc15268SAneesh Kumar K.V pdu->read_offset = VIRTIO_P9_HDR_LEN; 1061bfc15268SAneesh Kumar K.V pdu->write_offset = VIRTIO_P9_HDR_LEN; 1062af045e53SAneesh Kumar K.V pdu->queue_head = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov, 1063af045e53SAneesh Kumar K.V pdu->out_iov, 1064af045e53SAneesh Kumar K.V &pdu->in_iov_cnt, 1065af045e53SAneesh Kumar K.V &pdu->out_iov_cnt); 1066af045e53SAneesh Kumar K.V return pdu; 1067af045e53SAneesh Kumar K.V } 1068af045e53SAneesh Kumar K.V 1069af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu) 1070af045e53SAneesh Kumar K.V { 1071af045e53SAneesh Kumar K.V struct p9_msg *msg; 1072af045e53SAneesh Kumar K.V /* 1073af045e53SAneesh Kumar K.V * we can peek directly into pdu for a u8 1074af045e53SAneesh Kumar K.V * value. The host endianess won't be an issue 1075af045e53SAneesh Kumar K.V */ 1076af045e53SAneesh Kumar K.V msg = pdu->out_iov[0].iov_base; 1077af045e53SAneesh Kumar K.V return msg->cmd; 1078af045e53SAneesh Kumar K.V } 1079af045e53SAneesh Kumar K.V 1080b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job) 10811c7850f9SSasha Levin { 1082af045e53SAneesh Kumar K.V u8 cmd; 1083b4422bf3SAneesh Kumar K.V u32 len = 0; 1084b4422bf3SAneesh Kumar K.V p9_handler *handler; 1085b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 1086af045e53SAneesh Kumar K.V struct virt_queue *vq; 1087af045e53SAneesh Kumar K.V struct p9_pdu *p9pdu; 10881c7850f9SSasha Levin 1089b4422bf3SAneesh Kumar K.V vq = job->vq; 1090b4422bf3SAneesh Kumar K.V p9dev = job->p9dev; 10911c7850f9SSasha Levin 1092af045e53SAneesh Kumar K.V p9pdu = virtio_p9_pdu_init(kvm, vq); 1093af045e53SAneesh Kumar K.V cmd = virtio_p9_get_cmd(p9pdu); 1094af045e53SAneesh Kumar K.V 1095c797b6c6SAneesh Kumar K.V if ((cmd >= ARRAY_SIZE(virtio_9p_dotl_handler)) || 1096c797b6c6SAneesh Kumar K.V !virtio_9p_dotl_handler[cmd]) 109797b408afSAneesh Kumar K.V handler = virtio_p9_eopnotsupp; 1098dd78d9eaSAneesh Kumar K.V else 1099c797b6c6SAneesh Kumar K.V handler = virtio_9p_dotl_handler[cmd]; 1100c797b6c6SAneesh Kumar K.V 1101af045e53SAneesh Kumar K.V handler(p9dev, p9pdu, &len); 1102af045e53SAneesh Kumar K.V virt_queue__set_used_elem(vq, p9pdu->queue_head, len); 1103af045e53SAneesh Kumar K.V free(p9pdu); 11041c7850f9SSasha Levin return true; 11051c7850f9SSasha Levin } 11061c7850f9SSasha Levin 11071c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param) 11081c7850f9SSasha Levin { 1109b4422bf3SAneesh Kumar K.V struct p9_dev_job *job = (struct p9_dev_job *)param; 1110b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = job->p9dev; 1111b4422bf3SAneesh Kumar K.V struct virt_queue *vq = job->vq; 11121c7850f9SSasha Levin 11131c7850f9SSasha Levin while (virt_queue__available(vq)) { 1114b4422bf3SAneesh Kumar K.V virtio_p9_do_io_request(kvm, job); 1115c7838fbdSSasha Levin virtio_pci__signal_vq(kvm, &p9dev->vpci, vq - p9dev->vqs); 11161c7850f9SSasha Levin } 11171c7850f9SSasha Levin } 11181c7850f9SSasha Levin 111960eb42d5SSasha Levin static void ioevent_callback(struct kvm *kvm, void *param) 112060eb42d5SSasha Levin { 112160eb42d5SSasha Levin struct p9_dev_job *job = param; 112260eb42d5SSasha Levin 1123df0c7f57SSasha Levin thread_pool__do_job(&job->job_id); 112460eb42d5SSasha Levin } 112560eb42d5SSasha Levin 1126c7838fbdSSasha Levin static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset) 11271c7850f9SSasha Levin { 1128c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 11291c7850f9SSasha Levin 1130c7838fbdSSasha Levin ((u8 *)(p9dev->config))[offset] = data; 1131c7838fbdSSasha Levin } 11321c7850f9SSasha Levin 1133c7838fbdSSasha Levin static u8 get_config(struct kvm *kvm, void *dev, u32 offset) 1134c7838fbdSSasha Levin { 1135c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1136c7838fbdSSasha Levin 1137c7838fbdSSasha Levin return ((u8 *)(p9dev->config))[offset]; 1138c7838fbdSSasha Levin } 1139c7838fbdSSasha Levin 1140c7838fbdSSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev) 1141c7838fbdSSasha Levin { 1142c7838fbdSSasha Levin return 1 << VIRTIO_9P_MOUNT_TAG; 1143c7838fbdSSasha Levin } 1144c7838fbdSSasha Levin 1145c7838fbdSSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features) 1146c7838fbdSSasha Levin { 1147c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1148c7838fbdSSasha Levin 1149c7838fbdSSasha Levin p9dev->features = features; 1150c7838fbdSSasha Levin } 1151c7838fbdSSasha Levin 1152c7838fbdSSasha Levin static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn) 1153c7838fbdSSasha Levin { 1154c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1155b4422bf3SAneesh Kumar K.V struct p9_dev_job *job; 1156b4422bf3SAneesh Kumar K.V struct virt_queue *queue; 1157c7838fbdSSasha Levin void *p; 1158c7838fbdSSasha Levin struct ioevent ioevent; 11591c7850f9SSasha Levin 1160e59662b3SSasha Levin compat__remove_message(p9dev->compat_id); 1161e59662b3SSasha Levin 1162c7838fbdSSasha Levin queue = &p9dev->vqs[vq]; 1163c7838fbdSSasha Levin queue->pfn = pfn; 11641c7850f9SSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 1165c7838fbdSSasha Levin job = &p9dev->jobs[vq]; 11661c7850f9SSasha Levin 1167c7838fbdSSasha Levin vring_init(&queue->vring, VIRTQUEUE_NUM, p, VIRTIO_PCI_VRING_ALIGN); 11681c7850f9SSasha Levin 1169b4422bf3SAneesh Kumar K.V *job = (struct p9_dev_job) { 1170b4422bf3SAneesh Kumar K.V .vq = queue, 1171b4422bf3SAneesh Kumar K.V .p9dev = p9dev, 1172b4422bf3SAneesh Kumar K.V }; 1173df0c7f57SSasha Levin thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job); 117460eb42d5SSasha Levin 117560eb42d5SSasha Levin ioevent = (struct ioevent) { 1176c7838fbdSSasha Levin .io_addr = p9dev->vpci.base_addr + VIRTIO_PCI_QUEUE_NOTIFY, 117760eb42d5SSasha Levin .io_len = sizeof(u16), 117860eb42d5SSasha Levin .fn = ioevent_callback, 1179c7838fbdSSasha Levin .fn_ptr = &p9dev->jobs[vq], 1180c7838fbdSSasha Levin .datamatch = vq, 118160eb42d5SSasha Levin .fn_kvm = kvm, 118260eb42d5SSasha Levin .fd = eventfd(0, 0), 118360eb42d5SSasha Levin }; 118460eb42d5SSasha Levin 118560eb42d5SSasha Levin ioeventfd__add_event(&ioevent); 118660eb42d5SSasha Levin 1187c7838fbdSSasha Levin return 0; 11881c7850f9SSasha Levin } 11891c7850f9SSasha Levin 1190c7838fbdSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 1191c7838fbdSSasha Levin { 1192c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 11931c7850f9SSasha Levin 1194c7838fbdSSasha Levin thread_pool__do_job(&p9dev->jobs[vq].job_id); 1195c7838fbdSSasha Levin 1196c7838fbdSSasha Levin return 0; 1197c7838fbdSSasha Levin } 1198c7838fbdSSasha Levin 1199c7838fbdSSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq) 1200c7838fbdSSasha Levin { 1201c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1202c7838fbdSSasha Levin 1203c7838fbdSSasha Levin return p9dev->vqs[vq].pfn; 1204c7838fbdSSasha Levin } 1205c7838fbdSSasha Levin 1206c7838fbdSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 1207c7838fbdSSasha Levin { 1208c7838fbdSSasha Levin return VIRTQUEUE_NUM; 1209c7838fbdSSasha Levin } 1210c7838fbdSSasha Levin 1211c7838fbdSSasha Levin int virtio_9p__init(struct kvm *kvm) 12121c7850f9SSasha Levin { 1213b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 1214c7838fbdSSasha Levin 1215c7838fbdSSasha Levin list_for_each_entry(p9dev, &devs, list) { 1216c7838fbdSSasha Levin virtio_pci__init(kvm, &p9dev->vpci, p9dev, PCI_DEVICE_ID_VIRTIO_P9, VIRTIO_ID_9P); 1217c7838fbdSSasha Levin p9dev->vpci.ops = (struct virtio_pci_ops) { 1218c7838fbdSSasha Levin .set_config = set_config, 1219c7838fbdSSasha Levin .get_config = get_config, 1220c7838fbdSSasha Levin .get_host_features = get_host_features, 1221c7838fbdSSasha Levin .set_guest_features = set_guest_features, 1222c7838fbdSSasha Levin .init_vq = init_vq, 1223c7838fbdSSasha Levin .notify_vq = notify_vq, 1224c7838fbdSSasha Levin .get_pfn_vq = get_pfn_vq, 1225c7838fbdSSasha Levin .get_size_vq = get_size_vq, 1226c7838fbdSSasha Levin }; 1227c7838fbdSSasha Levin } 1228c7838fbdSSasha Levin 1229c7838fbdSSasha Levin return 0; 1230c7838fbdSSasha Levin } 1231c7838fbdSSasha Levin 1232c7838fbdSSasha Levin int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name) 1233c7838fbdSSasha Levin { 1234c7838fbdSSasha Levin struct p9_dev *p9dev; 123554f6802dSPekka Enberg u32 i, root_len; 123654f6802dSPekka Enberg int err = 0; 12371c7850f9SSasha Levin 1238b4422bf3SAneesh Kumar K.V p9dev = calloc(1, sizeof(*p9dev)); 1239b4422bf3SAneesh Kumar K.V if (!p9dev) 124054f6802dSPekka Enberg return -ENOMEM; 124154f6802dSPekka Enberg 1242b4422bf3SAneesh Kumar K.V if (!tag_name) 1243b4422bf3SAneesh Kumar K.V tag_name = VIRTIO_P9_DEFAULT_TAG; 124454f6802dSPekka Enberg 1245b4422bf3SAneesh Kumar K.V p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1); 124654f6802dSPekka Enberg if (p9dev->config == NULL) { 124754f6802dSPekka Enberg err = -ENOMEM; 1248b4422bf3SAneesh Kumar K.V goto free_p9dev; 124954f6802dSPekka Enberg } 12501c7850f9SSasha Levin 1251b4422bf3SAneesh Kumar K.V strcpy(p9dev->root_dir, root); 12521c7850f9SSasha Levin root_len = strlen(root); 12531c7850f9SSasha Levin /* 12541c7850f9SSasha Levin * We prefix the full path in all fids, This allows us to get the 12551c7850f9SSasha Levin * absolute path of an fid without playing with strings. 12561c7850f9SSasha Levin */ 12571c7850f9SSasha Levin for (i = 0; i < VIRTIO_P9_MAX_FID; i++) { 1258b4422bf3SAneesh Kumar K.V strcpy(p9dev->fids[i].abs_path, root); 1259b4422bf3SAneesh Kumar K.V p9dev->fids[i].path = p9dev->fids[i].abs_path + root_len; 12601c7850f9SSasha Levin } 1261b4422bf3SAneesh Kumar K.V p9dev->config->tag_len = strlen(tag_name); 126254f6802dSPekka Enberg if (p9dev->config->tag_len > MAX_TAG_LEN) { 126354f6802dSPekka Enberg err = -EINVAL; 1264b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 126554f6802dSPekka Enberg } 12661c7850f9SSasha Levin 1267c7838fbdSSasha Levin memcpy(&p9dev->config->tag, tag_name, strlen(tag_name)); 12681c7850f9SSasha Levin 1269c7838fbdSSasha Levin list_add(&p9dev->list, &devs); 1270b4422bf3SAneesh Kumar K.V 1271e59662b3SSasha Levin p9dev->compat_id = compat__add_message("virtio-9p device was not detected", 1272e59662b3SSasha Levin "While you have requested a virtio-9p device, " 1273e59662b3SSasha Levin "the guest kernel didn't seem to detect it.\n" 1274e59662b3SSasha Levin "Please make sure that the kernel was compiled" 1275e59662b3SSasha Levin "with CONFIG_NET_9P_VIRTIO."); 1276e59662b3SSasha Levin 127754f6802dSPekka Enberg return err; 127854f6802dSPekka Enberg 1279b4422bf3SAneesh Kumar K.V free_p9dev_config: 1280b4422bf3SAneesh Kumar K.V free(p9dev->config); 1281b4422bf3SAneesh Kumar K.V free_p9dev: 1282b4422bf3SAneesh Kumar K.V free(p9dev); 128354f6802dSPekka Enberg return err; 12841c7850f9SSasha Levin } 1285