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 2531a6fb8dSSasha Levin static struct p9_fid *get_fid(struct p9_dev *p9dev, int fid) 2631a6fb8dSSasha Levin { 2731a6fb8dSSasha Levin if (fid >= VIRTIO_9P_MAX_FID) 2831a6fb8dSSasha Levin die("virtio-9p max FID (%u) reached!", VIRTIO_9P_MAX_FID); 2931a6fb8dSSasha Levin 3031a6fb8dSSasha Levin return &p9dev->fids[fid]; 3131a6fb8dSSasha Levin } 3231a6fb8dSSasha Levin 331c7850f9SSasha Levin /* Warning: Immediately use value returned from this function */ 34b4422bf3SAneesh Kumar K.V static const char *rel_to_abs(struct p9_dev *p9dev, 35b4422bf3SAneesh Kumar K.V const char *path, char *abs_path) 361c7850f9SSasha Levin { 37b4422bf3SAneesh Kumar K.V sprintf(abs_path, "%s/%s", p9dev->root_dir, path); 381c7850f9SSasha Levin 391c7850f9SSasha Levin return abs_path; 401c7850f9SSasha Levin } 411c7850f9SSasha Levin 42c797b6c6SAneesh Kumar K.V static void stat2qid(struct stat *st, struct p9_qid *qid) 431c7850f9SSasha Levin { 441c7850f9SSasha Levin *qid = (struct p9_qid) { 451c7850f9SSasha Levin .path = st->st_ino, 461c7850f9SSasha Levin .version = st->st_mtime, 471c7850f9SSasha Levin }; 481c7850f9SSasha Levin 491c7850f9SSasha Levin if (S_ISDIR(st->st_mode)) 501c7850f9SSasha Levin qid->type |= P9_QTDIR; 511c7850f9SSasha Levin } 521c7850f9SSasha Levin 53b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid) 541c7850f9SSasha Levin { 55b4422bf3SAneesh Kumar K.V if (p9dev->fids[fid].fd > 0) { 56b4422bf3SAneesh Kumar K.V close(p9dev->fids[fid].fd); 57b4422bf3SAneesh Kumar K.V p9dev->fids[fid].fd = -1; 581c7850f9SSasha Levin } 59b4422bf3SAneesh Kumar K.V if (p9dev->fids[fid].dir) { 60b4422bf3SAneesh Kumar K.V closedir(p9dev->fids[fid].dir); 61b4422bf3SAneesh Kumar K.V p9dev->fids[fid].dir = NULL; 621c7850f9SSasha Levin } 63c797b6c6SAneesh Kumar K.V p9dev->fids[fid].fid = P9_NOFID; 641c7850f9SSasha Levin } 651c7850f9SSasha Levin 66bfc15268SAneesh Kumar K.V static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size) 671c7850f9SSasha Levin { 68bfc15268SAneesh Kumar K.V u8 cmd; 69bfc15268SAneesh Kumar K.V u16 tag; 70bfc15268SAneesh Kumar K.V 71bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32); 72bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag); 73bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 74bfc15268SAneesh Kumar K.V /* cmd + 1 is the reply message */ 75bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag); 761c7850f9SSasha Levin } 771c7850f9SSasha Levin 786b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt) 796b163a87SAneesh Kumar K.V { 806b163a87SAneesh Kumar K.V int i; 816b163a87SAneesh Kumar K.V u32 total = 0; 826b163a87SAneesh Kumar K.V for (i = 0; (i < iov_cnt) && (total < count); i++) { 836b163a87SAneesh Kumar K.V if (total + iov[i].iov_len > count) { 846b163a87SAneesh Kumar K.V /* we don't need this iov fully */ 856b163a87SAneesh Kumar K.V iov[i].iov_len -= ((total + iov[i].iov_len) - count); 866b163a87SAneesh Kumar K.V i++; 876b163a87SAneesh Kumar K.V break; 886b163a87SAneesh Kumar K.V } 896b163a87SAneesh Kumar K.V total += iov[i].iov_len; 906b163a87SAneesh Kumar K.V } 916b163a87SAneesh Kumar K.V return i; 926b163a87SAneesh Kumar K.V } 936b163a87SAneesh Kumar K.V 94eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev, 95eee1ba8eSAneesh Kumar K.V struct p9_pdu *pdu, int err, u32 *outlen) 96eee1ba8eSAneesh Kumar K.V { 97bfc15268SAneesh Kumar K.V u16 tag; 98eee1ba8eSAneesh Kumar K.V 995529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 100c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", err); 101bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 102eee1ba8eSAneesh Kumar K.V 103c797b6c6SAneesh Kumar K.V /* read the tag from input */ 104bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32) + sizeof(u8); 105bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "w", &tag); 106bfc15268SAneesh Kumar K.V 107c797b6c6SAneesh Kumar K.V /* Update the header */ 108bfc15268SAneesh Kumar K.V pdu->write_offset = 0; 109c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RLERROR, tag); 110eee1ba8eSAneesh Kumar K.V } 111eee1ba8eSAneesh Kumar K.V 112ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev, 113af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1141c7850f9SSasha Levin { 115c797b6c6SAneesh Kumar K.V u32 msize; 116c797b6c6SAneesh Kumar K.V char *version; 117c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ds", &msize, &version); 118c797b6c6SAneesh Kumar K.V /* 119c797b6c6SAneesh Kumar K.V * reply with the same msize the client sent us 120c797b6c6SAneesh Kumar K.V * Error out if the request is not for 9P2000.L 121c797b6c6SAneesh Kumar K.V */ 1225529bcd7SAsias He if (!strcmp(version, VIRTIO_9P_VERSION_DOTL)) 123c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, version); 124c797b6c6SAneesh Kumar K.V else 125c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, "unknown"); 1261c7850f9SSasha Levin 127bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 128bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 129c797b6c6SAneesh Kumar K.V free(version); 130ead43b01SAneesh Kumar K.V return; 1311c7850f9SSasha Levin } 1321c7850f9SSasha Levin 133ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev, 134af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1351c7850f9SSasha Levin { 136bfc15268SAneesh Kumar K.V u32 fid; 1371c7850f9SSasha Levin 138bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid); 139bfc15268SAneesh Kumar K.V close_fid(p9dev, fid); 1401c7850f9SSasha Levin 141bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 142bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 143ead43b01SAneesh Kumar K.V return; 1441c7850f9SSasha Levin } 1451c7850f9SSasha Levin 146c797b6c6SAneesh Kumar K.V /* 147c797b6c6SAneesh Kumar K.V * FIXME!! Need to map to protocol independent value. Upstream 148c797b6c6SAneesh Kumar K.V * 9p also have the same BUG 149c797b6c6SAneesh Kumar K.V */ 150c797b6c6SAneesh Kumar K.V static int virtio_p9_openflags(int flags) 151c797b6c6SAneesh Kumar K.V { 152c797b6c6SAneesh Kumar K.V flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT | O_DIRECT); 153c797b6c6SAneesh Kumar K.V flags |= O_NOFOLLOW; 154c797b6c6SAneesh Kumar K.V return flags; 155c797b6c6SAneesh Kumar K.V } 156c797b6c6SAneesh Kumar K.V 157ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev, 158af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1591c7850f9SSasha Levin { 160c797b6c6SAneesh Kumar K.V u32 fid, flags; 1611c7850f9SSasha Levin struct stat st; 162bfc15268SAneesh Kumar K.V struct p9_qid qid; 163bfc15268SAneesh Kumar K.V struct p9_fid *new_fid; 164bfc15268SAneesh Kumar K.V 165c797b6c6SAneesh Kumar K.V 166c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid, &flags); 16731a6fb8dSSasha Levin new_fid = get_fid(p9dev, fid); 1681c7850f9SSasha Levin 16930204a77SAneesh Kumar K.V if (lstat(new_fid->abs_path, &st) < 0) 170eee1ba8eSAneesh Kumar K.V goto err_out; 1711c7850f9SSasha Levin 172c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 1731c7850f9SSasha Levin 174eee1ba8eSAneesh Kumar K.V if (new_fid->is_dir) { 1751c7850f9SSasha Levin new_fid->dir = opendir(new_fid->abs_path); 176eee1ba8eSAneesh Kumar K.V if (!new_fid->dir) 177eee1ba8eSAneesh Kumar K.V goto err_out; 178eee1ba8eSAneesh Kumar K.V } else { 179eee1ba8eSAneesh Kumar K.V new_fid->fd = open(new_fid->abs_path, 180c797b6c6SAneesh Kumar K.V virtio_p9_openflags(flags)); 181eee1ba8eSAneesh Kumar K.V if (new_fid->fd < 0) 182eee1ba8eSAneesh Kumar K.V goto err_out; 183eee1ba8eSAneesh Kumar K.V } 184c797b6c6SAneesh Kumar K.V /* FIXME!! need ot send proper iounit */ 185bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 186bfc15268SAneesh Kumar K.V 187bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 188bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 189ead43b01SAneesh Kumar K.V return; 190eee1ba8eSAneesh Kumar K.V err_out: 191eee1ba8eSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 192ead43b01SAneesh Kumar K.V return; 1931c7850f9SSasha Levin } 1941c7850f9SSasha Levin 195ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev, 196af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1971c7850f9SSasha Levin { 198c797b6c6SAneesh Kumar K.V int fd, ret; 199bfc15268SAneesh Kumar K.V char *name; 200af045e53SAneesh Kumar K.V struct stat st; 201bfc15268SAneesh Kumar K.V struct p9_qid qid; 202c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 2034bc9734aSAneesh Kumar K.V char full_path[PATH_MAX]; 204c797b6c6SAneesh Kumar K.V u32 dfid_val, flags, mode, gid; 205af045e53SAneesh Kumar K.V 206c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsddd", &dfid_val, 207c797b6c6SAneesh Kumar K.V &name, &flags, &mode, &gid); 20831a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 2091c7850f9SSasha Levin 210c797b6c6SAneesh Kumar K.V flags = virtio_p9_openflags(flags); 2115f900f6dSSasha Levin 212c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 213c797b6c6SAneesh Kumar K.V fd = open(full_path, flags | O_CREAT, mode); 2144bc9734aSAneesh Kumar K.V if (fd < 0) 2154bc9734aSAneesh Kumar K.V goto err_out; 216c797b6c6SAneesh Kumar K.V close_fid(p9dev, dfid_val); 217c797b6c6SAneesh Kumar K.V dfid->fd = fd; 218c797b6c6SAneesh Kumar K.V 2194bc9734aSAneesh Kumar K.V if (lstat(full_path, &st) < 0) 2206c8ca053SAneesh Kumar K.V goto err_out; 2211c7850f9SSasha Levin 222c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 223c797b6c6SAneesh Kumar K.V if (ret < 0) 224c797b6c6SAneesh Kumar K.V goto err_out; 225c797b6c6SAneesh Kumar K.V 226c797b6c6SAneesh Kumar K.V ret = lchown(full_path, dfid->uid, gid); 227c797b6c6SAneesh Kumar K.V if (ret < 0) 228c797b6c6SAneesh Kumar K.V goto err_out; 229c797b6c6SAneesh Kumar K.V 230c797b6c6SAneesh Kumar K.V sprintf(dfid->path, "%s/%s", dfid->path, name); 231c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 232bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 233bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 234bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 2355f900f6dSSasha Levin free(name); 2366c8ca053SAneesh Kumar K.V return; 2376c8ca053SAneesh Kumar K.V err_out: 2385f900f6dSSasha Levin free(name); 239c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 240c797b6c6SAneesh Kumar K.V return; 241c797b6c6SAneesh Kumar K.V } 242c797b6c6SAneesh Kumar K.V 243c797b6c6SAneesh Kumar K.V static void virtio_p9_mkdir(struct p9_dev *p9dev, 244c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 245c797b6c6SAneesh Kumar K.V { 246c797b6c6SAneesh Kumar K.V int ret; 247c797b6c6SAneesh Kumar K.V char *name; 248c797b6c6SAneesh Kumar K.V struct stat st; 249c797b6c6SAneesh Kumar K.V struct p9_qid qid; 250c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 251c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 252c797b6c6SAneesh Kumar K.V u32 dfid_val, mode, gid; 253c797b6c6SAneesh Kumar K.V 254c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdd", &dfid_val, 255c797b6c6SAneesh Kumar K.V &name, &mode, &gid); 25631a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 257c797b6c6SAneesh Kumar K.V 258c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 259c797b6c6SAneesh Kumar K.V ret = mkdir(full_path, mode); 260c797b6c6SAneesh Kumar K.V if (ret < 0) 261c797b6c6SAneesh Kumar K.V goto err_out; 262c797b6c6SAneesh Kumar K.V 263c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0) 264c797b6c6SAneesh Kumar K.V goto err_out; 265c797b6c6SAneesh Kumar K.V 266c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 267c797b6c6SAneesh Kumar K.V if (ret < 0) 268c797b6c6SAneesh Kumar K.V goto err_out; 269c797b6c6SAneesh Kumar K.V 270c797b6c6SAneesh Kumar K.V ret = lchown(full_path, dfid->uid, gid); 271c797b6c6SAneesh Kumar K.V if (ret < 0) 272c797b6c6SAneesh Kumar K.V goto err_out; 273c797b6c6SAneesh Kumar K.V 274c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 275c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0); 276c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 277c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 278c797b6c6SAneesh Kumar K.V free(name); 279c797b6c6SAneesh Kumar K.V return; 280c797b6c6SAneesh Kumar K.V err_out: 281c797b6c6SAneesh Kumar K.V free(name); 282c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 283ead43b01SAneesh Kumar K.V return; 2841c7850f9SSasha Levin } 2851c7850f9SSasha Levin 286ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev, 287af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 2881c7850f9SSasha Levin { 289af045e53SAneesh Kumar K.V u8 i; 290bfc15268SAneesh Kumar K.V u16 nwqid; 291bfc15268SAneesh Kumar K.V u16 nwname; 292bfc15268SAneesh Kumar K.V struct p9_qid wqid; 293bfc15268SAneesh Kumar K.V struct p9_fid *new_fid; 294c797b6c6SAneesh Kumar K.V u32 fid_val, newfid_val; 295c797b6c6SAneesh Kumar K.V 2961c7850f9SSasha Levin 297bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname); 29831a6fb8dSSasha Levin new_fid = get_fid(p9dev, newfid_val); 2991c7850f9SSasha Levin 300bfc15268SAneesh Kumar K.V nwqid = 0; 301bfc15268SAneesh Kumar K.V if (nwname) { 30231a6fb8dSSasha Levin struct p9_fid *fid = get_fid(p9dev, fid_val); 303bfc15268SAneesh Kumar K.V 304baac79a5SAneesh Kumar K.V strcpy(new_fid->path, fid->path); 305bfc15268SAneesh Kumar K.V /* skip the space for count */ 306bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 307bfc15268SAneesh Kumar K.V for (i = 0; i < nwname; i++) { 308bfc15268SAneesh Kumar K.V struct stat st; 3091c7850f9SSasha Levin char tmp[PATH_MAX] = {0}; 3101c7850f9SSasha Levin char full_path[PATH_MAX]; 311e55ed135SPekka Enberg char *str; 312bfc15268SAneesh Kumar K.V 313bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "s", &str); 3141c7850f9SSasha Levin 3151c7850f9SSasha Levin /* Format the new path we're 'walk'ing into */ 316baac79a5SAneesh Kumar K.V sprintf(tmp, "%s/%s", new_fid->path, str); 317e55ed135SPekka Enberg 318e55ed135SPekka Enberg free(str); 319e55ed135SPekka Enberg 320c797b6c6SAneesh Kumar K.V if (lstat(rel_to_abs(p9dev, tmp, full_path), &st) < 0) 3216c8ca053SAneesh Kumar K.V goto err_out; 3221c7850f9SSasha Levin 323c797b6c6SAneesh Kumar K.V stat2qid(&st, &wqid); 3241c7850f9SSasha Levin new_fid->is_dir = S_ISDIR(st.st_mode); 3251c7850f9SSasha Levin strcpy(new_fid->path, tmp); 326bfc15268SAneesh Kumar K.V new_fid->fid = newfid_val; 327c797b6c6SAneesh Kumar K.V new_fid->uid = fid->uid; 328bfc15268SAneesh Kumar K.V nwqid++; 329bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &wqid); 3301c7850f9SSasha Levin } 3311c7850f9SSasha Levin } else { 332bfc15268SAneesh Kumar K.V /* 333bfc15268SAneesh Kumar K.V * update write_offset so our outlen get correct value 334bfc15268SAneesh Kumar K.V */ 335bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16); 336bfc15268SAneesh Kumar K.V new_fid->is_dir = p9dev->fids[fid_val].is_dir; 337bfc15268SAneesh Kumar K.V strcpy(new_fid->path, p9dev->fids[fid_val].path); 338bfc15268SAneesh Kumar K.V new_fid->fid = newfid_val; 339c797b6c6SAneesh Kumar K.V new_fid->uid = p9dev->fids[fid_val].uid; 3401c7850f9SSasha Levin } 341bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 3425529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 343bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", nwqid); 344bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 3456c8ca053SAneesh Kumar K.V return; 3466c8ca053SAneesh Kumar K.V err_out: 3476c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 348ead43b01SAneesh Kumar K.V return; 3491c7850f9SSasha Levin } 3501c7850f9SSasha Levin 351ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev, 352af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 3531c7850f9SSasha Levin { 354c797b6c6SAneesh Kumar K.V int i; 355bfc15268SAneesh Kumar K.V char *uname; 356bfc15268SAneesh Kumar K.V char *aname; 3571c7850f9SSasha Levin struct stat st; 358bfc15268SAneesh Kumar K.V struct p9_qid qid; 3591c7850f9SSasha Levin struct p9_fid *fid; 360c797b6c6SAneesh Kumar K.V u32 fid_val, afid, uid; 361bfc15268SAneesh Kumar K.V 362c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddssd", &fid_val, &afid, 363c797b6c6SAneesh Kumar K.V &uname, &aname, &uid); 3641c7850f9SSasha Levin 36539257180SPekka Enberg free(uname); 36639257180SPekka Enberg free(aname); 36739257180SPekka Enberg 3681c7850f9SSasha Levin /* Reset everything */ 3695529bcd7SAsias He for (i = 0; i < VIRTIO_9P_MAX_FID; i++) 370b4422bf3SAneesh Kumar K.V p9dev->fids[i].fid = P9_NOFID; 3711c7850f9SSasha Levin 37230204a77SAneesh Kumar K.V if (lstat(p9dev->root_dir, &st) < 0) 3736c8ca053SAneesh Kumar K.V goto err_out; 3741c7850f9SSasha Levin 375c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 3761c7850f9SSasha Levin 37731a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 378bfc15268SAneesh Kumar K.V fid->fid = fid_val; 379c797b6c6SAneesh Kumar K.V fid->uid = uid; 3801c7850f9SSasha Levin fid->is_dir = 1; 3811c7850f9SSasha Levin strcpy(fid->path, "/"); 3821c7850f9SSasha Levin 383bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 384bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 385bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 3866c8ca053SAneesh Kumar K.V return; 3876c8ca053SAneesh Kumar K.V err_out: 3886c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 389ead43b01SAneesh Kumar K.V return; 3901c7850f9SSasha Levin } 3911c7850f9SSasha Levin 392c797b6c6SAneesh Kumar K.V static void virtio_p9_fill_stat(struct p9_dev *p9dev, 393c797b6c6SAneesh Kumar K.V struct stat *st, struct p9_stat_dotl *statl) 3945f900f6dSSasha Levin { 395c797b6c6SAneesh Kumar K.V memset(statl, 0, sizeof(*statl)); 396c797b6c6SAneesh Kumar K.V statl->st_mode = st->st_mode; 397c797b6c6SAneesh Kumar K.V statl->st_nlink = st->st_nlink; 398c797b6c6SAneesh Kumar K.V statl->st_uid = st->st_uid; 399c797b6c6SAneesh Kumar K.V statl->st_gid = st->st_gid; 400c797b6c6SAneesh Kumar K.V statl->st_rdev = st->st_rdev; 401c797b6c6SAneesh Kumar K.V statl->st_size = st->st_size; 402c797b6c6SAneesh Kumar K.V statl->st_blksize = st->st_blksize; 403c797b6c6SAneesh Kumar K.V statl->st_blocks = st->st_blocks; 404c797b6c6SAneesh Kumar K.V statl->st_atime_sec = st->st_atime; 405c797b6c6SAneesh Kumar K.V statl->st_atime_nsec = st->st_atim.tv_nsec; 406c797b6c6SAneesh Kumar K.V statl->st_mtime_sec = st->st_mtime; 407c797b6c6SAneesh Kumar K.V statl->st_mtime_nsec = st->st_mtim.tv_nsec; 408c797b6c6SAneesh Kumar K.V statl->st_ctime_sec = st->st_ctime; 409c797b6c6SAneesh Kumar K.V statl->st_ctime_nsec = st->st_ctim.tv_nsec; 410c797b6c6SAneesh Kumar K.V /* Currently we only support BASIC fields in stat */ 411c797b6c6SAneesh Kumar K.V statl->st_result_mask = P9_STATS_BASIC; 412c797b6c6SAneesh Kumar K.V stat2qid(st, &statl->qid); 4131c7850f9SSasha Levin } 4141c7850f9SSasha Levin 415ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev, 416af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 4171c7850f9SSasha Levin { 418bfc15268SAneesh Kumar K.V u64 offset; 419bfc15268SAneesh Kumar K.V u32 fid_val; 420c797b6c6SAneesh Kumar K.V u16 iov_cnt; 421c797b6c6SAneesh Kumar K.V void *iov_base; 422c797b6c6SAneesh Kumar K.V size_t iov_len; 423bfc15268SAneesh Kumar K.V u32 count, rcount; 424bfc15268SAneesh Kumar K.V struct p9_fid *fid; 425c797b6c6SAneesh Kumar K.V 4261c7850f9SSasha Levin 427bfc15268SAneesh Kumar K.V rcount = 0; 428bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 42931a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 43050c479e0SAneesh Kumar K.V 43150c479e0SAneesh Kumar K.V iov_base = pdu->in_iov[0].iov_base; 43250c479e0SAneesh Kumar K.V iov_len = pdu->in_iov[0].iov_len; 43350c479e0SAneesh Kumar K.V iov_cnt = pdu->in_iov_cnt; 4345529bcd7SAsias He pdu->in_iov[0].iov_base += VIRTIO_9P_HDR_LEN + sizeof(u32); 4355529bcd7SAsias He pdu->in_iov[0].iov_len -= VIRTIO_9P_HDR_LEN + sizeof(u32); 4366b163a87SAneesh Kumar K.V pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov, 437bfc15268SAneesh Kumar K.V count, 4386b163a87SAneesh Kumar K.V pdu->in_iov_cnt); 439bfc15268SAneesh Kumar K.V rcount = preadv(fid->fd, pdu->in_iov, 440bfc15268SAneesh Kumar K.V pdu->in_iov_cnt, offset); 441bfc15268SAneesh Kumar K.V if (rcount > count) 442bfc15268SAneesh Kumar K.V rcount = count; 443bfc15268SAneesh Kumar K.V /* 444bfc15268SAneesh Kumar K.V * Update the iov_base back, so that rest of 445bfc15268SAneesh Kumar K.V * pdu_writef works correctly. 446bfc15268SAneesh Kumar K.V */ 44750c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_base = iov_base; 44850c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_len = iov_len; 44950c479e0SAneesh Kumar K.V pdu->in_iov_cnt = iov_cnt; 450c797b6c6SAneesh Kumar K.V 4515529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 452bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 453bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 454bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 455ead43b01SAneesh Kumar K.V return; 4561c7850f9SSasha Levin } 4571c7850f9SSasha Levin 458c797b6c6SAneesh Kumar K.V static int virtio_p9_dentry_size(struct dirent *dent) 459c797b6c6SAneesh Kumar K.V { 460c797b6c6SAneesh Kumar K.V /* 461c797b6c6SAneesh Kumar K.V * Size of each dirent: 462c797b6c6SAneesh Kumar K.V * qid(13) + offset(8) + type(1) + name_len(2) + name 463c797b6c6SAneesh Kumar K.V */ 464c797b6c6SAneesh Kumar K.V return 24 + strlen(dent->d_name); 465c797b6c6SAneesh Kumar K.V } 466c797b6c6SAneesh Kumar K.V 467c797b6c6SAneesh Kumar K.V static void virtio_p9_readdir(struct p9_dev *p9dev, 468c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 469c797b6c6SAneesh Kumar K.V { 470c797b6c6SAneesh Kumar K.V u32 fid_val; 471c797b6c6SAneesh Kumar K.V u32 count, rcount; 472c797b6c6SAneesh Kumar K.V struct stat st; 473c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 474c797b6c6SAneesh Kumar K.V struct dirent *dent; 475c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 476c797b6c6SAneesh Kumar K.V u64 offset, old_offset; 477c797b6c6SAneesh Kumar K.V 478c797b6c6SAneesh Kumar K.V rcount = 0; 479c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 48031a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 481c797b6c6SAneesh Kumar K.V 482c797b6c6SAneesh Kumar K.V if (!fid->is_dir) { 483c797b6c6SAneesh Kumar K.V errno = -EINVAL; 484c797b6c6SAneesh Kumar K.V goto err_out; 485c797b6c6SAneesh Kumar K.V } 486c797b6c6SAneesh Kumar K.V 487c797b6c6SAneesh Kumar K.V /* Move the offset specified */ 488c797b6c6SAneesh Kumar K.V seekdir(fid->dir, offset); 489c797b6c6SAneesh Kumar K.V 490c797b6c6SAneesh Kumar K.V old_offset = offset; 491c797b6c6SAneesh Kumar K.V /* If reading a dir, fill the buffer with p9_stat entries */ 492c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir); 493c797b6c6SAneesh Kumar K.V 494c797b6c6SAneesh Kumar K.V /* Skip the space for writing count */ 495c797b6c6SAneesh Kumar K.V pdu->write_offset += sizeof(u32); 496c797b6c6SAneesh Kumar K.V while (dent) { 497c797b6c6SAneesh Kumar K.V u32 read; 498c797b6c6SAneesh Kumar K.V struct p9_qid qid; 499c797b6c6SAneesh Kumar K.V 500c797b6c6SAneesh Kumar K.V if ((rcount + virtio_p9_dentry_size(dent)) > count) { 501c797b6c6SAneesh Kumar K.V /* seek to the previous offset and return */ 502c797b6c6SAneesh Kumar K.V seekdir(fid->dir, old_offset); 503c797b6c6SAneesh Kumar K.V break; 504c797b6c6SAneesh Kumar K.V } 505c797b6c6SAneesh Kumar K.V old_offset = dent->d_off; 506c797b6c6SAneesh Kumar K.V lstat(rel_to_abs(p9dev, dent->d_name, full_path), &st); 507c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 508c797b6c6SAneesh Kumar K.V read = pdu->write_offset; 509c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qqbs", &qid, dent->d_off, 510c797b6c6SAneesh Kumar K.V dent->d_type, dent->d_name); 511c797b6c6SAneesh Kumar K.V rcount += pdu->write_offset - read; 512c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir); 513c797b6c6SAneesh Kumar K.V } 514c797b6c6SAneesh Kumar K.V 5155529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 516c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount); 517c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset + rcount; 518c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 519c797b6c6SAneesh Kumar K.V return; 520c797b6c6SAneesh Kumar K.V err_out: 521c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 522c797b6c6SAneesh Kumar K.V return; 523c797b6c6SAneesh Kumar K.V } 524c797b6c6SAneesh Kumar K.V 525c797b6c6SAneesh Kumar K.V 526c797b6c6SAneesh Kumar K.V static void virtio_p9_getattr(struct p9_dev *p9dev, 527af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5281c7850f9SSasha Levin { 529bfc15268SAneesh Kumar K.V u32 fid_val; 530af045e53SAneesh Kumar K.V struct stat st; 531c797b6c6SAneesh Kumar K.V u64 request_mask; 532bfc15268SAneesh Kumar K.V struct p9_fid *fid; 533c797b6c6SAneesh Kumar K.V struct p9_stat_dotl statl; 5341c7850f9SSasha Levin 535c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dq", &fid_val, &request_mask); 53631a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 53730204a77SAneesh Kumar K.V if (lstat(fid->abs_path, &st) < 0) 5386c8ca053SAneesh Kumar K.V goto err_out; 5391c7850f9SSasha Levin 540c797b6c6SAneesh Kumar K.V virtio_p9_fill_stat(p9dev, &st, &statl); 541c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "A", &statl); 542bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 543bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 544ead43b01SAneesh Kumar K.V return; 5456c8ca053SAneesh Kumar K.V err_out: 5466c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 5476c8ca053SAneesh Kumar K.V return; 5481c7850f9SSasha Levin } 5491c7850f9SSasha Levin 550c797b6c6SAneesh Kumar K.V /* FIXME!! from linux/fs.h */ 551c797b6c6SAneesh Kumar K.V /* 552c797b6c6SAneesh Kumar K.V * Attribute flags. These should be or-ed together to figure out what 553c797b6c6SAneesh Kumar K.V * has been changed! 554c797b6c6SAneesh Kumar K.V */ 555c797b6c6SAneesh Kumar K.V #define ATTR_MODE (1 << 0) 556c797b6c6SAneesh Kumar K.V #define ATTR_UID (1 << 1) 557c797b6c6SAneesh Kumar K.V #define ATTR_GID (1 << 2) 558c797b6c6SAneesh Kumar K.V #define ATTR_SIZE (1 << 3) 559c797b6c6SAneesh Kumar K.V #define ATTR_ATIME (1 << 4) 560c797b6c6SAneesh Kumar K.V #define ATTR_MTIME (1 << 5) 561c797b6c6SAneesh Kumar K.V #define ATTR_CTIME (1 << 6) 562c797b6c6SAneesh Kumar K.V #define ATTR_ATIME_SET (1 << 7) 563c797b6c6SAneesh Kumar K.V #define ATTR_MTIME_SET (1 << 8) 564c797b6c6SAneesh Kumar K.V #define ATTR_FORCE (1 << 9) /* Not a change, but a change it */ 565c797b6c6SAneesh Kumar K.V #define ATTR_ATTR_FLAG (1 << 10) 566c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SUID (1 << 11) 567c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SGID (1 << 12) 568c797b6c6SAneesh Kumar K.V #define ATTR_FILE (1 << 13) 569c797b6c6SAneesh Kumar K.V #define ATTR_KILL_PRIV (1 << 14) 570c797b6c6SAneesh Kumar K.V #define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ 571c797b6c6SAneesh Kumar K.V #define ATTR_TIMES_SET (1 << 16) 572c797b6c6SAneesh Kumar K.V 573c797b6c6SAneesh Kumar K.V #define ATTR_MASK 127 574c797b6c6SAneesh Kumar K.V 575c797b6c6SAneesh Kumar K.V static void virtio_p9_setattr(struct p9_dev *p9dev, 576af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 5771c7850f9SSasha Levin { 578c797b6c6SAneesh Kumar K.V int ret = 0; 579bfc15268SAneesh Kumar K.V u32 fid_val; 580bfc15268SAneesh Kumar K.V struct p9_fid *fid; 581c797b6c6SAneesh Kumar K.V struct p9_iattr_dotl p9attr; 5821c7850f9SSasha Levin 583c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dI", &fid_val, &p9attr); 58431a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 5851c7850f9SSasha Levin 586c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MODE) { 587c797b6c6SAneesh Kumar K.V ret = chmod(fid->abs_path, p9attr.mode); 588c797b6c6SAneesh Kumar K.V if (ret < 0) 589c797b6c6SAneesh Kumar K.V goto err_out; 590c797b6c6SAneesh Kumar K.V } 591c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_ATIME | ATTR_MTIME)) { 592c797b6c6SAneesh Kumar K.V struct timespec times[2]; 593c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME) { 594c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME_SET) { 595c797b6c6SAneesh Kumar K.V times[0].tv_sec = p9attr.atime_sec; 596c797b6c6SAneesh Kumar K.V times[0].tv_nsec = p9attr.atime_nsec; 597c797b6c6SAneesh Kumar K.V } else { 598c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_NOW; 599c797b6c6SAneesh Kumar K.V } 600c797b6c6SAneesh Kumar K.V } else { 601c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_OMIT; 602c797b6c6SAneesh Kumar K.V } 603c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME) { 604c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME_SET) { 605c797b6c6SAneesh Kumar K.V times[1].tv_sec = p9attr.mtime_sec; 606c797b6c6SAneesh Kumar K.V times[1].tv_nsec = p9attr.mtime_nsec; 607c797b6c6SAneesh Kumar K.V } else { 608c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_NOW; 609c797b6c6SAneesh Kumar K.V } 610c797b6c6SAneesh Kumar K.V } else 611c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_OMIT; 612c797b6c6SAneesh Kumar K.V 613c797b6c6SAneesh Kumar K.V ret = utimensat(-1, fid->abs_path, times, AT_SYMLINK_NOFOLLOW); 614c797b6c6SAneesh Kumar K.V if (ret < 0) 615c797b6c6SAneesh Kumar K.V goto err_out; 616c797b6c6SAneesh Kumar K.V } 617c797b6c6SAneesh Kumar K.V /* 618c797b6c6SAneesh Kumar K.V * If the only valid entry in iattr is ctime we can call 619c797b6c6SAneesh Kumar K.V * chown(-1,-1) to update the ctime of the file 620c797b6c6SAneesh Kumar K.V */ 621c797b6c6SAneesh Kumar K.V if ((p9attr.valid & (ATTR_UID | ATTR_GID)) || 622c797b6c6SAneesh Kumar K.V ((p9attr.valid & ATTR_CTIME) 623c797b6c6SAneesh Kumar K.V && !((p9attr.valid & ATTR_MASK) & ~ATTR_CTIME))) { 624c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_UID)) 625c797b6c6SAneesh Kumar K.V p9attr.uid = -1; 626c797b6c6SAneesh Kumar K.V 627c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_GID)) 628c797b6c6SAneesh Kumar K.V p9attr.gid = -1; 629c797b6c6SAneesh Kumar K.V 630c797b6c6SAneesh Kumar K.V ret = lchown(fid->abs_path, p9attr.uid, p9attr.gid); 631c797b6c6SAneesh Kumar K.V if (ret < 0) 632c797b6c6SAneesh Kumar K.V goto err_out; 633c797b6c6SAneesh Kumar K.V } 634c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_SIZE)) { 635c797b6c6SAneesh Kumar K.V ret = truncate(fid->abs_path, p9attr.size); 636c797b6c6SAneesh Kumar K.V if (ret < 0) 637c797b6c6SAneesh Kumar K.V goto err_out; 638c797b6c6SAneesh Kumar K.V } 6395529bcd7SAsias He *outlen = VIRTIO_9P_HDR_LEN; 640bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 641ead43b01SAneesh Kumar K.V return; 6424bc9734aSAneesh Kumar K.V err_out: 6434bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 6444bc9734aSAneesh Kumar K.V return; 6451c7850f9SSasha Levin } 6461c7850f9SSasha Levin 647ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev, 648af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 6491c7850f9SSasha Levin { 6504bc9734aSAneesh Kumar K.V 651bfc15268SAneesh Kumar K.V u64 offset; 652bfc15268SAneesh Kumar K.V u32 fid_val; 6534bc9734aSAneesh Kumar K.V u32 count; 6544bc9734aSAneesh Kumar K.V ssize_t res; 65550c479e0SAneesh Kumar K.V u16 iov_cnt; 65650c479e0SAneesh Kumar K.V void *iov_base; 65750c479e0SAneesh Kumar K.V size_t iov_len; 658bfc15268SAneesh Kumar K.V struct p9_fid *fid; 659b064b05aSAneesh Kumar K.V /* u32 fid + u64 offset + u32 count */ 660b064b05aSAneesh Kumar K.V int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32); 6611c7850f9SSasha Levin 662bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count); 66331a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 664af045e53SAneesh Kumar K.V 66550c479e0SAneesh Kumar K.V iov_base = pdu->out_iov[0].iov_base; 66650c479e0SAneesh Kumar K.V iov_len = pdu->out_iov[0].iov_len; 66750c479e0SAneesh Kumar K.V iov_cnt = pdu->out_iov_cnt; 66850c479e0SAneesh Kumar K.V 669bfc15268SAneesh Kumar K.V /* Adjust the iovec to skip the header and meta data */ 670b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size); 671b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_len -= (sizeof(struct p9_msg) + twrite_size); 672bfc15268SAneesh Kumar K.V pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count, 6736b163a87SAneesh Kumar K.V pdu->out_iov_cnt); 6744bc9734aSAneesh Kumar K.V res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset); 67550c479e0SAneesh Kumar K.V /* 67650c479e0SAneesh Kumar K.V * Update the iov_base back, so that rest of 67750c479e0SAneesh Kumar K.V * pdu_readf works correctly. 67850c479e0SAneesh Kumar K.V */ 67950c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_base = iov_base; 68050c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_len = iov_len; 68150c479e0SAneesh Kumar K.V pdu->out_iov_cnt = iov_cnt; 682c797b6c6SAneesh Kumar K.V 6834bc9734aSAneesh Kumar K.V if (res < 0) 6844bc9734aSAneesh Kumar K.V goto err_out; 6854bc9734aSAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", res); 686bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset; 687bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 688ead43b01SAneesh Kumar K.V return; 6894bc9734aSAneesh Kumar K.V err_out: 6904bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 6914bc9734aSAneesh Kumar K.V return; 6921c7850f9SSasha Levin } 6931c7850f9SSasha Levin 6946fc5cd9bSSasha Levin static void virtio_p9_remove(struct p9_dev *p9dev, 6956fc5cd9bSSasha Levin struct p9_pdu *pdu, u32 *outlen) 6966fc5cd9bSSasha Levin { 6976fc5cd9bSSasha Levin int ret; 6986fc5cd9bSSasha Levin u32 fid_val; 6996fc5cd9bSSasha Levin struct p9_fid *fid; 7006fc5cd9bSSasha Levin 7016fc5cd9bSSasha Levin virtio_p9_pdu_readf(pdu, "d", &fid_val); 70231a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 7036fc5cd9bSSasha Levin 7049b604a9cSSasha Levin ret = remove(fid->abs_path); 7056fc5cd9bSSasha Levin if (ret < 0) 7066fc5cd9bSSasha Levin goto err_out; 7076fc5cd9bSSasha Levin *outlen = pdu->write_offset; 7086fc5cd9bSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 7096fc5cd9bSSasha Levin return; 7106fc5cd9bSSasha Levin 7116fc5cd9bSSasha Levin err_out: 7126fc5cd9bSSasha Levin virtio_p9_error_reply(p9dev, pdu, errno, outlen); 7136fc5cd9bSSasha Levin return; 7146fc5cd9bSSasha Levin } 7156fc5cd9bSSasha Levin 716f161f28bSSasha Levin static void virtio_p9_rename(struct p9_dev *p9dev, 717f161f28bSSasha Levin struct p9_pdu *pdu, u32 *outlen) 718f161f28bSSasha Levin { 719f161f28bSSasha Levin int ret; 720f161f28bSSasha Levin u32 fid_val, new_fid_val; 721f161f28bSSasha Levin struct p9_fid *fid, *new_fid; 722f161f28bSSasha Levin char full_path[PATH_MAX], *new_name; 723f161f28bSSasha Levin 724f161f28bSSasha Levin virtio_p9_pdu_readf(pdu, "dds", &fid_val, &new_fid_val, &new_name); 72531a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 72631a6fb8dSSasha Levin new_fid = get_fid(p9dev, new_fid_val); 727f161f28bSSasha Levin 728f161f28bSSasha Levin sprintf(full_path, "%s/%s", new_fid->abs_path, new_name); 729f161f28bSSasha Levin ret = rename(fid->abs_path, full_path); 730f161f28bSSasha Levin if (ret < 0) 731f161f28bSSasha Levin goto err_out; 732f161f28bSSasha Levin close_fid(p9dev, fid_val); 733f161f28bSSasha Levin *outlen = pdu->write_offset; 734f161f28bSSasha Levin virtio_p9_set_reply_header(pdu, *outlen); 735f161f28bSSasha Levin return; 736f161f28bSSasha Levin 737f161f28bSSasha Levin err_out: 738f161f28bSSasha Levin virtio_p9_error_reply(p9dev, pdu, errno, outlen); 739f161f28bSSasha Levin return; 740f161f28bSSasha Levin } 741f161f28bSSasha Levin 742c797b6c6SAneesh Kumar K.V static void virtio_p9_readlink(struct p9_dev *p9dev, 743c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 744c797b6c6SAneesh Kumar K.V { 745c797b6c6SAneesh Kumar K.V int ret; 746c797b6c6SAneesh Kumar K.V u32 fid_val; 747c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 748c797b6c6SAneesh Kumar K.V char target_path[PATH_MAX]; 749c797b6c6SAneesh Kumar K.V 750c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 75131a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 752c797b6c6SAneesh Kumar K.V 753c797b6c6SAneesh Kumar K.V memset(target_path, 0, PATH_MAX); 754c797b6c6SAneesh Kumar K.V ret = readlink(fid->abs_path, target_path, PATH_MAX - 1); 755c797b6c6SAneesh Kumar K.V if (ret < 0) 756c797b6c6SAneesh Kumar K.V goto err_out; 757c797b6c6SAneesh Kumar K.V 758c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "s", target_path); 759c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 760c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 761c797b6c6SAneesh Kumar K.V return; 762c797b6c6SAneesh Kumar K.V err_out: 763c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 764c797b6c6SAneesh Kumar K.V return; 765c797b6c6SAneesh Kumar K.V } 766c797b6c6SAneesh Kumar K.V 767c797b6c6SAneesh Kumar K.V static void virtio_p9_statfs(struct p9_dev *p9dev, 768c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 769c797b6c6SAneesh Kumar K.V { 770c797b6c6SAneesh Kumar K.V int ret; 771c797b6c6SAneesh Kumar K.V u64 fsid; 772c797b6c6SAneesh Kumar K.V u32 fid_val; 773c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 774c797b6c6SAneesh Kumar K.V struct statfs stat_buf; 775c797b6c6SAneesh Kumar K.V 776c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val); 77731a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 778c797b6c6SAneesh Kumar K.V 779c797b6c6SAneesh Kumar K.V ret = statfs(fid->abs_path, &stat_buf); 780c797b6c6SAneesh Kumar K.V if (ret < 0) 781c797b6c6SAneesh Kumar K.V goto err_out; 782c797b6c6SAneesh Kumar K.V /* FIXME!! f_blocks needs update based on client msize */ 783c797b6c6SAneesh Kumar K.V fsid = (unsigned int) stat_buf.f_fsid.__val[0] | 784c797b6c6SAneesh Kumar K.V (unsigned long long)stat_buf.f_fsid.__val[1] << 32; 785c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ddqqqqqqd", stat_buf.f_type, 786c797b6c6SAneesh Kumar K.V stat_buf.f_bsize, stat_buf.f_blocks, 787c797b6c6SAneesh Kumar K.V stat_buf.f_bfree, stat_buf.f_bavail, 788c797b6c6SAneesh Kumar K.V stat_buf.f_files, stat_buf.f_ffree, 789c797b6c6SAneesh Kumar K.V fsid, stat_buf.f_namelen); 790c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 791c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 792c797b6c6SAneesh Kumar K.V return; 793c797b6c6SAneesh Kumar K.V err_out: 794c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 795c797b6c6SAneesh Kumar K.V return; 796c797b6c6SAneesh Kumar K.V } 797c797b6c6SAneesh Kumar K.V 798c797b6c6SAneesh Kumar K.V static void virtio_p9_mknod(struct p9_dev *p9dev, 799c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 800c797b6c6SAneesh Kumar K.V { 801c797b6c6SAneesh Kumar K.V int ret; 802c797b6c6SAneesh Kumar K.V char *name; 803c797b6c6SAneesh Kumar K.V struct stat st; 804c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 805c797b6c6SAneesh Kumar K.V struct p9_qid qid; 806c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 807c797b6c6SAneesh Kumar K.V u32 fid_val, mode, major, minor, gid; 808c797b6c6SAneesh Kumar K.V 809c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdddd", &fid_val, &name, &mode, 810c797b6c6SAneesh Kumar K.V &major, &minor, &gid); 811c797b6c6SAneesh Kumar K.V 81231a6fb8dSSasha Levin dfid = get_fid(p9dev, fid_val); 813c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 814c797b6c6SAneesh Kumar K.V ret = mknod(full_path, mode, makedev(major, minor)); 815c797b6c6SAneesh Kumar K.V if (ret < 0) 816c797b6c6SAneesh Kumar K.V goto err_out; 817c797b6c6SAneesh Kumar K.V 818c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0) 819c797b6c6SAneesh Kumar K.V goto err_out; 820c797b6c6SAneesh Kumar K.V 821c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777); 822c797b6c6SAneesh Kumar K.V if (ret < 0) 823c797b6c6SAneesh Kumar K.V goto err_out; 824c797b6c6SAneesh Kumar K.V 825c797b6c6SAneesh Kumar K.V ret = lchown(full_path, 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 *outlen = pdu->write_offset; 833c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 834c797b6c6SAneesh Kumar K.V return; 835c797b6c6SAneesh Kumar K.V err_out: 836c797b6c6SAneesh Kumar K.V free(name); 837c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 838c797b6c6SAneesh Kumar K.V return; 839c797b6c6SAneesh Kumar K.V } 840c797b6c6SAneesh Kumar K.V 841c797b6c6SAneesh Kumar K.V static void virtio_p9_fsync(struct p9_dev *p9dev, 842c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 843c797b6c6SAneesh Kumar K.V { 844c797b6c6SAneesh Kumar K.V int ret; 845c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 846c797b6c6SAneesh Kumar K.V u32 fid_val, datasync; 847c797b6c6SAneesh Kumar K.V 848c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid_val, &datasync); 84931a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 850c797b6c6SAneesh Kumar K.V 851c797b6c6SAneesh Kumar K.V if (datasync) 852c797b6c6SAneesh Kumar K.V ret = fdatasync(fid->fd); 853c797b6c6SAneesh Kumar K.V else 854c797b6c6SAneesh Kumar K.V ret = fsync(fid->fd); 855c797b6c6SAneesh Kumar K.V if (ret < 0) 856c797b6c6SAneesh Kumar K.V goto err_out; 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_symlink(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 struct stat st; 870c797b6c6SAneesh Kumar K.V u32 fid_val, gid; 871c797b6c6SAneesh Kumar K.V struct p9_qid qid; 872c797b6c6SAneesh Kumar K.V struct p9_fid *dfid; 873c797b6c6SAneesh Kumar K.V char new_name[PATH_MAX]; 874c797b6c6SAneesh Kumar K.V char *old_path, *name; 875c797b6c6SAneesh Kumar K.V 876c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dssd", &fid_val, &name, &old_path, &gid); 877c797b6c6SAneesh Kumar K.V 87831a6fb8dSSasha Levin dfid = get_fid(p9dev, fid_val); 879c797b6c6SAneesh Kumar K.V sprintf(new_name, "%s/%s", dfid->abs_path, name); 880c797b6c6SAneesh Kumar K.V ret = symlink(old_path, new_name); 881c797b6c6SAneesh Kumar K.V if (ret < 0) 882c797b6c6SAneesh Kumar K.V goto err_out; 883c797b6c6SAneesh Kumar K.V 884c797b6c6SAneesh Kumar K.V if (lstat(new_name, &st) < 0) 885c797b6c6SAneesh Kumar K.V goto err_out; 886c797b6c6SAneesh Kumar K.V 887c797b6c6SAneesh Kumar K.V ret = lchown(new_name, dfid->uid, gid); 888c797b6c6SAneesh Kumar K.V if (ret < 0) 889c797b6c6SAneesh Kumar K.V goto err_out; 890c797b6c6SAneesh Kumar K.V 891c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid); 892c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid); 893c797b6c6SAneesh Kumar K.V free(name); 894c797b6c6SAneesh Kumar K.V free(old_path); 895c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 896c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 897c797b6c6SAneesh Kumar K.V return; 898c797b6c6SAneesh Kumar K.V err_out: 899c797b6c6SAneesh Kumar K.V free(name); 900c797b6c6SAneesh Kumar K.V free(old_path); 901c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 902c797b6c6SAneesh Kumar K.V return; 903c797b6c6SAneesh Kumar K.V } 904c797b6c6SAneesh Kumar K.V 905c797b6c6SAneesh Kumar K.V static void virtio_p9_link(struct p9_dev *p9dev, 906c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 907c797b6c6SAneesh Kumar K.V { 908c797b6c6SAneesh Kumar K.V int ret; 909c797b6c6SAneesh Kumar K.V char *name; 910c797b6c6SAneesh Kumar K.V u32 fid_val, dfid_val; 911c797b6c6SAneesh Kumar K.V struct p9_fid *dfid, *fid; 912c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 913c797b6c6SAneesh Kumar K.V 914c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dds", &dfid_val, &fid_val, &name); 915c797b6c6SAneesh Kumar K.V 91631a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val); 91731a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 918c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", dfid->abs_path, name); 919c797b6c6SAneesh Kumar K.V ret = link(fid->abs_path, full_path); 920c797b6c6SAneesh Kumar K.V if (ret < 0) 921c797b6c6SAneesh Kumar K.V goto err_out; 922c797b6c6SAneesh Kumar K.V free(name); 923c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 924c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 925c797b6c6SAneesh Kumar K.V return; 926c797b6c6SAneesh Kumar K.V err_out: 927c797b6c6SAneesh Kumar K.V free(name); 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 933c797b6c6SAneesh Kumar K.V static void virtio_p9_lock(struct p9_dev *p9dev, 934c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 935c797b6c6SAneesh Kumar K.V { 936c797b6c6SAneesh Kumar K.V u8 ret; 937c797b6c6SAneesh Kumar K.V u32 fid_val; 938c797b6c6SAneesh Kumar K.V struct p9_flock flock; 939c797b6c6SAneesh Kumar K.V 940c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbdqqds", &fid_val, &flock.type, 941c797b6c6SAneesh Kumar K.V &flock.flags, &flock.start, &flock.length, 942c797b6c6SAneesh Kumar K.V &flock.proc_id, &flock.client_id); 943c797b6c6SAneesh Kumar K.V 944c797b6c6SAneesh Kumar K.V /* Just return success */ 945c797b6c6SAneesh Kumar K.V ret = P9_LOCK_SUCCESS; 946c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", ret); 947c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 948c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 949c797b6c6SAneesh Kumar K.V free(flock.client_id); 950c797b6c6SAneesh Kumar K.V return; 951c797b6c6SAneesh Kumar K.V } 952c797b6c6SAneesh Kumar K.V 953c797b6c6SAneesh Kumar K.V static void virtio_p9_getlock(struct p9_dev *p9dev, 954c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 955c797b6c6SAneesh Kumar K.V { 956c797b6c6SAneesh Kumar K.V u32 fid_val; 957c797b6c6SAneesh Kumar K.V struct p9_getlock glock; 958c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbqqds", &fid_val, &glock.type, 959c797b6c6SAneesh Kumar K.V &glock.start, &glock.length, &glock.proc_id, 960c797b6c6SAneesh Kumar K.V &glock.client_id); 961c797b6c6SAneesh Kumar K.V 962c797b6c6SAneesh Kumar K.V /* Just return success */ 963c797b6c6SAneesh Kumar K.V glock.type = F_UNLCK; 964c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "bqqds", glock.type, 965c797b6c6SAneesh Kumar K.V glock.start, glock.length, glock.proc_id, 966c797b6c6SAneesh Kumar K.V glock.client_id); 967c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 968c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 969c797b6c6SAneesh Kumar K.V free(glock.client_id); 970c797b6c6SAneesh Kumar K.V return; 971c797b6c6SAneesh Kumar K.V } 972c797b6c6SAneesh Kumar K.V 973c797b6c6SAneesh Kumar K.V static int virtio_p9_ancestor(char *path, char *ancestor) 974c797b6c6SAneesh Kumar K.V { 975c797b6c6SAneesh Kumar K.V int size = strlen(ancestor); 976c797b6c6SAneesh Kumar K.V if (!strncmp(path, ancestor, size)) { 977c797b6c6SAneesh Kumar K.V /* 978c797b6c6SAneesh Kumar K.V * Now check whether ancestor is a full name or 979c797b6c6SAneesh Kumar K.V * or directory component and not just part 980c797b6c6SAneesh Kumar K.V * of a name. 981c797b6c6SAneesh Kumar K.V */ 982c797b6c6SAneesh Kumar K.V if (path[size] == '\0' || path[size] == '/') 983c797b6c6SAneesh Kumar K.V return 1; 984c797b6c6SAneesh Kumar K.V } 985c797b6c6SAneesh Kumar K.V return 0; 986c797b6c6SAneesh Kumar K.V } 987c797b6c6SAneesh Kumar K.V 988c797b6c6SAneesh Kumar K.V static void virtio_p9_fix_path(char *fid_path, char *old_name, char *new_name) 989c797b6c6SAneesh Kumar K.V { 990c797b6c6SAneesh Kumar K.V char tmp_name[PATH_MAX]; 991c797b6c6SAneesh Kumar K.V size_t rp_sz = strlen(old_name); 992c797b6c6SAneesh Kumar K.V 993c797b6c6SAneesh Kumar K.V if (rp_sz == strlen(fid_path)) { 994c797b6c6SAneesh Kumar K.V /* replace the full name */ 995c797b6c6SAneesh Kumar K.V strcpy(fid_path, new_name); 996c797b6c6SAneesh Kumar K.V return; 997c797b6c6SAneesh Kumar K.V } 998c797b6c6SAneesh Kumar K.V /* save the trailing path details */ 999c797b6c6SAneesh Kumar K.V strcpy(tmp_name, fid_path + rp_sz); 1000c797b6c6SAneesh Kumar K.V sprintf(fid_path, "%s%s", new_name, tmp_name); 1001c797b6c6SAneesh Kumar K.V return; 1002c797b6c6SAneesh Kumar K.V } 1003c797b6c6SAneesh Kumar K.V 1004c797b6c6SAneesh Kumar K.V static void virtio_p9_renameat(struct p9_dev *p9dev, 1005c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1006c797b6c6SAneesh Kumar K.V { 1007c797b6c6SAneesh Kumar K.V int i, ret; 1008c797b6c6SAneesh Kumar K.V char *old_name, *new_name; 1009c797b6c6SAneesh Kumar K.V u32 old_dfid_val, new_dfid_val; 1010c797b6c6SAneesh Kumar K.V struct p9_fid *old_dfid, *new_dfid; 1011c797b6c6SAneesh Kumar K.V char old_full_path[PATH_MAX], new_full_path[PATH_MAX]; 1012c797b6c6SAneesh Kumar K.V 1013c797b6c6SAneesh Kumar K.V 1014c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsds", &old_dfid_val, &old_name, 1015c797b6c6SAneesh Kumar K.V &new_dfid_val, &new_name); 1016c797b6c6SAneesh Kumar K.V 101731a6fb8dSSasha Levin old_dfid = get_fid(p9dev, old_dfid_val); 101831a6fb8dSSasha Levin new_dfid = get_fid(p9dev, new_dfid_val); 1019c797b6c6SAneesh Kumar K.V 1020c797b6c6SAneesh Kumar K.V sprintf(old_full_path, "%s/%s", old_dfid->abs_path, old_name); 1021c797b6c6SAneesh Kumar K.V sprintf(new_full_path, "%s/%s", new_dfid->abs_path, new_name); 1022c797b6c6SAneesh Kumar K.V ret = rename(old_full_path, new_full_path); 1023c797b6c6SAneesh Kumar K.V if (ret < 0) 1024c797b6c6SAneesh Kumar K.V goto err_out; 1025c797b6c6SAneesh Kumar K.V /* 1026c797b6c6SAneesh Kumar K.V * Now fix path in other fids, if the renamed path is part of 1027c797b6c6SAneesh Kumar K.V * that. 1028c797b6c6SAneesh Kumar K.V */ 10295529bcd7SAsias He for (i = 0; i < VIRTIO_9P_MAX_FID; i++) { 103031a6fb8dSSasha Levin if (get_fid(p9dev, i)->fid != P9_NOFID && 103131a6fb8dSSasha Levin virtio_p9_ancestor(get_fid(p9dev, i)->path, old_name)) { 103231a6fb8dSSasha Levin virtio_p9_fix_path(get_fid(p9dev, i)->path, old_name, 1033c797b6c6SAneesh Kumar K.V new_name); 1034c797b6c6SAneesh Kumar K.V } 1035c797b6c6SAneesh Kumar K.V } 1036c797b6c6SAneesh Kumar K.V free(old_name); 1037c797b6c6SAneesh Kumar K.V free(new_name); 1038c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1039c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1040c797b6c6SAneesh Kumar K.V return; 1041c797b6c6SAneesh Kumar K.V err_out: 1042c797b6c6SAneesh Kumar K.V free(old_name); 1043c797b6c6SAneesh Kumar K.V free(new_name); 1044c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1045c797b6c6SAneesh Kumar K.V return; 1046c797b6c6SAneesh Kumar K.V } 1047c797b6c6SAneesh Kumar K.V 1048c797b6c6SAneesh Kumar K.V static void virtio_p9_unlinkat(struct p9_dev *p9dev, 1049c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1050c797b6c6SAneesh Kumar K.V { 1051c797b6c6SAneesh Kumar K.V int ret; 1052c797b6c6SAneesh Kumar K.V char *name; 1053c797b6c6SAneesh Kumar K.V u32 fid_val, flags; 1054c797b6c6SAneesh Kumar K.V struct p9_fid *fid; 1055c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX]; 1056c797b6c6SAneesh Kumar K.V 1057c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsd", &fid_val, &name, &flags); 105831a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val); 1059c797b6c6SAneesh Kumar K.V 1060c797b6c6SAneesh Kumar K.V sprintf(full_path, "%s/%s", fid->abs_path, name); 1061c797b6c6SAneesh Kumar K.V ret = remove(full_path); 1062c797b6c6SAneesh Kumar K.V if (ret < 0) 1063c797b6c6SAneesh Kumar K.V goto err_out; 1064c797b6c6SAneesh Kumar K.V free(name); 1065c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset; 1066c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen); 1067c797b6c6SAneesh Kumar K.V return; 1068c797b6c6SAneesh Kumar K.V err_out: 1069c797b6c6SAneesh Kumar K.V free(name); 1070c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen); 1071c797b6c6SAneesh Kumar K.V return; 1072c797b6c6SAneesh Kumar K.V } 1073c797b6c6SAneesh Kumar K.V 1074c797b6c6SAneesh Kumar K.V static void virtio_p9_eopnotsupp(struct p9_dev *p9dev, 1075c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen) 1076c797b6c6SAneesh Kumar K.V { 1077c797b6c6SAneesh Kumar K.V return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen); 1078c797b6c6SAneesh Kumar K.V } 1079c797b6c6SAneesh Kumar K.V 1080ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev, 1081af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen); 1082b4422bf3SAneesh Kumar K.V 1083c797b6c6SAneesh Kumar K.V /* FIXME should be removed when merging with latest linus tree */ 1084c797b6c6SAneesh Kumar K.V #define P9_TRENAMEAT 74 1085c797b6c6SAneesh Kumar K.V #define P9_TUNLINKAT 76 1086c797b6c6SAneesh Kumar K.V 1087c797b6c6SAneesh Kumar K.V static p9_handler *virtio_9p_dotl_handler [] = { 1088c797b6c6SAneesh Kumar K.V [P9_TREADDIR] = virtio_p9_readdir, 1089c797b6c6SAneesh Kumar K.V [P9_TSTATFS] = virtio_p9_statfs, 1090c797b6c6SAneesh Kumar K.V [P9_TGETATTR] = virtio_p9_getattr, 1091c797b6c6SAneesh Kumar K.V [P9_TSETATTR] = virtio_p9_setattr, 1092c797b6c6SAneesh Kumar K.V [P9_TXATTRWALK] = virtio_p9_eopnotsupp, 1093c797b6c6SAneesh Kumar K.V [P9_TXATTRCREATE] = virtio_p9_eopnotsupp, 1094c797b6c6SAneesh Kumar K.V [P9_TMKNOD] = virtio_p9_mknod, 1095c797b6c6SAneesh Kumar K.V [P9_TLOCK] = virtio_p9_lock, 1096c797b6c6SAneesh Kumar K.V [P9_TGETLOCK] = virtio_p9_getlock, 1097c797b6c6SAneesh Kumar K.V [P9_TRENAMEAT] = virtio_p9_renameat, 1098c797b6c6SAneesh Kumar K.V [P9_TREADLINK] = virtio_p9_readlink, 1099c797b6c6SAneesh Kumar K.V [P9_TUNLINKAT] = virtio_p9_unlinkat, 1100c797b6c6SAneesh Kumar K.V [P9_TMKDIR] = virtio_p9_mkdir, 1101b4422bf3SAneesh Kumar K.V [P9_TVERSION] = virtio_p9_version, 1102c797b6c6SAneesh Kumar K.V [P9_TLOPEN] = virtio_p9_open, 1103b4422bf3SAneesh Kumar K.V [P9_TATTACH] = virtio_p9_attach, 1104b4422bf3SAneesh Kumar K.V [P9_TWALK] = virtio_p9_walk, 1105c797b6c6SAneesh Kumar K.V [P9_TCLUNK] = virtio_p9_clunk, 1106c797b6c6SAneesh Kumar K.V [P9_TFSYNC] = virtio_p9_fsync, 1107b4422bf3SAneesh Kumar K.V [P9_TREAD] = virtio_p9_read, 1108c797b6c6SAneesh Kumar K.V [P9_TFLUSH] = virtio_p9_eopnotsupp, 1109c797b6c6SAneesh Kumar K.V [P9_TLINK] = virtio_p9_link, 1110c797b6c6SAneesh Kumar K.V [P9_TSYMLINK] = virtio_p9_symlink, 1111c797b6c6SAneesh Kumar K.V [P9_TLCREATE] = virtio_p9_create, 1112b4422bf3SAneesh Kumar K.V [P9_TWRITE] = virtio_p9_write, 11136fc5cd9bSSasha Levin [P9_TREMOVE] = virtio_p9_remove, 1114f161f28bSSasha Levin [P9_TRENAME] = virtio_p9_rename, 1115b4422bf3SAneesh Kumar K.V }; 1116b4422bf3SAneesh Kumar K.V 1117af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq) 1118af045e53SAneesh Kumar K.V { 1119af045e53SAneesh Kumar K.V struct p9_pdu *pdu = calloc(1, sizeof(*pdu)); 1120af045e53SAneesh Kumar K.V if (!pdu) 1121af045e53SAneesh Kumar K.V return NULL; 1122af045e53SAneesh Kumar K.V 1123bfc15268SAneesh Kumar K.V /* skip the pdu header p9_msg */ 11245529bcd7SAsias He pdu->read_offset = VIRTIO_9P_HDR_LEN; 11255529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN; 1126af045e53SAneesh Kumar K.V pdu->queue_head = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov, 1127*a8a44649SAsias He pdu->out_iov, &pdu->in_iov_cnt, &pdu->out_iov_cnt); 1128af045e53SAneesh Kumar K.V return pdu; 1129af045e53SAneesh Kumar K.V } 1130af045e53SAneesh Kumar K.V 1131af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu) 1132af045e53SAneesh Kumar K.V { 1133af045e53SAneesh Kumar K.V struct p9_msg *msg; 1134af045e53SAneesh Kumar K.V /* 1135af045e53SAneesh Kumar K.V * we can peek directly into pdu for a u8 1136af045e53SAneesh Kumar K.V * value. The host endianess won't be an issue 1137af045e53SAneesh Kumar K.V */ 1138af045e53SAneesh Kumar K.V msg = pdu->out_iov[0].iov_base; 1139af045e53SAneesh Kumar K.V return msg->cmd; 1140af045e53SAneesh Kumar K.V } 1141af045e53SAneesh Kumar K.V 1142b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job) 11431c7850f9SSasha Levin { 1144af045e53SAneesh Kumar K.V u8 cmd; 1145b4422bf3SAneesh Kumar K.V u32 len = 0; 1146b4422bf3SAneesh Kumar K.V p9_handler *handler; 1147b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev; 1148af045e53SAneesh Kumar K.V struct virt_queue *vq; 1149af045e53SAneesh Kumar K.V struct p9_pdu *p9pdu; 11501c7850f9SSasha Levin 1151b4422bf3SAneesh Kumar K.V vq = job->vq; 1152b4422bf3SAneesh Kumar K.V p9dev = job->p9dev; 11531c7850f9SSasha Levin 1154af045e53SAneesh Kumar K.V p9pdu = virtio_p9_pdu_init(kvm, vq); 1155af045e53SAneesh Kumar K.V cmd = virtio_p9_get_cmd(p9pdu); 1156af045e53SAneesh Kumar K.V 1157c797b6c6SAneesh Kumar K.V if ((cmd >= ARRAY_SIZE(virtio_9p_dotl_handler)) || 1158c797b6c6SAneesh Kumar K.V !virtio_9p_dotl_handler[cmd]) 115997b408afSAneesh Kumar K.V handler = virtio_p9_eopnotsupp; 1160dd78d9eaSAneesh Kumar K.V else 1161c797b6c6SAneesh Kumar K.V handler = virtio_9p_dotl_handler[cmd]; 1162c797b6c6SAneesh Kumar K.V 1163af045e53SAneesh Kumar K.V handler(p9dev, p9pdu, &len); 1164af045e53SAneesh Kumar K.V virt_queue__set_used_elem(vq, p9pdu->queue_head, len); 1165af045e53SAneesh Kumar K.V free(p9pdu); 11661c7850f9SSasha Levin return true; 11671c7850f9SSasha Levin } 11681c7850f9SSasha Levin 11691c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param) 11701c7850f9SSasha Levin { 1171b4422bf3SAneesh Kumar K.V struct p9_dev_job *job = (struct p9_dev_job *)param; 1172b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = job->p9dev; 1173b4422bf3SAneesh Kumar K.V struct virt_queue *vq = job->vq; 11741c7850f9SSasha Levin 11751c7850f9SSasha Levin while (virt_queue__available(vq)) { 1176b4422bf3SAneesh Kumar K.V virtio_p9_do_io_request(kvm, job); 117702eca50cSAsias He p9dev->vdev.ops->signal_vq(kvm, &p9dev->vdev, vq - p9dev->vqs); 11781c7850f9SSasha Levin } 11791c7850f9SSasha Levin } 11801c7850f9SSasha Levin 1181c7838fbdSSasha Levin static void set_config(struct kvm *kvm, void *dev, u8 data, u32 offset) 11821c7850f9SSasha Levin { 1183c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 11841c7850f9SSasha Levin 1185c7838fbdSSasha Levin ((u8 *)(p9dev->config))[offset] = data; 1186c7838fbdSSasha Levin } 11871c7850f9SSasha Levin 1188c7838fbdSSasha Levin static u8 get_config(struct kvm *kvm, void *dev, u32 offset) 1189c7838fbdSSasha Levin { 1190c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1191c7838fbdSSasha Levin 1192c7838fbdSSasha Levin return ((u8 *)(p9dev->config))[offset]; 1193c7838fbdSSasha Levin } 1194c7838fbdSSasha Levin 1195c7838fbdSSasha Levin static u32 get_host_features(struct kvm *kvm, void *dev) 1196c7838fbdSSasha Levin { 1197c7838fbdSSasha Levin return 1 << VIRTIO_9P_MOUNT_TAG; 1198c7838fbdSSasha Levin } 1199c7838fbdSSasha Levin 1200c7838fbdSSasha Levin static void set_guest_features(struct kvm *kvm, void *dev, u32 features) 1201c7838fbdSSasha Levin { 1202c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1203c7838fbdSSasha Levin 1204c7838fbdSSasha Levin p9dev->features = features; 1205c7838fbdSSasha Levin } 1206c7838fbdSSasha Levin 1207c7838fbdSSasha Levin static int init_vq(struct kvm *kvm, void *dev, u32 vq, u32 pfn) 1208c7838fbdSSasha Levin { 1209c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1210b4422bf3SAneesh Kumar K.V struct p9_dev_job *job; 1211b4422bf3SAneesh Kumar K.V struct virt_queue *queue; 1212c7838fbdSSasha Levin void *p; 12131c7850f9SSasha Levin 1214312c62d1SSasha Levin compat__remove_message(compat_id); 1215e59662b3SSasha Levin 1216c7838fbdSSasha Levin queue = &p9dev->vqs[vq]; 1217c7838fbdSSasha Levin queue->pfn = pfn; 12181c7850f9SSasha Levin p = guest_pfn_to_host(kvm, queue->pfn); 1219c7838fbdSSasha Levin job = &p9dev->jobs[vq]; 12201c7850f9SSasha Levin 1221c7838fbdSSasha Levin vring_init(&queue->vring, VIRTQUEUE_NUM, p, VIRTIO_PCI_VRING_ALIGN); 12221c7850f9SSasha Levin 1223b4422bf3SAneesh Kumar K.V *job = (struct p9_dev_job) { 1224b4422bf3SAneesh Kumar K.V .vq = queue, 1225b4422bf3SAneesh Kumar K.V .p9dev = p9dev, 1226b4422bf3SAneesh Kumar K.V }; 1227df0c7f57SSasha Levin thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job); 122860eb42d5SSasha Levin 1229c7838fbdSSasha Levin return 0; 12301c7850f9SSasha Levin } 12311c7850f9SSasha Levin 1232c7838fbdSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq) 1233c7838fbdSSasha Levin { 1234c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 12351c7850f9SSasha Levin 1236c7838fbdSSasha Levin thread_pool__do_job(&p9dev->jobs[vq].job_id); 1237c7838fbdSSasha Levin 1238c7838fbdSSasha Levin return 0; 1239c7838fbdSSasha Levin } 1240c7838fbdSSasha Levin 1241c7838fbdSSasha Levin static int get_pfn_vq(struct kvm *kvm, void *dev, u32 vq) 1242c7838fbdSSasha Levin { 1243c7838fbdSSasha Levin struct p9_dev *p9dev = dev; 1244c7838fbdSSasha Levin 1245c7838fbdSSasha Levin return p9dev->vqs[vq].pfn; 1246c7838fbdSSasha Levin } 1247c7838fbdSSasha Levin 1248c7838fbdSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq) 1249c7838fbdSSasha Levin { 1250c7838fbdSSasha Levin return VIRTQUEUE_NUM; 1251c7838fbdSSasha Levin } 1252c7838fbdSSasha Levin 12531c47ce69SSasha Levin struct virtio_ops p9_dev_virtio_ops = (struct virtio_ops) { 1254c7838fbdSSasha Levin .set_config = set_config, 1255c7838fbdSSasha Levin .get_config = get_config, 1256c7838fbdSSasha Levin .get_host_features = get_host_features, 1257c7838fbdSSasha Levin .set_guest_features = set_guest_features, 1258c7838fbdSSasha Levin .init_vq = init_vq, 1259c7838fbdSSasha Levin .notify_vq = notify_vq, 1260c7838fbdSSasha Levin .get_pfn_vq = get_pfn_vq, 1261c7838fbdSSasha Levin .get_size_vq = get_size_vq, 1262c7838fbdSSasha Levin }; 12631c47ce69SSasha Levin 12641c47ce69SSasha Levin int virtio_9p__init(struct kvm *kvm) 12651c47ce69SSasha Levin { 12661c47ce69SSasha Levin struct p9_dev *p9dev; 12671c47ce69SSasha Levin 12681c47ce69SSasha Levin list_for_each_entry(p9dev, &devs, list) { 126902eca50cSAsias He virtio_init(kvm, p9dev, &p9dev->vdev, &p9_dev_virtio_ops, 12705529bcd7SAsias He VIRTIO_PCI, PCI_DEVICE_ID_VIRTIO_9P, VIRTIO_ID_9P, PCI_CLASS_9P); 1271c7838fbdSSasha Levin } 1272c7838fbdSSasha Levin 1273c7838fbdSSasha Levin return 0; 1274c7838fbdSSasha Levin } 1275c7838fbdSSasha Levin 1276c7838fbdSSasha Levin int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name) 1277c7838fbdSSasha Levin { 1278c7838fbdSSasha Levin struct p9_dev *p9dev; 127954f6802dSPekka Enberg u32 i, root_len; 128054f6802dSPekka Enberg int err = 0; 12811c7850f9SSasha Levin 1282b4422bf3SAneesh Kumar K.V p9dev = calloc(1, sizeof(*p9dev)); 1283b4422bf3SAneesh Kumar K.V if (!p9dev) 128454f6802dSPekka Enberg return -ENOMEM; 128554f6802dSPekka Enberg 1286b4422bf3SAneesh Kumar K.V if (!tag_name) 12875529bcd7SAsias He tag_name = VIRTIO_9P_DEFAULT_TAG; 128854f6802dSPekka Enberg 1289b4422bf3SAneesh Kumar K.V p9dev->config = calloc(1, sizeof(*p9dev->config) + strlen(tag_name) + 1); 129054f6802dSPekka Enberg if (p9dev->config == NULL) { 129154f6802dSPekka Enberg err = -ENOMEM; 1292b4422bf3SAneesh Kumar K.V goto free_p9dev; 129354f6802dSPekka Enberg } 12941c7850f9SSasha Levin 1295b4422bf3SAneesh Kumar K.V strcpy(p9dev->root_dir, root); 12961c7850f9SSasha Levin root_len = strlen(root); 12971c7850f9SSasha Levin /* 12981c7850f9SSasha Levin * We prefix the full path in all fids, This allows us to get the 12991c7850f9SSasha Levin * absolute path of an fid without playing with strings. 13001c7850f9SSasha Levin */ 13015529bcd7SAsias He for (i = 0; i < VIRTIO_9P_MAX_FID; i++) { 130231a6fb8dSSasha Levin strcpy(get_fid(p9dev, i)->abs_path, root); 130331a6fb8dSSasha Levin get_fid(p9dev, i)->path = get_fid(p9dev, i)->abs_path + root_len; 13041c7850f9SSasha Levin } 1305b4422bf3SAneesh Kumar K.V p9dev->config->tag_len = strlen(tag_name); 130654f6802dSPekka Enberg if (p9dev->config->tag_len > MAX_TAG_LEN) { 130754f6802dSPekka Enberg err = -EINVAL; 1308b4422bf3SAneesh Kumar K.V goto free_p9dev_config; 130954f6802dSPekka Enberg } 13101c7850f9SSasha Levin 1311c7838fbdSSasha Levin memcpy(&p9dev->config->tag, tag_name, strlen(tag_name)); 13121c7850f9SSasha Levin 1313c7838fbdSSasha Levin list_add(&p9dev->list, &devs); 1314b4422bf3SAneesh Kumar K.V 1315312c62d1SSasha Levin if (compat_id != -1) 1316312c62d1SSasha Levin compat_id = compat__add_message("virtio-9p device was not detected", 1317e59662b3SSasha Levin "While you have requested a virtio-9p device, " 1318fc835ab3SSasha Levin "the guest kernel did not initialize it.\n" 1319fc835ab3SSasha Levin "Please make sure that the guest kernel was " 1320fc835ab3SSasha Levin "compiled with CONFIG_NET_9P_VIRTIO=y enabled " 1321fc835ab3SSasha Levin "in its .config"); 1322e59662b3SSasha Levin 132354f6802dSPekka Enberg return err; 132454f6802dSPekka Enberg 1325b4422bf3SAneesh Kumar K.V free_p9dev_config: 1326b4422bf3SAneesh Kumar K.V free(p9dev->config); 1327b4422bf3SAneesh Kumar K.V free_p9dev: 1328b4422bf3SAneesh Kumar K.V free(p9dev); 132954f6802dSPekka Enberg return err; 13301c7850f9SSasha Levin } 1331