11c7850f9SSasha Levin #include "kvm/virtio-pci-dev.h"
21c7850f9SSasha Levin #include "kvm/ioport.h"
31c7850f9SSasha Levin #include "kvm/util.h"
41c7850f9SSasha Levin #include "kvm/threadpool.h"
5bfc15268SAneesh Kumar K.V #include "kvm/irq.h"
6bfc15268SAneesh Kumar K.V #include "kvm/virtio-9p.h"
7e59662b3SSasha Levin #include "kvm/guest_compat.h"
8cac9e8fdSSasha Levin #include "kvm/builtin-setup.h"
91c7850f9SSasha Levin
10bfc15268SAneesh Kumar K.V #include <stdio.h>
11bfc15268SAneesh Kumar K.V #include <stdlib.h>
121c7850f9SSasha Levin #include <fcntl.h>
131c7850f9SSasha Levin #include <sys/stat.h>
14c0a98553SJeremy Linton #include <sys/sysmacros.h>
15bfc15268SAneesh Kumar K.V #include <unistd.h>
16bfc15268SAneesh Kumar K.V #include <string.h>
17bfc15268SAneesh Kumar K.V #include <errno.h>
18c797b6c6SAneesh Kumar K.V #include <sys/vfs.h>
191c7850f9SSasha Levin
202daa28d4SAneesh Kumar K.V #include <linux/virtio_ring.h>
212daa28d4SAneesh Kumar K.V #include <linux/virtio_9p.h>
22c6cb7c75SAndre Przywara #include <linux/9p.h>
232daa28d4SAneesh Kumar K.V
24c7838fbdSSasha Levin static LIST_HEAD(devs);
25312c62d1SSasha Levin static int compat_id = -1;
26c7838fbdSSasha Levin
27e2341580SSasha Levin static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid);
find_or_create_fid(struct p9_dev * dev,u32 fid)28e2341580SSasha Levin static struct p9_fid *find_or_create_fid(struct p9_dev *dev, u32 fid)
29e2341580SSasha Levin {
30e2341580SSasha Levin struct rb_node *node = dev->fids.rb_node;
31e2341580SSasha Levin struct p9_fid *pfid = NULL;
32e277a1b4SG. Campana size_t len;
33e2341580SSasha Levin
34e2341580SSasha Levin while (node) {
35e2341580SSasha Levin struct p9_fid *cur = rb_entry(node, struct p9_fid, node);
36e2341580SSasha Levin
37e2341580SSasha Levin if (fid < cur->fid) {
38e2341580SSasha Levin node = node->rb_left;
39e2341580SSasha Levin } else if (fid > cur->fid) {
40e2341580SSasha Levin node = node->rb_right;
41e2341580SSasha Levin } else {
42e2341580SSasha Levin return cur;
43e2341580SSasha Levin }
44e2341580SSasha Levin }
45e2341580SSasha Levin
46e2341580SSasha Levin pfid = calloc(sizeof(*pfid), 1);
47e2341580SSasha Levin if (!pfid)
48e2341580SSasha Levin return NULL;
49e2341580SSasha Levin
50e277a1b4SG. Campana len = strlen(dev->root_dir);
51e277a1b4SG. Campana if (len >= sizeof(pfid->abs_path)) {
52e277a1b4SG. Campana free(pfid);
53e277a1b4SG. Campana return NULL;
54e277a1b4SG. Campana }
55e277a1b4SG. Campana
56e2341580SSasha Levin pfid->fid = fid;
57e2341580SSasha Levin strcpy(pfid->abs_path, dev->root_dir);
58e277a1b4SG. Campana pfid->path = pfid->abs_path + strlen(pfid->abs_path);
59e2341580SSasha Levin
60e2341580SSasha Levin insert_new_fid(dev, pfid);
61e2341580SSasha Levin
62e2341580SSasha Levin return pfid;
63e2341580SSasha Levin }
64e2341580SSasha Levin
insert_new_fid(struct p9_dev * dev,struct p9_fid * fid)65e2341580SSasha Levin static int insert_new_fid(struct p9_dev *dev, struct p9_fid *fid)
66e2341580SSasha Levin {
67e2341580SSasha Levin struct rb_node **node = &(dev->fids.rb_node), *parent = NULL;
68e2341580SSasha Levin
69e2341580SSasha Levin while (*node) {
70e2341580SSasha Levin int result = fid->fid - rb_entry(*node, struct p9_fid, node)->fid;
71e2341580SSasha Levin
72e2341580SSasha Levin parent = *node;
73e2341580SSasha Levin if (result < 0)
74e2341580SSasha Levin node = &((*node)->rb_left);
75e2341580SSasha Levin else if (result > 0)
76e2341580SSasha Levin node = &((*node)->rb_right);
77e2341580SSasha Levin else
78e2341580SSasha Levin return -EEXIST;
79e2341580SSasha Levin }
80e2341580SSasha Levin
81e2341580SSasha Levin rb_link_node(&fid->node, parent, node);
82e2341580SSasha Levin rb_insert_color(&fid->node, &dev->fids);
83e2341580SSasha Levin return 0;
84e2341580SSasha Levin }
85e2341580SSasha Levin
get_fid(struct p9_dev * p9dev,int fid)8631a6fb8dSSasha Levin static struct p9_fid *get_fid(struct p9_dev *p9dev, int fid)
8731a6fb8dSSasha Levin {
88e2341580SSasha Levin struct p9_fid *new;
8931a6fb8dSSasha Levin
90e2341580SSasha Levin new = find_or_create_fid(p9dev, fid);
91e2341580SSasha Levin
92e2341580SSasha Levin return new;
9331a6fb8dSSasha Levin }
9431a6fb8dSSasha Levin
stat2qid(struct stat * st,struct p9_qid * qid)95c797b6c6SAneesh Kumar K.V static void stat2qid(struct stat *st, struct p9_qid *qid)
961c7850f9SSasha Levin {
971c7850f9SSasha Levin *qid = (struct p9_qid) {
981c7850f9SSasha Levin .path = st->st_ino,
991c7850f9SSasha Levin .version = st->st_mtime,
1001c7850f9SSasha Levin };
1011c7850f9SSasha Levin
1021c7850f9SSasha Levin if (S_ISDIR(st->st_mode))
1031c7850f9SSasha Levin qid->type |= P9_QTDIR;
1041c7850f9SSasha Levin }
1051c7850f9SSasha Levin
close_fid(struct p9_dev * p9dev,u32 fid)106b4422bf3SAneesh Kumar K.V static void close_fid(struct p9_dev *p9dev, u32 fid)
1071c7850f9SSasha Levin {
108e2341580SSasha Levin struct p9_fid *pfid = get_fid(p9dev, fid);
109e2341580SSasha Levin
110e2341580SSasha Levin if (pfid->fd > 0)
111e2341580SSasha Levin close(pfid->fd);
112e2341580SSasha Levin
113e2341580SSasha Levin if (pfid->dir)
114e2341580SSasha Levin closedir(pfid->dir);
115e2341580SSasha Levin
116e2341580SSasha Levin rb_erase(&pfid->node, &p9dev->fids);
117e2341580SSasha Levin free(pfid);
1181c7850f9SSasha Levin }
119e2341580SSasha Levin
virtio_p9_set_reply_header(struct p9_pdu * pdu,u32 size)120bfc15268SAneesh Kumar K.V static void virtio_p9_set_reply_header(struct p9_pdu *pdu, u32 size)
1211c7850f9SSasha Levin {
122bfc15268SAneesh Kumar K.V u8 cmd;
123bfc15268SAneesh Kumar K.V u16 tag;
124bfc15268SAneesh Kumar K.V
125bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32);
126bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "bw", &cmd, &tag);
127bfc15268SAneesh Kumar K.V pdu->write_offset = 0;
128bfc15268SAneesh Kumar K.V /* cmd + 1 is the reply message */
129bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", size, cmd + 1, tag);
1301c7850f9SSasha Levin }
1311c7850f9SSasha Levin
virtio_p9_update_iov_cnt(struct iovec iov[],u32 count,int iov_cnt)1326b163a87SAneesh Kumar K.V static u16 virtio_p9_update_iov_cnt(struct iovec iov[], u32 count, int iov_cnt)
1336b163a87SAneesh Kumar K.V {
1346b163a87SAneesh Kumar K.V int i;
1356b163a87SAneesh Kumar K.V u32 total = 0;
1366b163a87SAneesh Kumar K.V for (i = 0; (i < iov_cnt) && (total < count); i++) {
1376b163a87SAneesh Kumar K.V if (total + iov[i].iov_len > count) {
1386b163a87SAneesh Kumar K.V /* we don't need this iov fully */
1396b163a87SAneesh Kumar K.V iov[i].iov_len -= ((total + iov[i].iov_len) - count);
1406b163a87SAneesh Kumar K.V i++;
1416b163a87SAneesh Kumar K.V break;
1426b163a87SAneesh Kumar K.V }
1436b163a87SAneesh Kumar K.V total += iov[i].iov_len;
1446b163a87SAneesh Kumar K.V }
1456b163a87SAneesh Kumar K.V return i;
1466b163a87SAneesh Kumar K.V }
1476b163a87SAneesh Kumar K.V
virtio_p9_error_reply(struct p9_dev * p9dev,struct p9_pdu * pdu,int err,u32 * outlen)148eee1ba8eSAneesh Kumar K.V static void virtio_p9_error_reply(struct p9_dev *p9dev,
149eee1ba8eSAneesh Kumar K.V struct p9_pdu *pdu, int err, u32 *outlen)
150eee1ba8eSAneesh Kumar K.V {
151bfc15268SAneesh Kumar K.V u16 tag;
152eee1ba8eSAneesh Kumar K.V
1539c2e1d1aSSuzuki K. Poulose /* EMFILE at server implies ENFILE for the VM */
1549c2e1d1aSSuzuki K. Poulose if (err == EMFILE)
1559c2e1d1aSSuzuki K. Poulose err = ENFILE;
1569c2e1d1aSSuzuki K. Poulose
1575529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN;
158c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", err);
159bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset;
160eee1ba8eSAneesh Kumar K.V
161c797b6c6SAneesh Kumar K.V /* read the tag from input */
162bfc15268SAneesh Kumar K.V pdu->read_offset = sizeof(u32) + sizeof(u8);
163bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "w", &tag);
164bfc15268SAneesh Kumar K.V
165c797b6c6SAneesh Kumar K.V /* Update the header */
166bfc15268SAneesh Kumar K.V pdu->write_offset = 0;
167c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "dbw", *outlen, P9_RLERROR, tag);
168eee1ba8eSAneesh Kumar K.V }
169eee1ba8eSAneesh Kumar K.V
virtio_p9_version(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)170ead43b01SAneesh Kumar K.V static void virtio_p9_version(struct p9_dev *p9dev,
171af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
1721c7850f9SSasha Levin {
173c797b6c6SAneesh Kumar K.V u32 msize;
174c797b6c6SAneesh Kumar K.V char *version;
175c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ds", &msize, &version);
176c797b6c6SAneesh Kumar K.V /*
177c797b6c6SAneesh Kumar K.V * reply with the same msize the client sent us
178c797b6c6SAneesh Kumar K.V * Error out if the request is not for 9P2000.L
179c797b6c6SAneesh Kumar K.V */
1805529bcd7SAsias He if (!strcmp(version, VIRTIO_9P_VERSION_DOTL))
181c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, version);
182c797b6c6SAneesh Kumar K.V else
183c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ds", msize, "unknown");
1841c7850f9SSasha Levin
185bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset;
186bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
187c797b6c6SAneesh Kumar K.V free(version);
188ead43b01SAneesh Kumar K.V return;
1891c7850f9SSasha Levin }
1901c7850f9SSasha Levin
virtio_p9_clunk(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)191ead43b01SAneesh Kumar K.V static void virtio_p9_clunk(struct p9_dev *p9dev,
192af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
1931c7850f9SSasha Levin {
194bfc15268SAneesh Kumar K.V u32 fid;
1951c7850f9SSasha Levin
196bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid);
197bfc15268SAneesh Kumar K.V close_fid(p9dev, fid);
1981c7850f9SSasha Levin
199bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset;
200bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
201ead43b01SAneesh Kumar K.V return;
2021c7850f9SSasha Levin }
2031c7850f9SSasha Levin
204c797b6c6SAneesh Kumar K.V /*
205c797b6c6SAneesh Kumar K.V * FIXME!! Need to map to protocol independent value. Upstream
206c797b6c6SAneesh Kumar K.V * 9p also have the same BUG
207c797b6c6SAneesh Kumar K.V */
virtio_p9_openflags(int flags)208c797b6c6SAneesh Kumar K.V static int virtio_p9_openflags(int flags)
209c797b6c6SAneesh Kumar K.V {
210c797b6c6SAneesh Kumar K.V flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT | O_DIRECT);
211c797b6c6SAneesh Kumar K.V flags |= O_NOFOLLOW;
212c797b6c6SAneesh Kumar K.V return flags;
213c797b6c6SAneesh Kumar K.V }
214c797b6c6SAneesh Kumar K.V
is_dir(struct p9_fid * fid)21532585666SSasha Levin static bool is_dir(struct p9_fid *fid)
21632585666SSasha Levin {
21732585666SSasha Levin struct stat st;
21832585666SSasha Levin
21932585666SSasha Levin stat(fid->abs_path, &st);
22032585666SSasha Levin
22132585666SSasha Levin return S_ISDIR(st.st_mode);
22232585666SSasha Levin }
22332585666SSasha Levin
is_reg(struct p9_fid * fid)224*4d2c017fSYanwu Shen static bool is_reg(struct p9_fid *fid)
225*4d2c017fSYanwu Shen {
226*4d2c017fSYanwu Shen struct stat st;
227*4d2c017fSYanwu Shen
228*4d2c017fSYanwu Shen stat(fid->abs_path, &st);
229*4d2c017fSYanwu Shen
230*4d2c017fSYanwu Shen return S_ISREG(st.st_mode);
231*4d2c017fSYanwu Shen }
232*4d2c017fSYanwu Shen
2339bb99a82SG. Campana /* path is always absolute */
path_is_illegal(const char * path)2349bb99a82SG. Campana static bool path_is_illegal(const char *path)
2359bb99a82SG. Campana {
2369bb99a82SG. Campana size_t len;
2379bb99a82SG. Campana
2389bb99a82SG. Campana if (strstr(path, "/../") != NULL)
2399bb99a82SG. Campana return true;
2409bb99a82SG. Campana
2419bb99a82SG. Campana len = strlen(path);
2429bb99a82SG. Campana if (len >= 3 && strcmp(path + len - 3, "/..") == 0)
2439bb99a82SG. Campana return true;
2449bb99a82SG. Campana
2459bb99a82SG. Campana return false;
2469bb99a82SG. Campana }
2479bb99a82SG. Campana
get_full_path_helper(char * full_path,size_t size,const char * dirname,const char * name)248d4727f2bSG. Campana static int get_full_path_helper(char *full_path, size_t size,
249d4727f2bSG. Campana const char *dirname, const char *name)
250d4727f2bSG. Campana {
251d4727f2bSG. Campana int ret;
252d4727f2bSG. Campana
253d4727f2bSG. Campana ret = snprintf(full_path, size, "%s/%s", dirname, name);
254716b2944SG. Campana if (ret >= (int)size) {
255d4727f2bSG. Campana errno = ENAMETOOLONG;
256d4727f2bSG. Campana return -1;
257d4727f2bSG. Campana }
258d4727f2bSG. Campana
259d4727f2bSG. Campana if (path_is_illegal(full_path)) {
260d4727f2bSG. Campana errno = EACCES;
261d4727f2bSG. Campana return -1;
262d4727f2bSG. Campana }
263d4727f2bSG. Campana
264d4727f2bSG. Campana return 0;
265d4727f2bSG. Campana }
266d4727f2bSG. Campana
get_full_path(char * full_path,size_t size,struct p9_fid * fid,const char * name)267d4727f2bSG. Campana static int get_full_path(char *full_path, size_t size, struct p9_fid *fid,
268d4727f2bSG. Campana const char *name)
269d4727f2bSG. Campana {
270d4727f2bSG. Campana return get_full_path_helper(full_path, size, fid->abs_path, name);
271d4727f2bSG. Campana }
272d4727f2bSG. Campana
stat_rel(struct p9_dev * p9dev,const char * path,struct stat * st)273b0922422SG. Campana static int stat_rel(struct p9_dev *p9dev, const char *path, struct stat *st)
274b0922422SG. Campana {
275b0922422SG. Campana char full_path[PATH_MAX];
276b0922422SG. Campana
277b0922422SG. Campana if (get_full_path_helper(full_path, sizeof(full_path), p9dev->root_dir, path) != 0)
278b0922422SG. Campana return -1;
279b0922422SG. Campana
280b0922422SG. Campana if (lstat(full_path, st) != 0)
281b0922422SG. Campana return -1;
282b0922422SG. Campana
283b0922422SG. Campana return 0;
284b0922422SG. Campana }
285b0922422SG. Campana
virtio_p9_open(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)286ead43b01SAneesh Kumar K.V static void virtio_p9_open(struct p9_dev *p9dev,
287af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
2881c7850f9SSasha Levin {
289c797b6c6SAneesh Kumar K.V u32 fid, flags;
2901c7850f9SSasha Levin struct stat st;
291bfc15268SAneesh Kumar K.V struct p9_qid qid;
292bfc15268SAneesh Kumar K.V struct p9_fid *new_fid;
293bfc15268SAneesh Kumar K.V
294c797b6c6SAneesh Kumar K.V
295c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid, &flags);
29631a6fb8dSSasha Levin new_fid = get_fid(p9dev, fid);
2971c7850f9SSasha Levin
29830204a77SAneesh Kumar K.V if (lstat(new_fid->abs_path, &st) < 0)
299eee1ba8eSAneesh Kumar K.V goto err_out;
3001c7850f9SSasha Levin
301c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid);
3021c7850f9SSasha Levin
30332585666SSasha Levin if (is_dir(new_fid)) {
3041c7850f9SSasha Levin new_fid->dir = opendir(new_fid->abs_path);
305eee1ba8eSAneesh Kumar K.V if (!new_fid->dir)
306eee1ba8eSAneesh Kumar K.V goto err_out;
307*4d2c017fSYanwu Shen } else if (is_reg(new_fid)) {
308eee1ba8eSAneesh Kumar K.V new_fid->fd = open(new_fid->abs_path,
309c797b6c6SAneesh Kumar K.V virtio_p9_openflags(flags));
310eee1ba8eSAneesh Kumar K.V if (new_fid->fd < 0)
311eee1ba8eSAneesh Kumar K.V goto err_out;
312*4d2c017fSYanwu Shen } else {
313*4d2c017fSYanwu Shen goto err_out;
314eee1ba8eSAneesh Kumar K.V }
315c797b6c6SAneesh Kumar K.V /* FIXME!! need ot send proper iounit */
316bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
317bfc15268SAneesh Kumar K.V
318bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset;
319bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
320ead43b01SAneesh Kumar K.V return;
321eee1ba8eSAneesh Kumar K.V err_out:
322eee1ba8eSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
323ead43b01SAneesh Kumar K.V return;
3241c7850f9SSasha Levin }
3251c7850f9SSasha Levin
virtio_p9_create(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)326ead43b01SAneesh Kumar K.V static void virtio_p9_create(struct p9_dev *p9dev,
327af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
3281c7850f9SSasha Levin {
329c797b6c6SAneesh Kumar K.V int fd, ret;
330bfc15268SAneesh Kumar K.V char *name;
33132832dd1SG. Campana size_t size;
332af045e53SAneesh Kumar K.V struct stat st;
333bfc15268SAneesh Kumar K.V struct p9_qid qid;
334c797b6c6SAneesh Kumar K.V struct p9_fid *dfid;
3354bc9734aSAneesh Kumar K.V char full_path[PATH_MAX];
33604d604b6SAnisse Astier char *tmp_path;
337c797b6c6SAneesh Kumar K.V u32 dfid_val, flags, mode, gid;
338af045e53SAneesh Kumar K.V
339c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsddd", &dfid_val,
340c797b6c6SAneesh Kumar K.V &name, &flags, &mode, &gid);
34131a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val);
3421c7850f9SSasha Levin
343d4727f2bSG. Campana if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0)
34432832dd1SG. Campana goto err_out;
3459bb99a82SG. Campana
34632832dd1SG. Campana size = sizeof(dfid->abs_path) - (dfid->path - dfid->abs_path);
34704d604b6SAnisse Astier
34804d604b6SAnisse Astier tmp_path = strdup(dfid->path);
34904d604b6SAnisse Astier if (!tmp_path)
35004d604b6SAnisse Astier goto err_out;
35104d604b6SAnisse Astier
35204d604b6SAnisse Astier ret = snprintf(dfid->path, size, "%s/%s", tmp_path, name);
35304d604b6SAnisse Astier free(tmp_path);
35432832dd1SG. Campana if (ret >= (int)size) {
35532832dd1SG. Campana errno = ENAMETOOLONG;
35632832dd1SG. Campana if (size > 0)
35732832dd1SG. Campana dfid->path[size] = '\x00';
35832832dd1SG. Campana goto err_out;
35932832dd1SG. Campana }
36032832dd1SG. Campana
361d4727f2bSG. Campana flags = virtio_p9_openflags(flags);
362d4727f2bSG. Campana
363c797b6c6SAneesh Kumar K.V fd = open(full_path, flags | O_CREAT, mode);
3644bc9734aSAneesh Kumar K.V if (fd < 0)
3654bc9734aSAneesh Kumar K.V goto err_out;
366c797b6c6SAneesh Kumar K.V dfid->fd = fd;
367c797b6c6SAneesh Kumar K.V
3684bc9734aSAneesh Kumar K.V if (lstat(full_path, &st) < 0)
3696c8ca053SAneesh Kumar K.V goto err_out;
3701c7850f9SSasha Levin
371c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777);
372c797b6c6SAneesh Kumar K.V if (ret < 0)
373c797b6c6SAneesh Kumar K.V goto err_out;
374c797b6c6SAneesh Kumar K.V
375c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid);
376bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
377bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset;
378bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
3795f900f6dSSasha Levin free(name);
3806c8ca053SAneesh Kumar K.V return;
3816c8ca053SAneesh Kumar K.V err_out:
3825f900f6dSSasha Levin free(name);
383c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
384c797b6c6SAneesh Kumar K.V return;
385c797b6c6SAneesh Kumar K.V }
386c797b6c6SAneesh Kumar K.V
virtio_p9_mkdir(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)387c797b6c6SAneesh Kumar K.V static void virtio_p9_mkdir(struct p9_dev *p9dev,
388c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
389c797b6c6SAneesh Kumar K.V {
390c797b6c6SAneesh Kumar K.V int ret;
391c797b6c6SAneesh Kumar K.V char *name;
392c797b6c6SAneesh Kumar K.V struct stat st;
393c797b6c6SAneesh Kumar K.V struct p9_qid qid;
394c797b6c6SAneesh Kumar K.V struct p9_fid *dfid;
395c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX];
396c797b6c6SAneesh Kumar K.V u32 dfid_val, mode, gid;
397c797b6c6SAneesh Kumar K.V
398c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdd", &dfid_val,
399c797b6c6SAneesh Kumar K.V &name, &mode, &gid);
40031a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val);
401c797b6c6SAneesh Kumar K.V
402d4727f2bSG. Campana if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0)
40332832dd1SG. Campana goto err_out;
4049bb99a82SG. Campana
405c797b6c6SAneesh Kumar K.V ret = mkdir(full_path, mode);
406c797b6c6SAneesh Kumar K.V if (ret < 0)
407c797b6c6SAneesh Kumar K.V goto err_out;
408c797b6c6SAneesh Kumar K.V
409c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0)
410c797b6c6SAneesh Kumar K.V goto err_out;
411c797b6c6SAneesh Kumar K.V
412c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777);
413c797b6c6SAneesh Kumar K.V if (ret < 0)
414c797b6c6SAneesh Kumar K.V goto err_out;
415c797b6c6SAneesh Kumar K.V
416c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid);
417c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qd", &qid, 0);
418c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset;
419c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
420c797b6c6SAneesh Kumar K.V free(name);
421c797b6c6SAneesh Kumar K.V return;
422c797b6c6SAneesh Kumar K.V err_out:
423c797b6c6SAneesh Kumar K.V free(name);
424c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
425ead43b01SAneesh Kumar K.V return;
4261c7850f9SSasha Levin }
4271c7850f9SSasha Levin
join_path(struct p9_fid * fid,const char * name)428e277a1b4SG. Campana static int join_path(struct p9_fid *fid, const char *name)
429e277a1b4SG. Campana {
430e277a1b4SG. Campana size_t len, size;
431e277a1b4SG. Campana
432e277a1b4SG. Campana size = sizeof(fid->abs_path) - (fid->path - fid->abs_path);
433e277a1b4SG. Campana len = strlen(name);
434e277a1b4SG. Campana if (len >= size)
435e277a1b4SG. Campana return -1;
436e277a1b4SG. Campana
437e277a1b4SG. Campana strncpy(fid->path, name, size);
438e277a1b4SG. Campana return 0;
439e277a1b4SG. Campana }
440e277a1b4SG. Campana
virtio_p9_walk(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)441ead43b01SAneesh Kumar K.V static void virtio_p9_walk(struct p9_dev *p9dev,
442af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
4431c7850f9SSasha Levin {
444af045e53SAneesh Kumar K.V u8 i;
445bfc15268SAneesh Kumar K.V u16 nwqid;
446bfc15268SAneesh Kumar K.V u16 nwname;
447bfc15268SAneesh Kumar K.V struct p9_qid wqid;
448e2341580SSasha Levin struct p9_fid *new_fid, *old_fid;
449c797b6c6SAneesh Kumar K.V u32 fid_val, newfid_val;
450c797b6c6SAneesh Kumar K.V
4511c7850f9SSasha Levin
452bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddw", &fid_val, &newfid_val, &nwname);
45331a6fb8dSSasha Levin new_fid = get_fid(p9dev, newfid_val);
4541c7850f9SSasha Levin
455bfc15268SAneesh Kumar K.V nwqid = 0;
456bfc15268SAneesh Kumar K.V if (nwname) {
45731a6fb8dSSasha Levin struct p9_fid *fid = get_fid(p9dev, fid_val);
458bfc15268SAneesh Kumar K.V
459e277a1b4SG. Campana if (join_path(new_fid, fid->path) != 0) {
460e277a1b4SG. Campana errno = ENAMETOOLONG;
461e277a1b4SG. Campana goto err_out;
462e277a1b4SG. Campana }
463e277a1b4SG. Campana
464bfc15268SAneesh Kumar K.V /* skip the space for count */
465bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16);
466bfc15268SAneesh Kumar K.V for (i = 0; i < nwname; i++) {
467bfc15268SAneesh Kumar K.V struct stat st;
4681c7850f9SSasha Levin char tmp[PATH_MAX] = {0};
469e55ed135SPekka Enberg char *str;
47032832dd1SG. Campana int ret;
471bfc15268SAneesh Kumar K.V
472bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "s", &str);
4731c7850f9SSasha Levin
4741c7850f9SSasha Levin /* Format the new path we're 'walk'ing into */
47532832dd1SG. Campana ret = snprintf(tmp, sizeof(tmp), "%s/%s", new_fid->path, str);
47632832dd1SG. Campana if (ret >= (int)sizeof(tmp)) {
47732832dd1SG. Campana errno = ENAMETOOLONG;
47832832dd1SG. Campana goto err_out;
47932832dd1SG. Campana }
480e55ed135SPekka Enberg
481e55ed135SPekka Enberg free(str);
482e55ed135SPekka Enberg
483b0922422SG. Campana if (stat_rel(p9dev, tmp, &st) != 0)
4846c8ca053SAneesh Kumar K.V goto err_out;
4851c7850f9SSasha Levin
486c797b6c6SAneesh Kumar K.V stat2qid(&st, &wqid);
487e277a1b4SG. Campana if (join_path(new_fid, tmp) != 0) {
488e277a1b4SG. Campana errno = ENAMETOOLONG;
489e277a1b4SG. Campana goto err_out;
490e277a1b4SG. Campana }
491c797b6c6SAneesh Kumar K.V new_fid->uid = fid->uid;
492bfc15268SAneesh Kumar K.V nwqid++;
493bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &wqid);
4941c7850f9SSasha Levin }
4951c7850f9SSasha Levin } else {
496bfc15268SAneesh Kumar K.V /*
497bfc15268SAneesh Kumar K.V * update write_offset so our outlen get correct value
498bfc15268SAneesh Kumar K.V */
499bfc15268SAneesh Kumar K.V pdu->write_offset += sizeof(u16);
500e2341580SSasha Levin old_fid = get_fid(p9dev, fid_val);
501e277a1b4SG. Campana if (join_path(new_fid, old_fid->path) != 0) {
502e277a1b4SG. Campana errno = ENAMETOOLONG;
503e277a1b4SG. Campana goto err_out;
504e277a1b4SG. Campana }
505e2341580SSasha Levin new_fid->uid = old_fid->uid;
5061c7850f9SSasha Levin }
507bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset;
5085529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN;
509bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", nwqid);
510bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
5116c8ca053SAneesh Kumar K.V return;
5126c8ca053SAneesh Kumar K.V err_out:
5136c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
514ead43b01SAneesh Kumar K.V return;
5151c7850f9SSasha Levin }
5161c7850f9SSasha Levin
virtio_p9_attach(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)517ead43b01SAneesh Kumar K.V static void virtio_p9_attach(struct p9_dev *p9dev,
518af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
5191c7850f9SSasha Levin {
520bfc15268SAneesh Kumar K.V char *uname;
521bfc15268SAneesh Kumar K.V char *aname;
5221c7850f9SSasha Levin struct stat st;
523bfc15268SAneesh Kumar K.V struct p9_qid qid;
5241c7850f9SSasha Levin struct p9_fid *fid;
525c797b6c6SAneesh Kumar K.V u32 fid_val, afid, uid;
526bfc15268SAneesh Kumar K.V
527c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "ddssd", &fid_val, &afid,
528c797b6c6SAneesh Kumar K.V &uname, &aname, &uid);
5291c7850f9SSasha Levin
53039257180SPekka Enberg free(uname);
53139257180SPekka Enberg free(aname);
53239257180SPekka Enberg
53330204a77SAneesh Kumar K.V if (lstat(p9dev->root_dir, &st) < 0)
5346c8ca053SAneesh Kumar K.V goto err_out;
5351c7850f9SSasha Levin
536c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid);
5371c7850f9SSasha Levin
53831a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val);
539c797b6c6SAneesh Kumar K.V fid->uid = uid;
540e277a1b4SG. Campana if (join_path(fid, "/") != 0) {
541e277a1b4SG. Campana errno = ENAMETOOLONG;
542e277a1b4SG. Campana goto err_out;
543e277a1b4SG. Campana }
5441c7850f9SSasha Levin
545bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid);
546bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset;
547bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
5486c8ca053SAneesh Kumar K.V return;
5496c8ca053SAneesh Kumar K.V err_out:
5506c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
551ead43b01SAneesh Kumar K.V return;
5521c7850f9SSasha Levin }
5531c7850f9SSasha Levin
virtio_p9_fill_stat(struct p9_dev * p9dev,struct stat * st,struct p9_stat_dotl * statl)554c797b6c6SAneesh Kumar K.V static void virtio_p9_fill_stat(struct p9_dev *p9dev,
555c797b6c6SAneesh Kumar K.V struct stat *st, struct p9_stat_dotl *statl)
5565f900f6dSSasha Levin {
557c797b6c6SAneesh Kumar K.V memset(statl, 0, sizeof(*statl));
558c797b6c6SAneesh Kumar K.V statl->st_mode = st->st_mode;
559c797b6c6SAneesh Kumar K.V statl->st_nlink = st->st_nlink;
560506fd90bSSasha Levin statl->st_uid = KUIDT_INIT(st->st_uid);
561506fd90bSSasha Levin statl->st_gid = KGIDT_INIT(st->st_gid);
562c797b6c6SAneesh Kumar K.V statl->st_rdev = st->st_rdev;
563c797b6c6SAneesh Kumar K.V statl->st_size = st->st_size;
564c797b6c6SAneesh Kumar K.V statl->st_blksize = st->st_blksize;
565c797b6c6SAneesh Kumar K.V statl->st_blocks = st->st_blocks;
566c797b6c6SAneesh Kumar K.V statl->st_atime_sec = st->st_atime;
567c797b6c6SAneesh Kumar K.V statl->st_atime_nsec = st->st_atim.tv_nsec;
568c797b6c6SAneesh Kumar K.V statl->st_mtime_sec = st->st_mtime;
569c797b6c6SAneesh Kumar K.V statl->st_mtime_nsec = st->st_mtim.tv_nsec;
570c797b6c6SAneesh Kumar K.V statl->st_ctime_sec = st->st_ctime;
571c797b6c6SAneesh Kumar K.V statl->st_ctime_nsec = st->st_ctim.tv_nsec;
572c797b6c6SAneesh Kumar K.V /* Currently we only support BASIC fields in stat */
573c797b6c6SAneesh Kumar K.V statl->st_result_mask = P9_STATS_BASIC;
574c797b6c6SAneesh Kumar K.V stat2qid(st, &statl->qid);
5751c7850f9SSasha Levin }
5761c7850f9SSasha Levin
virtio_p9_read(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)577ead43b01SAneesh Kumar K.V static void virtio_p9_read(struct p9_dev *p9dev,
578af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
5791c7850f9SSasha Levin {
580bfc15268SAneesh Kumar K.V u64 offset;
581bfc15268SAneesh Kumar K.V u32 fid_val;
582c797b6c6SAneesh Kumar K.V u16 iov_cnt;
583c797b6c6SAneesh Kumar K.V void *iov_base;
584c797b6c6SAneesh Kumar K.V size_t iov_len;
585bfc15268SAneesh Kumar K.V u32 count, rcount;
586bfc15268SAneesh Kumar K.V struct p9_fid *fid;
587c797b6c6SAneesh Kumar K.V
5881c7850f9SSasha Levin
589bfc15268SAneesh Kumar K.V rcount = 0;
590bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
59131a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val);
59250c479e0SAneesh Kumar K.V
59350c479e0SAneesh Kumar K.V iov_base = pdu->in_iov[0].iov_base;
59450c479e0SAneesh Kumar K.V iov_len = pdu->in_iov[0].iov_len;
59550c479e0SAneesh Kumar K.V iov_cnt = pdu->in_iov_cnt;
5965529bcd7SAsias He pdu->in_iov[0].iov_base += VIRTIO_9P_HDR_LEN + sizeof(u32);
5975529bcd7SAsias He pdu->in_iov[0].iov_len -= VIRTIO_9P_HDR_LEN + sizeof(u32);
5986b163a87SAneesh Kumar K.V pdu->in_iov_cnt = virtio_p9_update_iov_cnt(pdu->in_iov,
599bfc15268SAneesh Kumar K.V count,
6006b163a87SAneesh Kumar K.V pdu->in_iov_cnt);
601bfc15268SAneesh Kumar K.V rcount = preadv(fid->fd, pdu->in_iov,
602bfc15268SAneesh Kumar K.V pdu->in_iov_cnt, offset);
603bfc15268SAneesh Kumar K.V if (rcount > count)
604bfc15268SAneesh Kumar K.V rcount = count;
605bfc15268SAneesh Kumar K.V /*
606bfc15268SAneesh Kumar K.V * Update the iov_base back, so that rest of
607bfc15268SAneesh Kumar K.V * pdu_writef works correctly.
608bfc15268SAneesh Kumar K.V */
60950c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_base = iov_base;
61050c479e0SAneesh Kumar K.V pdu->in_iov[0].iov_len = iov_len;
61150c479e0SAneesh Kumar K.V pdu->in_iov_cnt = iov_cnt;
612c797b6c6SAneesh Kumar K.V
6135529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN;
614bfc15268SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount);
615bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset + rcount;
616bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
617ead43b01SAneesh Kumar K.V return;
6181c7850f9SSasha Levin }
6191c7850f9SSasha Levin
virtio_p9_dentry_size(struct dirent * dent)620c797b6c6SAneesh Kumar K.V static int virtio_p9_dentry_size(struct dirent *dent)
621c797b6c6SAneesh Kumar K.V {
622c797b6c6SAneesh Kumar K.V /*
623c797b6c6SAneesh Kumar K.V * Size of each dirent:
624c797b6c6SAneesh Kumar K.V * qid(13) + offset(8) + type(1) + name_len(2) + name
625c797b6c6SAneesh Kumar K.V */
626c797b6c6SAneesh Kumar K.V return 24 + strlen(dent->d_name);
627c797b6c6SAneesh Kumar K.V }
628c797b6c6SAneesh Kumar K.V
virtio_p9_readdir(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)629c797b6c6SAneesh Kumar K.V static void virtio_p9_readdir(struct p9_dev *p9dev,
630c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
631c797b6c6SAneesh Kumar K.V {
632c797b6c6SAneesh Kumar K.V u32 fid_val;
633c797b6c6SAneesh Kumar K.V u32 count, rcount;
634c797b6c6SAneesh Kumar K.V struct stat st;
635c797b6c6SAneesh Kumar K.V struct p9_fid *fid;
636c797b6c6SAneesh Kumar K.V struct dirent *dent;
637c797b6c6SAneesh Kumar K.V u64 offset, old_offset;
638c797b6c6SAneesh Kumar K.V
639c797b6c6SAneesh Kumar K.V rcount = 0;
640c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
64131a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val);
642c797b6c6SAneesh Kumar K.V
64332585666SSasha Levin if (!is_dir(fid)) {
64469bb4278SSasha Levin errno = EINVAL;
645c797b6c6SAneesh Kumar K.V goto err_out;
646c797b6c6SAneesh Kumar K.V }
647c797b6c6SAneesh Kumar K.V
648c797b6c6SAneesh Kumar K.V /* Move the offset specified */
649c797b6c6SAneesh Kumar K.V seekdir(fid->dir, offset);
650c797b6c6SAneesh Kumar K.V
651c797b6c6SAneesh Kumar K.V old_offset = offset;
652c797b6c6SAneesh Kumar K.V /* If reading a dir, fill the buffer with p9_stat entries */
653c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir);
654c797b6c6SAneesh Kumar K.V
655c797b6c6SAneesh Kumar K.V /* Skip the space for writing count */
656c797b6c6SAneesh Kumar K.V pdu->write_offset += sizeof(u32);
657c797b6c6SAneesh Kumar K.V while (dent) {
658c797b6c6SAneesh Kumar K.V u32 read;
659c797b6c6SAneesh Kumar K.V struct p9_qid qid;
660c797b6c6SAneesh Kumar K.V
661c797b6c6SAneesh Kumar K.V if ((rcount + virtio_p9_dentry_size(dent)) > count) {
662c797b6c6SAneesh Kumar K.V /* seek to the previous offset and return */
663c797b6c6SAneesh Kumar K.V seekdir(fid->dir, old_offset);
664c797b6c6SAneesh Kumar K.V break;
665c797b6c6SAneesh Kumar K.V }
666c797b6c6SAneesh Kumar K.V old_offset = dent->d_off;
667b0922422SG. Campana if (stat_rel(p9dev, dent->d_name, &st) != 0)
668b0922422SG. Campana memset(&st, -1, sizeof(st));
669c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid);
670c797b6c6SAneesh Kumar K.V read = pdu->write_offset;
671c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Qqbs", &qid, dent->d_off,
672c797b6c6SAneesh Kumar K.V dent->d_type, dent->d_name);
673c797b6c6SAneesh Kumar K.V rcount += pdu->write_offset - read;
674c797b6c6SAneesh Kumar K.V dent = readdir(fid->dir);
675c797b6c6SAneesh Kumar K.V }
676c797b6c6SAneesh Kumar K.V
6775529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN;
678c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", rcount);
679c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset + rcount;
680c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
681c797b6c6SAneesh Kumar K.V return;
682c797b6c6SAneesh Kumar K.V err_out:
683c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
684c797b6c6SAneesh Kumar K.V return;
685c797b6c6SAneesh Kumar K.V }
686c797b6c6SAneesh Kumar K.V
687c797b6c6SAneesh Kumar K.V
virtio_p9_getattr(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)688c797b6c6SAneesh Kumar K.V static void virtio_p9_getattr(struct p9_dev *p9dev,
689af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
6901c7850f9SSasha Levin {
691bfc15268SAneesh Kumar K.V u32 fid_val;
692af045e53SAneesh Kumar K.V struct stat st;
693c797b6c6SAneesh Kumar K.V u64 request_mask;
694bfc15268SAneesh Kumar K.V struct p9_fid *fid;
695c797b6c6SAneesh Kumar K.V struct p9_stat_dotl statl;
6961c7850f9SSasha Levin
697c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dq", &fid_val, &request_mask);
69831a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val);
69930204a77SAneesh Kumar K.V if (lstat(fid->abs_path, &st) < 0)
7006c8ca053SAneesh Kumar K.V goto err_out;
7011c7850f9SSasha Levin
702c797b6c6SAneesh Kumar K.V virtio_p9_fill_stat(p9dev, &st, &statl);
703c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "A", &statl);
704bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset;
705bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
706ead43b01SAneesh Kumar K.V return;
7076c8ca053SAneesh Kumar K.V err_out:
7086c8ca053SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
7096c8ca053SAneesh Kumar K.V return;
7101c7850f9SSasha Levin }
7111c7850f9SSasha Levin
712c797b6c6SAneesh Kumar K.V /* FIXME!! from linux/fs.h */
713c797b6c6SAneesh Kumar K.V /*
714c797b6c6SAneesh Kumar K.V * Attribute flags. These should be or-ed together to figure out what
715c797b6c6SAneesh Kumar K.V * has been changed!
716c797b6c6SAneesh Kumar K.V */
717c797b6c6SAneesh Kumar K.V #define ATTR_MODE (1 << 0)
718c797b6c6SAneesh Kumar K.V #define ATTR_UID (1 << 1)
719c797b6c6SAneesh Kumar K.V #define ATTR_GID (1 << 2)
720c797b6c6SAneesh Kumar K.V #define ATTR_SIZE (1 << 3)
721c797b6c6SAneesh Kumar K.V #define ATTR_ATIME (1 << 4)
722c797b6c6SAneesh Kumar K.V #define ATTR_MTIME (1 << 5)
723c797b6c6SAneesh Kumar K.V #define ATTR_CTIME (1 << 6)
724c797b6c6SAneesh Kumar K.V #define ATTR_ATIME_SET (1 << 7)
725c797b6c6SAneesh Kumar K.V #define ATTR_MTIME_SET (1 << 8)
726c797b6c6SAneesh Kumar K.V #define ATTR_FORCE (1 << 9) /* Not a change, but a change it */
727c797b6c6SAneesh Kumar K.V #define ATTR_ATTR_FLAG (1 << 10)
728c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SUID (1 << 11)
729c797b6c6SAneesh Kumar K.V #define ATTR_KILL_SGID (1 << 12)
730c797b6c6SAneesh Kumar K.V #define ATTR_FILE (1 << 13)
731c797b6c6SAneesh Kumar K.V #define ATTR_KILL_PRIV (1 << 14)
732c797b6c6SAneesh Kumar K.V #define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */
733c797b6c6SAneesh Kumar K.V #define ATTR_TIMES_SET (1 << 16)
734c797b6c6SAneesh Kumar K.V
735c797b6c6SAneesh Kumar K.V #define ATTR_MASK 127
736c797b6c6SAneesh Kumar K.V
virtio_p9_setattr(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)737c797b6c6SAneesh Kumar K.V static void virtio_p9_setattr(struct p9_dev *p9dev,
738af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
7391c7850f9SSasha Levin {
740c797b6c6SAneesh Kumar K.V int ret = 0;
741bfc15268SAneesh Kumar K.V u32 fid_val;
742bfc15268SAneesh Kumar K.V struct p9_fid *fid;
743c797b6c6SAneesh Kumar K.V struct p9_iattr_dotl p9attr;
7441c7850f9SSasha Levin
745c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dI", &fid_val, &p9attr);
74631a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val);
7471c7850f9SSasha Levin
748c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MODE) {
749c797b6c6SAneesh Kumar K.V ret = chmod(fid->abs_path, p9attr.mode);
750c797b6c6SAneesh Kumar K.V if (ret < 0)
751c797b6c6SAneesh Kumar K.V goto err_out;
752c797b6c6SAneesh Kumar K.V }
753c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_ATIME | ATTR_MTIME)) {
754c797b6c6SAneesh Kumar K.V struct timespec times[2];
755c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME) {
756c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_ATIME_SET) {
757c797b6c6SAneesh Kumar K.V times[0].tv_sec = p9attr.atime_sec;
758c797b6c6SAneesh Kumar K.V times[0].tv_nsec = p9attr.atime_nsec;
759c797b6c6SAneesh Kumar K.V } else {
760c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_NOW;
761c797b6c6SAneesh Kumar K.V }
762c797b6c6SAneesh Kumar K.V } else {
763c797b6c6SAneesh Kumar K.V times[0].tv_nsec = UTIME_OMIT;
764c797b6c6SAneesh Kumar K.V }
765c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME) {
766c797b6c6SAneesh Kumar K.V if (p9attr.valid & ATTR_MTIME_SET) {
767c797b6c6SAneesh Kumar K.V times[1].tv_sec = p9attr.mtime_sec;
768c797b6c6SAneesh Kumar K.V times[1].tv_nsec = p9attr.mtime_nsec;
769c797b6c6SAneesh Kumar K.V } else {
770c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_NOW;
771c797b6c6SAneesh Kumar K.V }
772c797b6c6SAneesh Kumar K.V } else
773c797b6c6SAneesh Kumar K.V times[1].tv_nsec = UTIME_OMIT;
774c797b6c6SAneesh Kumar K.V
775c797b6c6SAneesh Kumar K.V ret = utimensat(-1, fid->abs_path, times, AT_SYMLINK_NOFOLLOW);
776c797b6c6SAneesh Kumar K.V if (ret < 0)
777c797b6c6SAneesh Kumar K.V goto err_out;
778c797b6c6SAneesh Kumar K.V }
779c797b6c6SAneesh Kumar K.V /*
780c797b6c6SAneesh Kumar K.V * If the only valid entry in iattr is ctime we can call
781c797b6c6SAneesh Kumar K.V * chown(-1,-1) to update the ctime of the file
782c797b6c6SAneesh Kumar K.V */
783c797b6c6SAneesh Kumar K.V if ((p9attr.valid & (ATTR_UID | ATTR_GID)) ||
784c797b6c6SAneesh Kumar K.V ((p9attr.valid & ATTR_CTIME)
785c797b6c6SAneesh Kumar K.V && !((p9attr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
786c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_UID))
787506fd90bSSasha Levin p9attr.uid = KUIDT_INIT(-1);
788c797b6c6SAneesh Kumar K.V
789c797b6c6SAneesh Kumar K.V if (!(p9attr.valid & ATTR_GID))
790506fd90bSSasha Levin p9attr.gid = KGIDT_INIT(-1);
791c797b6c6SAneesh Kumar K.V
792506fd90bSSasha Levin ret = lchown(fid->abs_path, __kuid_val(p9attr.uid),
793506fd90bSSasha Levin __kgid_val(p9attr.gid));
794c797b6c6SAneesh Kumar K.V if (ret < 0)
795c797b6c6SAneesh Kumar K.V goto err_out;
796c797b6c6SAneesh Kumar K.V }
797c797b6c6SAneesh Kumar K.V if (p9attr.valid & (ATTR_SIZE)) {
798c797b6c6SAneesh Kumar K.V ret = truncate(fid->abs_path, p9attr.size);
799c797b6c6SAneesh Kumar K.V if (ret < 0)
800c797b6c6SAneesh Kumar K.V goto err_out;
801c797b6c6SAneesh Kumar K.V }
8025529bcd7SAsias He *outlen = VIRTIO_9P_HDR_LEN;
803bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
804ead43b01SAneesh Kumar K.V return;
8054bc9734aSAneesh Kumar K.V err_out:
8064bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
8074bc9734aSAneesh Kumar K.V return;
8081c7850f9SSasha Levin }
8091c7850f9SSasha Levin
virtio_p9_write(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)810ead43b01SAneesh Kumar K.V static void virtio_p9_write(struct p9_dev *p9dev,
811af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
8121c7850f9SSasha Levin {
8134bc9734aSAneesh Kumar K.V
814bfc15268SAneesh Kumar K.V u64 offset;
815bfc15268SAneesh Kumar K.V u32 fid_val;
8164bc9734aSAneesh Kumar K.V u32 count;
8174bc9734aSAneesh Kumar K.V ssize_t res;
81850c479e0SAneesh Kumar K.V u16 iov_cnt;
81950c479e0SAneesh Kumar K.V void *iov_base;
82050c479e0SAneesh Kumar K.V size_t iov_len;
821bfc15268SAneesh Kumar K.V struct p9_fid *fid;
822b064b05aSAneesh Kumar K.V /* u32 fid + u64 offset + u32 count */
823b064b05aSAneesh Kumar K.V int twrite_size = sizeof(u32) + sizeof(u64) + sizeof(u32);
8241c7850f9SSasha Levin
825bfc15268SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dqd", &fid_val, &offset, &count);
82631a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val);
827af045e53SAneesh Kumar K.V
82850c479e0SAneesh Kumar K.V iov_base = pdu->out_iov[0].iov_base;
82950c479e0SAneesh Kumar K.V iov_len = pdu->out_iov[0].iov_len;
83050c479e0SAneesh Kumar K.V iov_cnt = pdu->out_iov_cnt;
83150c479e0SAneesh Kumar K.V
832bfc15268SAneesh Kumar K.V /* Adjust the iovec to skip the header and meta data */
833b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_base += (sizeof(struct p9_msg) + twrite_size);
834b064b05aSAneesh Kumar K.V pdu->out_iov[0].iov_len -= (sizeof(struct p9_msg) + twrite_size);
835bfc15268SAneesh Kumar K.V pdu->out_iov_cnt = virtio_p9_update_iov_cnt(pdu->out_iov, count,
8366b163a87SAneesh Kumar K.V pdu->out_iov_cnt);
8374bc9734aSAneesh Kumar K.V res = pwritev(fid->fd, pdu->out_iov, pdu->out_iov_cnt, offset);
83850c479e0SAneesh Kumar K.V /*
83950c479e0SAneesh Kumar K.V * Update the iov_base back, so that rest of
84050c479e0SAneesh Kumar K.V * pdu_readf works correctly.
84150c479e0SAneesh Kumar K.V */
84250c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_base = iov_base;
84350c479e0SAneesh Kumar K.V pdu->out_iov[0].iov_len = iov_len;
84450c479e0SAneesh Kumar K.V pdu->out_iov_cnt = iov_cnt;
845c797b6c6SAneesh Kumar K.V
8464bc9734aSAneesh Kumar K.V if (res < 0)
8474bc9734aSAneesh Kumar K.V goto err_out;
8484bc9734aSAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", res);
849bfc15268SAneesh Kumar K.V *outlen = pdu->write_offset;
850bfc15268SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
851ead43b01SAneesh Kumar K.V return;
8524bc9734aSAneesh Kumar K.V err_out:
8534bc9734aSAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
8544bc9734aSAneesh Kumar K.V return;
8551c7850f9SSasha Levin }
8561c7850f9SSasha Levin
virtio_p9_remove(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)8576fc5cd9bSSasha Levin static void virtio_p9_remove(struct p9_dev *p9dev,
8586fc5cd9bSSasha Levin struct p9_pdu *pdu, u32 *outlen)
8596fc5cd9bSSasha Levin {
8606fc5cd9bSSasha Levin int ret;
8616fc5cd9bSSasha Levin u32 fid_val;
8626fc5cd9bSSasha Levin struct p9_fid *fid;
8636fc5cd9bSSasha Levin
8646fc5cd9bSSasha Levin virtio_p9_pdu_readf(pdu, "d", &fid_val);
86531a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val);
8666fc5cd9bSSasha Levin
8679b604a9cSSasha Levin ret = remove(fid->abs_path);
8686fc5cd9bSSasha Levin if (ret < 0)
8696fc5cd9bSSasha Levin goto err_out;
8706fc5cd9bSSasha Levin *outlen = pdu->write_offset;
8716fc5cd9bSSasha Levin virtio_p9_set_reply_header(pdu, *outlen);
8726fc5cd9bSSasha Levin return;
8736fc5cd9bSSasha Levin
8746fc5cd9bSSasha Levin err_out:
8756fc5cd9bSSasha Levin virtio_p9_error_reply(p9dev, pdu, errno, outlen);
8766fc5cd9bSSasha Levin return;
8776fc5cd9bSSasha Levin }
8786fc5cd9bSSasha Levin
virtio_p9_rename(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)879f161f28bSSasha Levin static void virtio_p9_rename(struct p9_dev *p9dev,
880f161f28bSSasha Levin struct p9_pdu *pdu, u32 *outlen)
881f161f28bSSasha Levin {
882f161f28bSSasha Levin int ret;
883f161f28bSSasha Levin u32 fid_val, new_fid_val;
884f161f28bSSasha Levin struct p9_fid *fid, *new_fid;
885f161f28bSSasha Levin char full_path[PATH_MAX], *new_name;
886f161f28bSSasha Levin
887f161f28bSSasha Levin virtio_p9_pdu_readf(pdu, "dds", &fid_val, &new_fid_val, &new_name);
88831a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val);
88931a6fb8dSSasha Levin new_fid = get_fid(p9dev, new_fid_val);
890f161f28bSSasha Levin
891d4727f2bSG. Campana if (get_full_path(full_path, sizeof(full_path), new_fid, new_name) != 0)
89232832dd1SG. Campana goto err_out;
8939bb99a82SG. Campana
894f161f28bSSasha Levin ret = rename(fid->abs_path, full_path);
895f161f28bSSasha Levin if (ret < 0)
896f161f28bSSasha Levin goto err_out;
897f161f28bSSasha Levin *outlen = pdu->write_offset;
898f161f28bSSasha Levin virtio_p9_set_reply_header(pdu, *outlen);
899f161f28bSSasha Levin return;
900f161f28bSSasha Levin
901f161f28bSSasha Levin err_out:
902f161f28bSSasha Levin virtio_p9_error_reply(p9dev, pdu, errno, outlen);
903f161f28bSSasha Levin return;
904f161f28bSSasha Levin }
905f161f28bSSasha Levin
virtio_p9_readlink(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)906c797b6c6SAneesh Kumar K.V static void virtio_p9_readlink(struct p9_dev *p9dev,
907c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
908c797b6c6SAneesh Kumar K.V {
909c797b6c6SAneesh Kumar K.V int ret;
910c797b6c6SAneesh Kumar K.V u32 fid_val;
911c797b6c6SAneesh Kumar K.V struct p9_fid *fid;
912c797b6c6SAneesh Kumar K.V char target_path[PATH_MAX];
913c797b6c6SAneesh Kumar K.V
914c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val);
91531a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val);
916c797b6c6SAneesh Kumar K.V
917c797b6c6SAneesh Kumar K.V memset(target_path, 0, PATH_MAX);
918c797b6c6SAneesh Kumar K.V ret = readlink(fid->abs_path, target_path, PATH_MAX - 1);
919c797b6c6SAneesh Kumar K.V if (ret < 0)
920c797b6c6SAneesh Kumar K.V goto err_out;
921c797b6c6SAneesh Kumar K.V
922c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "s", target_path);
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 virtio_p9_error_reply(p9dev, pdu, errno, outlen);
928c797b6c6SAneesh Kumar K.V return;
929c797b6c6SAneesh Kumar K.V }
930c797b6c6SAneesh Kumar K.V
virtio_p9_statfs(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)931c797b6c6SAneesh Kumar K.V static void virtio_p9_statfs(struct p9_dev *p9dev,
932c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
933c797b6c6SAneesh Kumar K.V {
934c797b6c6SAneesh Kumar K.V int ret;
935c797b6c6SAneesh Kumar K.V u64 fsid;
936c797b6c6SAneesh Kumar K.V u32 fid_val;
937c797b6c6SAneesh Kumar K.V struct p9_fid *fid;
938c797b6c6SAneesh Kumar K.V struct statfs stat_buf;
939c797b6c6SAneesh Kumar K.V
940c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "d", &fid_val);
94131a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val);
942c797b6c6SAneesh Kumar K.V
943c797b6c6SAneesh Kumar K.V ret = statfs(fid->abs_path, &stat_buf);
944c797b6c6SAneesh Kumar K.V if (ret < 0)
945c797b6c6SAneesh Kumar K.V goto err_out;
946c797b6c6SAneesh Kumar K.V /* FIXME!! f_blocks needs update based on client msize */
947c797b6c6SAneesh Kumar K.V fsid = (unsigned int) stat_buf.f_fsid.__val[0] |
948c797b6c6SAneesh Kumar K.V (unsigned long long)stat_buf.f_fsid.__val[1] << 32;
949c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "ddqqqqqqd", stat_buf.f_type,
950c797b6c6SAneesh Kumar K.V stat_buf.f_bsize, stat_buf.f_blocks,
951c797b6c6SAneesh Kumar K.V stat_buf.f_bfree, stat_buf.f_bavail,
952c797b6c6SAneesh Kumar K.V stat_buf.f_files, stat_buf.f_ffree,
953c797b6c6SAneesh Kumar K.V fsid, stat_buf.f_namelen);
954c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset;
955c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
956c797b6c6SAneesh Kumar K.V return;
957c797b6c6SAneesh Kumar K.V err_out:
958c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
959c797b6c6SAneesh Kumar K.V return;
960c797b6c6SAneesh Kumar K.V }
961c797b6c6SAneesh Kumar K.V
virtio_p9_mknod(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)962c797b6c6SAneesh Kumar K.V static void virtio_p9_mknod(struct p9_dev *p9dev,
963c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
964c797b6c6SAneesh Kumar K.V {
965c797b6c6SAneesh Kumar K.V int ret;
966c797b6c6SAneesh Kumar K.V char *name;
967c797b6c6SAneesh Kumar K.V struct stat st;
968c797b6c6SAneesh Kumar K.V struct p9_fid *dfid;
969c797b6c6SAneesh Kumar K.V struct p9_qid qid;
970c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX];
971c797b6c6SAneesh Kumar K.V u32 fid_val, mode, major, minor, gid;
972c797b6c6SAneesh Kumar K.V
973c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsdddd", &fid_val, &name, &mode,
974c797b6c6SAneesh Kumar K.V &major, &minor, &gid);
975c797b6c6SAneesh Kumar K.V
97631a6fb8dSSasha Levin dfid = get_fid(p9dev, fid_val);
97732832dd1SG. Campana
978d4727f2bSG. Campana if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0)
9799bb99a82SG. Campana goto err_out;
9809bb99a82SG. Campana
981c797b6c6SAneesh Kumar K.V ret = mknod(full_path, mode, makedev(major, minor));
982c797b6c6SAneesh Kumar K.V if (ret < 0)
983c797b6c6SAneesh Kumar K.V goto err_out;
984c797b6c6SAneesh Kumar K.V
985c797b6c6SAneesh Kumar K.V if (lstat(full_path, &st) < 0)
986c797b6c6SAneesh Kumar K.V goto err_out;
987c797b6c6SAneesh Kumar K.V
988c797b6c6SAneesh Kumar K.V ret = chmod(full_path, mode & 0777);
989c797b6c6SAneesh Kumar K.V if (ret < 0)
990c797b6c6SAneesh Kumar K.V goto err_out;
991c797b6c6SAneesh Kumar K.V
992c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid);
993c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid);
994c797b6c6SAneesh Kumar K.V free(name);
995c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset;
996c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
997c797b6c6SAneesh Kumar K.V return;
998c797b6c6SAneesh Kumar K.V err_out:
999c797b6c6SAneesh Kumar K.V free(name);
1000c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1001c797b6c6SAneesh Kumar K.V return;
1002c797b6c6SAneesh Kumar K.V }
1003c797b6c6SAneesh Kumar K.V
virtio_p9_fsync(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1004c797b6c6SAneesh Kumar K.V static void virtio_p9_fsync(struct p9_dev *p9dev,
1005c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
1006c797b6c6SAneesh Kumar K.V {
1007644140efSRussell King int ret, fd;
1008c797b6c6SAneesh Kumar K.V struct p9_fid *fid;
1009c797b6c6SAneesh Kumar K.V u32 fid_val, datasync;
1010c797b6c6SAneesh Kumar K.V
1011c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dd", &fid_val, &datasync);
101231a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val);
1013c797b6c6SAneesh Kumar K.V
1014644140efSRussell King if (fid->dir)
1015644140efSRussell King fd = dirfd(fid->dir);
1016c797b6c6SAneesh Kumar K.V else
1017644140efSRussell King fd = fid->fd;
1018644140efSRussell King
1019644140efSRussell King if (datasync)
1020644140efSRussell King ret = fdatasync(fd);
1021644140efSRussell King else
1022644140efSRussell King ret = fsync(fd);
1023c797b6c6SAneesh Kumar K.V if (ret < 0)
1024c797b6c6SAneesh Kumar K.V goto err_out;
1025c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset;
1026c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
1027c797b6c6SAneesh Kumar K.V return;
1028c797b6c6SAneesh Kumar K.V err_out:
1029c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1030c797b6c6SAneesh Kumar K.V return;
1031c797b6c6SAneesh Kumar K.V }
1032c797b6c6SAneesh Kumar K.V
virtio_p9_symlink(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1033c797b6c6SAneesh Kumar K.V static void virtio_p9_symlink(struct p9_dev *p9dev,
1034c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
1035c797b6c6SAneesh Kumar K.V {
1036c797b6c6SAneesh Kumar K.V int ret;
1037c797b6c6SAneesh Kumar K.V struct stat st;
1038c797b6c6SAneesh Kumar K.V u32 fid_val, gid;
1039c797b6c6SAneesh Kumar K.V struct p9_qid qid;
1040c797b6c6SAneesh Kumar K.V struct p9_fid *dfid;
1041c797b6c6SAneesh Kumar K.V char new_name[PATH_MAX];
1042c797b6c6SAneesh Kumar K.V char *old_path, *name;
1043c797b6c6SAneesh Kumar K.V
1044c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dssd", &fid_val, &name, &old_path, &gid);
1045c797b6c6SAneesh Kumar K.V
104631a6fb8dSSasha Levin dfid = get_fid(p9dev, fid_val);
104732832dd1SG. Campana
1048d4727f2bSG. Campana if (get_full_path(new_name, sizeof(new_name), dfid, name) != 0)
10499bb99a82SG. Campana goto err_out;
10509bb99a82SG. Campana
1051c797b6c6SAneesh Kumar K.V ret = symlink(old_path, new_name);
1052c797b6c6SAneesh Kumar K.V if (ret < 0)
1053c797b6c6SAneesh Kumar K.V goto err_out;
1054c797b6c6SAneesh Kumar K.V
1055c797b6c6SAneesh Kumar K.V if (lstat(new_name, &st) < 0)
1056c797b6c6SAneesh Kumar K.V goto err_out;
1057c797b6c6SAneesh Kumar K.V
1058c797b6c6SAneesh Kumar K.V stat2qid(&st, &qid);
1059c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "Q", &qid);
1060c797b6c6SAneesh Kumar K.V free(name);
1061c797b6c6SAneesh Kumar K.V free(old_path);
1062c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset;
1063c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
1064c797b6c6SAneesh Kumar K.V return;
1065c797b6c6SAneesh Kumar K.V err_out:
1066c797b6c6SAneesh Kumar K.V free(name);
1067c797b6c6SAneesh Kumar K.V free(old_path);
1068c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1069c797b6c6SAneesh Kumar K.V return;
1070c797b6c6SAneesh Kumar K.V }
1071c797b6c6SAneesh Kumar K.V
virtio_p9_link(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1072c797b6c6SAneesh Kumar K.V static void virtio_p9_link(struct p9_dev *p9dev,
1073c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
1074c797b6c6SAneesh Kumar K.V {
1075c797b6c6SAneesh Kumar K.V int ret;
1076c797b6c6SAneesh Kumar K.V char *name;
1077c797b6c6SAneesh Kumar K.V u32 fid_val, dfid_val;
1078c797b6c6SAneesh Kumar K.V struct p9_fid *dfid, *fid;
1079c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX];
1080c797b6c6SAneesh Kumar K.V
1081c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dds", &dfid_val, &fid_val, &name);
1082c797b6c6SAneesh Kumar K.V
108331a6fb8dSSasha Levin dfid = get_fid(p9dev, dfid_val);
108431a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val);
108532832dd1SG. Campana
1086d4727f2bSG. Campana if (get_full_path(full_path, sizeof(full_path), dfid, name) != 0)
10879bb99a82SG. Campana goto err_out;
10889bb99a82SG. Campana
1089c797b6c6SAneesh Kumar K.V ret = link(fid->abs_path, full_path);
1090c797b6c6SAneesh Kumar K.V if (ret < 0)
1091c797b6c6SAneesh Kumar K.V goto err_out;
1092c797b6c6SAneesh Kumar K.V free(name);
1093c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset;
1094c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
1095c797b6c6SAneesh Kumar K.V return;
1096c797b6c6SAneesh Kumar K.V err_out:
1097c797b6c6SAneesh Kumar K.V free(name);
1098c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1099c797b6c6SAneesh Kumar K.V return;
1100c797b6c6SAneesh Kumar K.V
1101c797b6c6SAneesh Kumar K.V }
1102c797b6c6SAneesh Kumar K.V
virtio_p9_lock(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1103c797b6c6SAneesh Kumar K.V static void virtio_p9_lock(struct p9_dev *p9dev,
1104c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
1105c797b6c6SAneesh Kumar K.V {
1106c797b6c6SAneesh Kumar K.V u8 ret;
1107c797b6c6SAneesh Kumar K.V u32 fid_val;
1108c797b6c6SAneesh Kumar K.V struct p9_flock flock;
1109c797b6c6SAneesh Kumar K.V
1110c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbdqqds", &fid_val, &flock.type,
1111c797b6c6SAneesh Kumar K.V &flock.flags, &flock.start, &flock.length,
1112c797b6c6SAneesh Kumar K.V &flock.proc_id, &flock.client_id);
1113c797b6c6SAneesh Kumar K.V
1114c797b6c6SAneesh Kumar K.V /* Just return success */
1115c797b6c6SAneesh Kumar K.V ret = P9_LOCK_SUCCESS;
1116c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "d", ret);
1117c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset;
1118c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
1119c797b6c6SAneesh Kumar K.V free(flock.client_id);
1120c797b6c6SAneesh Kumar K.V return;
1121c797b6c6SAneesh Kumar K.V }
1122c797b6c6SAneesh Kumar K.V
virtio_p9_getlock(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1123c797b6c6SAneesh Kumar K.V static void virtio_p9_getlock(struct p9_dev *p9dev,
1124c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
1125c797b6c6SAneesh Kumar K.V {
1126c797b6c6SAneesh Kumar K.V u32 fid_val;
1127c797b6c6SAneesh Kumar K.V struct p9_getlock glock;
1128c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dbqqds", &fid_val, &glock.type,
1129c797b6c6SAneesh Kumar K.V &glock.start, &glock.length, &glock.proc_id,
1130c797b6c6SAneesh Kumar K.V &glock.client_id);
1131c797b6c6SAneesh Kumar K.V
1132c797b6c6SAneesh Kumar K.V /* Just return success */
1133c797b6c6SAneesh Kumar K.V glock.type = F_UNLCK;
1134c797b6c6SAneesh Kumar K.V virtio_p9_pdu_writef(pdu, "bqqds", glock.type,
1135c797b6c6SAneesh Kumar K.V glock.start, glock.length, glock.proc_id,
1136c797b6c6SAneesh Kumar K.V glock.client_id);
1137c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset;
1138c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
1139c797b6c6SAneesh Kumar K.V free(glock.client_id);
1140c797b6c6SAneesh Kumar K.V return;
1141c797b6c6SAneesh Kumar K.V }
1142c797b6c6SAneesh Kumar K.V
virtio_p9_ancestor(char * path,char * ancestor)1143c797b6c6SAneesh Kumar K.V static int virtio_p9_ancestor(char *path, char *ancestor)
1144c797b6c6SAneesh Kumar K.V {
1145c797b6c6SAneesh Kumar K.V int size = strlen(ancestor);
1146c797b6c6SAneesh Kumar K.V if (!strncmp(path, ancestor, size)) {
1147c797b6c6SAneesh Kumar K.V /*
1148c797b6c6SAneesh Kumar K.V * Now check whether ancestor is a full name or
1149c797b6c6SAneesh Kumar K.V * or directory component and not just part
1150c797b6c6SAneesh Kumar K.V * of a name.
1151c797b6c6SAneesh Kumar K.V */
1152c797b6c6SAneesh Kumar K.V if (path[size] == '\0' || path[size] == '/')
1153c797b6c6SAneesh Kumar K.V return 1;
1154c797b6c6SAneesh Kumar K.V }
1155c797b6c6SAneesh Kumar K.V return 0;
1156c797b6c6SAneesh Kumar K.V }
1157c797b6c6SAneesh Kumar K.V
virtio_p9_fix_path(struct p9_fid * fid,char * old_name,char * new_name)1158e277a1b4SG. Campana static int virtio_p9_fix_path(struct p9_fid *fid, char *old_name, char *new_name)
1159c797b6c6SAneesh Kumar K.V {
1160e277a1b4SG. Campana int ret;
1161e277a1b4SG. Campana char *p, tmp_name[PATH_MAX];
1162c797b6c6SAneesh Kumar K.V size_t rp_sz = strlen(old_name);
1163c797b6c6SAneesh Kumar K.V
1164e277a1b4SG. Campana if (rp_sz == strlen(fid->path)) {
1165c797b6c6SAneesh Kumar K.V /* replace the full name */
1166e277a1b4SG. Campana p = new_name;
1167e277a1b4SG. Campana } else {
1168c797b6c6SAneesh Kumar K.V /* save the trailing path details */
1169e277a1b4SG. Campana ret = snprintf(tmp_name, sizeof(tmp_name), "%s%s", new_name, fid->path + rp_sz);
1170e277a1b4SG. Campana if (ret >= (int)sizeof(tmp_name))
1171e277a1b4SG. Campana return -1;
1172e277a1b4SG. Campana p = tmp_name;
1173e277a1b4SG. Campana }
1174e277a1b4SG. Campana
1175e277a1b4SG. Campana return join_path(fid, p);
1176c797b6c6SAneesh Kumar K.V }
1177c797b6c6SAneesh Kumar K.V
rename_fids(struct p9_dev * p9dev,char * old_name,char * new_name)1178e2341580SSasha Levin static void rename_fids(struct p9_dev *p9dev, char *old_name, char *new_name)
1179e2341580SSasha Levin {
1180e2341580SSasha Levin struct rb_node *node = rb_first(&p9dev->fids);
1181e2341580SSasha Levin
1182e2341580SSasha Levin while (node) {
1183e2341580SSasha Levin struct p9_fid *fid = rb_entry(node, struct p9_fid, node);
1184e2341580SSasha Levin
1185e2341580SSasha Levin if (fid->fid != P9_NOFID && virtio_p9_ancestor(fid->path, old_name)) {
1186e277a1b4SG. Campana virtio_p9_fix_path(fid, old_name, new_name);
1187e2341580SSasha Levin }
1188e2341580SSasha Levin node = rb_next(node);
1189e2341580SSasha Levin }
1190e2341580SSasha Levin }
1191e2341580SSasha Levin
virtio_p9_renameat(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1192c797b6c6SAneesh Kumar K.V static void virtio_p9_renameat(struct p9_dev *p9dev,
1193c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
1194c797b6c6SAneesh Kumar K.V {
1195e2341580SSasha Levin int ret;
1196c797b6c6SAneesh Kumar K.V char *old_name, *new_name;
1197c797b6c6SAneesh Kumar K.V u32 old_dfid_val, new_dfid_val;
1198c797b6c6SAneesh Kumar K.V struct p9_fid *old_dfid, *new_dfid;
1199c797b6c6SAneesh Kumar K.V char old_full_path[PATH_MAX], new_full_path[PATH_MAX];
1200c797b6c6SAneesh Kumar K.V
1201c797b6c6SAneesh Kumar K.V
1202c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsds", &old_dfid_val, &old_name,
1203c797b6c6SAneesh Kumar K.V &new_dfid_val, &new_name);
1204c797b6c6SAneesh Kumar K.V
120531a6fb8dSSasha Levin old_dfid = get_fid(p9dev, old_dfid_val);
120631a6fb8dSSasha Levin new_dfid = get_fid(p9dev, new_dfid_val);
1207c797b6c6SAneesh Kumar K.V
1208d4727f2bSG. Campana if (get_full_path(old_full_path, sizeof(old_full_path), old_dfid, old_name) != 0)
120932832dd1SG. Campana goto err_out;
121032832dd1SG. Campana
1211d4727f2bSG. Campana if (get_full_path(new_full_path, sizeof(new_full_path), new_dfid, new_name) != 0)
121232832dd1SG. Campana goto err_out;
12139bb99a82SG. Campana
1214c797b6c6SAneesh Kumar K.V ret = rename(old_full_path, new_full_path);
1215c797b6c6SAneesh Kumar K.V if (ret < 0)
1216c797b6c6SAneesh Kumar K.V goto err_out;
1217c797b6c6SAneesh Kumar K.V /*
1218c797b6c6SAneesh Kumar K.V * Now fix path in other fids, if the renamed path is part of
1219c797b6c6SAneesh Kumar K.V * that.
1220c797b6c6SAneesh Kumar K.V */
1221e2341580SSasha Levin rename_fids(p9dev, old_name, new_name);
1222c797b6c6SAneesh Kumar K.V free(old_name);
1223c797b6c6SAneesh Kumar K.V free(new_name);
1224c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset;
1225c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
1226c797b6c6SAneesh Kumar K.V return;
1227c797b6c6SAneesh Kumar K.V err_out:
1228c797b6c6SAneesh Kumar K.V free(old_name);
1229c797b6c6SAneesh Kumar K.V free(new_name);
1230c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1231c797b6c6SAneesh Kumar K.V return;
1232c797b6c6SAneesh Kumar K.V }
1233c797b6c6SAneesh Kumar K.V
virtio_p9_unlinkat(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1234c797b6c6SAneesh Kumar K.V static void virtio_p9_unlinkat(struct p9_dev *p9dev,
1235c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
1236c797b6c6SAneesh Kumar K.V {
1237c797b6c6SAneesh Kumar K.V int ret;
1238c797b6c6SAneesh Kumar K.V char *name;
1239c797b6c6SAneesh Kumar K.V u32 fid_val, flags;
1240c797b6c6SAneesh Kumar K.V struct p9_fid *fid;
1241c797b6c6SAneesh Kumar K.V char full_path[PATH_MAX];
1242c797b6c6SAneesh Kumar K.V
1243c797b6c6SAneesh Kumar K.V virtio_p9_pdu_readf(pdu, "dsd", &fid_val, &name, &flags);
124431a6fb8dSSasha Levin fid = get_fid(p9dev, fid_val);
1245c797b6c6SAneesh Kumar K.V
1246d4727f2bSG. Campana if (get_full_path(full_path, sizeof(full_path), fid, name) != 0)
124732832dd1SG. Campana goto err_out;
12489bb99a82SG. Campana
1249c797b6c6SAneesh Kumar K.V ret = remove(full_path);
1250c797b6c6SAneesh Kumar K.V if (ret < 0)
1251c797b6c6SAneesh Kumar K.V goto err_out;
1252c797b6c6SAneesh Kumar K.V free(name);
1253c797b6c6SAneesh Kumar K.V *outlen = pdu->write_offset;
1254c797b6c6SAneesh Kumar K.V virtio_p9_set_reply_header(pdu, *outlen);
1255c797b6c6SAneesh Kumar K.V return;
1256c797b6c6SAneesh Kumar K.V err_out:
1257c797b6c6SAneesh Kumar K.V free(name);
1258c797b6c6SAneesh Kumar K.V virtio_p9_error_reply(p9dev, pdu, errno, outlen);
1259c797b6c6SAneesh Kumar K.V return;
1260c797b6c6SAneesh Kumar K.V }
1261c797b6c6SAneesh Kumar K.V
virtio_p9_flush(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)12625cc808aaSSasha Levin static void virtio_p9_flush(struct p9_dev *p9dev,
12635cc808aaSSasha Levin struct p9_pdu *pdu, u32 *outlen)
12645cc808aaSSasha Levin {
12655cc808aaSSasha Levin u16 tag, oldtag;
12665cc808aaSSasha Levin
12675cc808aaSSasha Levin virtio_p9_pdu_readf(pdu, "ww", &tag, &oldtag);
12685cc808aaSSasha Levin virtio_p9_pdu_writef(pdu, "w", tag);
12695cc808aaSSasha Levin *outlen = pdu->write_offset;
12705cc808aaSSasha Levin virtio_p9_set_reply_header(pdu, *outlen);
12715cc808aaSSasha Levin
12725cc808aaSSasha Levin return;
12735cc808aaSSasha Levin }
12745cc808aaSSasha Levin
virtio_p9_eopnotsupp(struct p9_dev * p9dev,struct p9_pdu * pdu,u32 * outlen)1275c797b6c6SAneesh Kumar K.V static void virtio_p9_eopnotsupp(struct p9_dev *p9dev,
1276c797b6c6SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen)
1277c797b6c6SAneesh Kumar K.V {
1278c797b6c6SAneesh Kumar K.V return virtio_p9_error_reply(p9dev, pdu, EOPNOTSUPP, outlen);
1279c797b6c6SAneesh Kumar K.V }
1280c797b6c6SAneesh Kumar K.V
1281ead43b01SAneesh Kumar K.V typedef void p9_handler(struct p9_dev *p9dev,
1282af045e53SAneesh Kumar K.V struct p9_pdu *pdu, u32 *outlen);
1283b4422bf3SAneesh Kumar K.V
1284c797b6c6SAneesh Kumar K.V /* FIXME should be removed when merging with latest linus tree */
1285c797b6c6SAneesh Kumar K.V #define P9_TRENAMEAT 74
1286c797b6c6SAneesh Kumar K.V #define P9_TUNLINKAT 76
1287c797b6c6SAneesh Kumar K.V
1288c797b6c6SAneesh Kumar K.V static p9_handler *virtio_9p_dotl_handler [] = {
1289c797b6c6SAneesh Kumar K.V [P9_TREADDIR] = virtio_p9_readdir,
1290c797b6c6SAneesh Kumar K.V [P9_TSTATFS] = virtio_p9_statfs,
1291c797b6c6SAneesh Kumar K.V [P9_TGETATTR] = virtio_p9_getattr,
1292c797b6c6SAneesh Kumar K.V [P9_TSETATTR] = virtio_p9_setattr,
1293c797b6c6SAneesh Kumar K.V [P9_TXATTRWALK] = virtio_p9_eopnotsupp,
1294c797b6c6SAneesh Kumar K.V [P9_TXATTRCREATE] = virtio_p9_eopnotsupp,
1295c797b6c6SAneesh Kumar K.V [P9_TMKNOD] = virtio_p9_mknod,
1296c797b6c6SAneesh Kumar K.V [P9_TLOCK] = virtio_p9_lock,
1297c797b6c6SAneesh Kumar K.V [P9_TGETLOCK] = virtio_p9_getlock,
1298c797b6c6SAneesh Kumar K.V [P9_TRENAMEAT] = virtio_p9_renameat,
1299c797b6c6SAneesh Kumar K.V [P9_TREADLINK] = virtio_p9_readlink,
1300c797b6c6SAneesh Kumar K.V [P9_TUNLINKAT] = virtio_p9_unlinkat,
1301c797b6c6SAneesh Kumar K.V [P9_TMKDIR] = virtio_p9_mkdir,
1302b4422bf3SAneesh Kumar K.V [P9_TVERSION] = virtio_p9_version,
1303c797b6c6SAneesh Kumar K.V [P9_TLOPEN] = virtio_p9_open,
1304b4422bf3SAneesh Kumar K.V [P9_TATTACH] = virtio_p9_attach,
1305b4422bf3SAneesh Kumar K.V [P9_TWALK] = virtio_p9_walk,
1306c797b6c6SAneesh Kumar K.V [P9_TCLUNK] = virtio_p9_clunk,
1307c797b6c6SAneesh Kumar K.V [P9_TFSYNC] = virtio_p9_fsync,
1308b4422bf3SAneesh Kumar K.V [P9_TREAD] = virtio_p9_read,
13095cc808aaSSasha Levin [P9_TFLUSH] = virtio_p9_flush,
1310c797b6c6SAneesh Kumar K.V [P9_TLINK] = virtio_p9_link,
1311c797b6c6SAneesh Kumar K.V [P9_TSYMLINK] = virtio_p9_symlink,
1312c797b6c6SAneesh Kumar K.V [P9_TLCREATE] = virtio_p9_create,
1313b4422bf3SAneesh Kumar K.V [P9_TWRITE] = virtio_p9_write,
13146fc5cd9bSSasha Levin [P9_TREMOVE] = virtio_p9_remove,
1315f161f28bSSasha Levin [P9_TRENAME] = virtio_p9_rename,
1316b4422bf3SAneesh Kumar K.V };
1317b4422bf3SAneesh Kumar K.V
virtio_p9_pdu_init(struct kvm * kvm,struct virt_queue * vq)1318af045e53SAneesh Kumar K.V static struct p9_pdu *virtio_p9_pdu_init(struct kvm *kvm, struct virt_queue *vq)
1319af045e53SAneesh Kumar K.V {
1320af045e53SAneesh Kumar K.V struct p9_pdu *pdu = calloc(1, sizeof(*pdu));
1321af045e53SAneesh Kumar K.V if (!pdu)
1322af045e53SAneesh Kumar K.V return NULL;
1323af045e53SAneesh Kumar K.V
1324bfc15268SAneesh Kumar K.V /* skip the pdu header p9_msg */
13255529bcd7SAsias He pdu->read_offset = VIRTIO_9P_HDR_LEN;
13265529bcd7SAsias He pdu->write_offset = VIRTIO_9P_HDR_LEN;
1327af045e53SAneesh Kumar K.V pdu->queue_head = virt_queue__get_inout_iov(kvm, vq, pdu->in_iov,
1328a8a44649SAsias He pdu->out_iov, &pdu->in_iov_cnt, &pdu->out_iov_cnt);
1329af045e53SAneesh Kumar K.V return pdu;
1330af045e53SAneesh Kumar K.V }
1331af045e53SAneesh Kumar K.V
virtio_p9_get_cmd(struct p9_pdu * pdu)1332af045e53SAneesh Kumar K.V static u8 virtio_p9_get_cmd(struct p9_pdu *pdu)
1333af045e53SAneesh Kumar K.V {
1334af045e53SAneesh Kumar K.V struct p9_msg *msg;
1335af045e53SAneesh Kumar K.V /*
1336af045e53SAneesh Kumar K.V * we can peek directly into pdu for a u8
1337af045e53SAneesh Kumar K.V * value. The host endianess won't be an issue
1338af045e53SAneesh Kumar K.V */
1339af045e53SAneesh Kumar K.V msg = pdu->out_iov[0].iov_base;
1340af045e53SAneesh Kumar K.V return msg->cmd;
1341af045e53SAneesh Kumar K.V }
1342af045e53SAneesh Kumar K.V
virtio_p9_do_io_request(struct kvm * kvm,struct p9_dev_job * job)1343b4422bf3SAneesh Kumar K.V static bool virtio_p9_do_io_request(struct kvm *kvm, struct p9_dev_job *job)
13441c7850f9SSasha Levin {
1345af045e53SAneesh Kumar K.V u8 cmd;
1346b4422bf3SAneesh Kumar K.V u32 len = 0;
1347b4422bf3SAneesh Kumar K.V p9_handler *handler;
1348b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev;
1349af045e53SAneesh Kumar K.V struct virt_queue *vq;
1350af045e53SAneesh Kumar K.V struct p9_pdu *p9pdu;
13511c7850f9SSasha Levin
1352b4422bf3SAneesh Kumar K.V vq = job->vq;
1353b4422bf3SAneesh Kumar K.V p9dev = job->p9dev;
13541c7850f9SSasha Levin
1355af045e53SAneesh Kumar K.V p9pdu = virtio_p9_pdu_init(kvm, vq);
1356af045e53SAneesh Kumar K.V cmd = virtio_p9_get_cmd(p9pdu);
1357af045e53SAneesh Kumar K.V
1358c797b6c6SAneesh Kumar K.V if ((cmd >= ARRAY_SIZE(virtio_9p_dotl_handler)) ||
1359c797b6c6SAneesh Kumar K.V !virtio_9p_dotl_handler[cmd])
136097b408afSAneesh Kumar K.V handler = virtio_p9_eopnotsupp;
1361dd78d9eaSAneesh Kumar K.V else
1362c797b6c6SAneesh Kumar K.V handler = virtio_9p_dotl_handler[cmd];
1363c797b6c6SAneesh Kumar K.V
1364af045e53SAneesh Kumar K.V handler(p9dev, p9pdu, &len);
1365af045e53SAneesh Kumar K.V virt_queue__set_used_elem(vq, p9pdu->queue_head, len);
1366af045e53SAneesh Kumar K.V free(p9pdu);
13671c7850f9SSasha Levin return true;
13681c7850f9SSasha Levin }
13691c7850f9SSasha Levin
virtio_p9_do_io(struct kvm * kvm,void * param)13701c7850f9SSasha Levin static void virtio_p9_do_io(struct kvm *kvm, void *param)
13711c7850f9SSasha Levin {
1372b4422bf3SAneesh Kumar K.V struct p9_dev_job *job = (struct p9_dev_job *)param;
1373b4422bf3SAneesh Kumar K.V struct p9_dev *p9dev = job->p9dev;
1374b4422bf3SAneesh Kumar K.V struct virt_queue *vq = job->vq;
13751c7850f9SSasha Levin
13761c7850f9SSasha Levin while (virt_queue__available(vq)) {
1377b4422bf3SAneesh Kumar K.V virtio_p9_do_io_request(kvm, job);
137802eca50cSAsias He p9dev->vdev.ops->signal_vq(kvm, &p9dev->vdev, vq - p9dev->vqs);
13791c7850f9SSasha Levin }
13801c7850f9SSasha Levin }
13811c7850f9SSasha Levin
get_config(struct kvm * kvm,void * dev)1382c5ae742bSSasha Levin static u8 *get_config(struct kvm *kvm, void *dev)
13831c7850f9SSasha Levin {
1384c7838fbdSSasha Levin struct p9_dev *p9dev = dev;
13851c7850f9SSasha Levin
1386c5ae742bSSasha Levin return ((u8 *)(p9dev->config));
1387c7838fbdSSasha Levin }
1388c7838fbdSSasha Levin
get_config_size(struct kvm * kvm,void * dev)1389e4730284SMartin Radev static size_t get_config_size(struct kvm *kvm, void *dev)
1390e4730284SMartin Radev {
1391e4730284SMartin Radev struct p9_dev *p9dev = dev;
1392e4730284SMartin Radev
1393e4730284SMartin Radev return p9dev->config_size;
1394e4730284SMartin Radev }
1395e4730284SMartin Radev
get_host_features(struct kvm * kvm,void * dev)13963c8f82b8SJean-Philippe Brucker static u64 get_host_features(struct kvm *kvm, void *dev)
1397c7838fbdSSasha Levin {
1398c7838fbdSSasha Levin return 1 << VIRTIO_9P_MOUNT_TAG;
1399c7838fbdSSasha Levin }
1400c7838fbdSSasha Levin
notify_status(struct kvm * kvm,void * dev,u32 status)140195242e44SJean-Philippe Brucker static void notify_status(struct kvm *kvm, void *dev, u32 status)
140295242e44SJean-Philippe Brucker {
14038003ede4SJean-Philippe Brucker struct p9_dev *p9dev = dev;
14048003ede4SJean-Philippe Brucker struct p9_fid *pfid, *next;
14058003ede4SJean-Philippe Brucker
1406867b15ccSJean-Philippe Brucker if (status & VIRTIO__STATUS_CONFIG)
1407b17552eeSAndre Przywara p9dev->config->tag_len = virtio_host_to_guest_u16(p9dev->vdev.endian,
1408867b15ccSJean-Philippe Brucker p9dev->tag_len);
1409867b15ccSJean-Philippe Brucker
14108003ede4SJean-Philippe Brucker if (!(status & VIRTIO__STATUS_STOP))
14118003ede4SJean-Philippe Brucker return;
14128003ede4SJean-Philippe Brucker
14138003ede4SJean-Philippe Brucker rbtree_postorder_for_each_entry_safe(pfid, next, &p9dev->fids, node)
14148003ede4SJean-Philippe Brucker close_fid(p9dev, pfid->fid);
141595242e44SJean-Philippe Brucker }
141695242e44SJean-Philippe Brucker
init_vq(struct kvm * kvm,void * dev,u32 vq)1417609ee906SJean-Philippe Brucker static int init_vq(struct kvm *kvm, void *dev, u32 vq)
1418c7838fbdSSasha Levin {
1419c7838fbdSSasha Levin struct p9_dev *p9dev = dev;
1420b4422bf3SAneesh Kumar K.V struct p9_dev_job *job;
1421b4422bf3SAneesh Kumar K.V struct virt_queue *queue;
14221c7850f9SSasha Levin
1423312c62d1SSasha Levin compat__remove_message(compat_id);
1424e59662b3SSasha Levin
1425c7838fbdSSasha Levin queue = &p9dev->vqs[vq];
1426c7838fbdSSasha Levin job = &p9dev->jobs[vq];
14271c7850f9SSasha Levin
1428609ee906SJean-Philippe Brucker virtio_init_device_vq(kvm, &p9dev->vdev, queue, VIRTQUEUE_NUM);
14291c7850f9SSasha Levin
1430b4422bf3SAneesh Kumar K.V *job = (struct p9_dev_job) {
1431b4422bf3SAneesh Kumar K.V .vq = queue,
1432b4422bf3SAneesh Kumar K.V .p9dev = p9dev,
1433b4422bf3SAneesh Kumar K.V };
1434df0c7f57SSasha Levin thread_pool__init_job(&job->job_id, kvm, virtio_p9_do_io, job);
143560eb42d5SSasha Levin
1436c7838fbdSSasha Levin return 0;
14371c7850f9SSasha Levin }
14381c7850f9SSasha Levin
exit_vq(struct kvm * kvm,void * dev,u32 vq)14398003ede4SJean-Philippe Brucker static void exit_vq(struct kvm *kvm, void *dev, u32 vq)
14408003ede4SJean-Philippe Brucker {
14418003ede4SJean-Philippe Brucker struct p9_dev *p9dev = dev;
14428003ede4SJean-Philippe Brucker
14438003ede4SJean-Philippe Brucker thread_pool__cancel_job(&p9dev->jobs[vq].job_id);
14448003ede4SJean-Philippe Brucker }
14458003ede4SJean-Philippe Brucker
notify_vq(struct kvm * kvm,void * dev,u32 vq)1446c7838fbdSSasha Levin static int notify_vq(struct kvm *kvm, void *dev, u32 vq)
1447c7838fbdSSasha Levin {
1448c7838fbdSSasha Levin struct p9_dev *p9dev = dev;
14491c7850f9SSasha Levin
1450c7838fbdSSasha Levin thread_pool__do_job(&p9dev->jobs[vq].job_id);
1451c7838fbdSSasha Levin
1452c7838fbdSSasha Levin return 0;
1453c7838fbdSSasha Levin }
1454c7838fbdSSasha Levin
get_vq(struct kvm * kvm,void * dev,u32 vq)145553fbb17bSJean-Philippe Brucker static struct virt_queue *get_vq(struct kvm *kvm, void *dev, u32 vq)
1456c7838fbdSSasha Levin {
1457c7838fbdSSasha Levin struct p9_dev *p9dev = dev;
1458c7838fbdSSasha Levin
145953fbb17bSJean-Philippe Brucker return &p9dev->vqs[vq];
1460c7838fbdSSasha Levin }
1461c7838fbdSSasha Levin
get_size_vq(struct kvm * kvm,void * dev,u32 vq)1462c7838fbdSSasha Levin static int get_size_vq(struct kvm *kvm, void *dev, u32 vq)
1463c7838fbdSSasha Levin {
1464c7838fbdSSasha Levin return VIRTQUEUE_NUM;
1465c7838fbdSSasha Levin }
1466c7838fbdSSasha Levin
set_size_vq(struct kvm * kvm,void * dev,u32 vq,int size)14677aba29c1SWill Deacon static int set_size_vq(struct kvm *kvm, void *dev, u32 vq, int size)
14687aba29c1SWill Deacon {
14697aba29c1SWill Deacon /* FIXME: dynamic */
14707aba29c1SWill Deacon return size;
14717aba29c1SWill Deacon }
14727aba29c1SWill Deacon
get_vq_count(struct kvm * kvm,void * dev)147331e0eaccSMartin Radev static unsigned int get_vq_count(struct kvm *kvm, void *dev)
1474b98ac591SJean-Philippe Brucker {
1475b98ac591SJean-Philippe Brucker return NUM_VIRT_QUEUES;
1476b98ac591SJean-Philippe Brucker }
1477b98ac591SJean-Philippe Brucker
147815542babSAndre Przywara struct virtio_ops p9_dev_virtio_ops = {
1479c7838fbdSSasha Levin .get_config = get_config,
1480e4730284SMartin Radev .get_config_size = get_config_size,
1481c7838fbdSSasha Levin .get_host_features = get_host_features,
1482c7838fbdSSasha Levin .init_vq = init_vq,
14838003ede4SJean-Philippe Brucker .exit_vq = exit_vq,
148495242e44SJean-Philippe Brucker .notify_status = notify_status,
1485c7838fbdSSasha Levin .notify_vq = notify_vq,
148653fbb17bSJean-Philippe Brucker .get_vq = get_vq,
1487c7838fbdSSasha Levin .get_size_vq = get_size_vq,
14887aba29c1SWill Deacon .set_size_vq = set_size_vq,
1489b98ac591SJean-Philippe Brucker .get_vq_count = get_vq_count,
1490c7838fbdSSasha Levin };
14911c47ce69SSasha Levin
virtio_9p_rootdir_parser(const struct option * opt,const char * arg,int unset)1492cac9e8fdSSasha Levin int virtio_9p_rootdir_parser(const struct option *opt, const char *arg, int unset)
1493cac9e8fdSSasha Levin {
1494cac9e8fdSSasha Levin char *tag_name;
1495cac9e8fdSSasha Levin char tmp[PATH_MAX];
1496cac9e8fdSSasha Levin struct kvm *kvm = opt->ptr;
1497cac9e8fdSSasha Levin
1498cac9e8fdSSasha Levin /*
1499cac9e8fdSSasha Levin * 9p dir can be of the form dirname,tag_name or
1500cac9e8fdSSasha Levin * just dirname. In the later case we use the
1501cac9e8fdSSasha Levin * default tag name
1502cac9e8fdSSasha Levin */
1503cac9e8fdSSasha Levin tag_name = strstr(arg, ",");
1504cac9e8fdSSasha Levin if (tag_name) {
1505cac9e8fdSSasha Levin *tag_name = '\0';
1506cac9e8fdSSasha Levin tag_name++;
1507cac9e8fdSSasha Levin }
1508cac9e8fdSSasha Levin if (realpath(arg, tmp)) {
1509cac9e8fdSSasha Levin if (virtio_9p__register(kvm, tmp, tag_name) < 0)
1510cac9e8fdSSasha Levin die("Unable to initialize virtio 9p");
1511cac9e8fdSSasha Levin } else
1512cac9e8fdSSasha Levin die("Failed resolving 9p path");
1513cac9e8fdSSasha Levin return 0;
1514cac9e8fdSSasha Levin }
1515cac9e8fdSSasha Levin
virtio_9p_img_name_parser(const struct option * opt,const char * arg,int unset)1516cac9e8fdSSasha Levin int virtio_9p_img_name_parser(const struct option *opt, const char *arg, int unset)
1517cac9e8fdSSasha Levin {
1518cac9e8fdSSasha Levin char path[PATH_MAX];
1519cac9e8fdSSasha Levin struct stat st;
1520cac9e8fdSSasha Levin struct kvm *kvm = opt->ptr;
1521cac9e8fdSSasha Levin
1522cac9e8fdSSasha Levin if (stat(arg, &st) == 0 &&
1523cac9e8fdSSasha Levin S_ISDIR(st.st_mode)) {
1524cac9e8fdSSasha Levin char tmp[PATH_MAX];
1525cac9e8fdSSasha Levin
1526cac9e8fdSSasha Levin if (kvm->cfg.using_rootfs)
1527cac9e8fdSSasha Levin die("Please use only one rootfs directory atmost");
1528cac9e8fdSSasha Levin
1529cac9e8fdSSasha Levin if (realpath(arg, tmp) == 0 ||
1530cac9e8fdSSasha Levin virtio_9p__register(kvm, tmp, "/dev/root") < 0)
1531cac9e8fdSSasha Levin die("Unable to initialize virtio 9p");
1532cac9e8fdSSasha Levin kvm->cfg.using_rootfs = 1;
1533cac9e8fdSSasha Levin return 0;
1534cac9e8fdSSasha Levin }
1535cac9e8fdSSasha Levin
1536cac9e8fdSSasha Levin snprintf(path, PATH_MAX, "%s%s", kvm__get_dir(), arg);
1537cac9e8fdSSasha Levin
1538cac9e8fdSSasha Levin if (stat(path, &st) == 0 &&
1539cac9e8fdSSasha Levin S_ISDIR(st.st_mode)) {
1540cac9e8fdSSasha Levin char tmp[PATH_MAX];
1541cac9e8fdSSasha Levin
1542cac9e8fdSSasha Levin if (kvm->cfg.using_rootfs)
1543cac9e8fdSSasha Levin die("Please use only one rootfs directory atmost");
1544cac9e8fdSSasha Levin
1545cac9e8fdSSasha Levin if (realpath(path, tmp) == 0 ||
1546cac9e8fdSSasha Levin virtio_9p__register(kvm, tmp, "/dev/root") < 0)
1547cac9e8fdSSasha Levin die("Unable to initialize virtio 9p");
1548cac9e8fdSSasha Levin if (virtio_9p__register(kvm, "/", "hostfs") < 0)
1549cac9e8fdSSasha Levin die("Unable to initialize virtio 9p");
1550cac9e8fdSSasha Levin kvm_setup_resolv(arg);
1551cac9e8fdSSasha Levin kvm->cfg.using_rootfs = kvm->cfg.custom_rootfs = 1;
1552cac9e8fdSSasha Levin kvm->cfg.custom_rootfs_name = arg;
1553cac9e8fdSSasha Levin return 0;
1554cac9e8fdSSasha Levin }
1555cac9e8fdSSasha Levin
1556cac9e8fdSSasha Levin return -1;
1557cac9e8fdSSasha Levin }
1558cac9e8fdSSasha Levin
virtio_9p__init(struct kvm * kvm)15591c47ce69SSasha Levin int virtio_9p__init(struct kvm *kvm)
15601c47ce69SSasha Levin {
15611c47ce69SSasha Levin struct p9_dev *p9dev;
1562db927775SAlexandru Elisei int r;
15631c47ce69SSasha Levin
15641c47ce69SSasha Levin list_for_each_entry(p9dev, &devs, list) {
1565db927775SAlexandru Elisei r = virtio_init(kvm, p9dev, &p9dev->vdev, &p9_dev_virtio_ops,
15669b46ebc5SRajnesh Kanwal kvm->cfg.virtio_transport, PCI_DEVICE_ID_VIRTIO_9P,
1567ae06ce71SWill Deacon VIRTIO_ID_9P, PCI_CLASS_9P);
1568db927775SAlexandru Elisei if (r < 0)
1569db927775SAlexandru Elisei return r;
1570c7838fbdSSasha Levin }
1571c7838fbdSSasha Levin
1572c7838fbdSSasha Levin return 0;
1573c7838fbdSSasha Levin }
157449a8afd1SSasha Levin virtio_dev_init(virtio_9p__init);
1575c7838fbdSSasha Levin
virtio_9p__exit(struct kvm * kvm)157674af1456SEduardo Bart int virtio_9p__exit(struct kvm *kvm)
157774af1456SEduardo Bart {
157874af1456SEduardo Bart struct p9_dev *p9dev, *tmp;
157974af1456SEduardo Bart
158074af1456SEduardo Bart list_for_each_entry_safe(p9dev, tmp, &devs, list) {
158174af1456SEduardo Bart list_del(&p9dev->list);
158274af1456SEduardo Bart virtio_exit(kvm, &p9dev->vdev);
158374af1456SEduardo Bart free(p9dev);
158474af1456SEduardo Bart }
158574af1456SEduardo Bart
158674af1456SEduardo Bart return 0;
158774af1456SEduardo Bart }
158874af1456SEduardo Bart virtio_dev_exit(virtio_9p__exit);
158974af1456SEduardo Bart
virtio_9p__register(struct kvm * kvm,const char * root,const char * tag_name)1590c7838fbdSSasha Levin int virtio_9p__register(struct kvm *kvm, const char *root, const char *tag_name)
1591c7838fbdSSasha Levin {
1592c7838fbdSSasha Levin struct p9_dev *p9dev;
1593e4730284SMartin Radev size_t tag_length;
1594e4730284SMartin Radev size_t config_size;
1595e4730284SMartin Radev int err;
15961c7850f9SSasha Levin
1597b4422bf3SAneesh Kumar K.V p9dev = calloc(1, sizeof(*p9dev));
1598b4422bf3SAneesh Kumar K.V if (!p9dev)
159954f6802dSPekka Enberg return -ENOMEM;
160054f6802dSPekka Enberg
1601b4422bf3SAneesh Kumar K.V if (!tag_name)
16025529bcd7SAsias He tag_name = VIRTIO_9P_DEFAULT_TAG;
160354f6802dSPekka Enberg
1604e4730284SMartin Radev tag_length = strlen(tag_name);
1605e4730284SMartin Radev /* The tag_name zero byte is intentionally excluded */
1606e4730284SMartin Radev config_size = sizeof(*p9dev->config) + tag_length;
1607e4730284SMartin Radev
1608e4730284SMartin Radev p9dev->config = calloc(1, config_size);
160954f6802dSPekka Enberg if (p9dev->config == NULL) {
161054f6802dSPekka Enberg err = -ENOMEM;
1611b4422bf3SAneesh Kumar K.V goto free_p9dev;
161254f6802dSPekka Enberg }
1613e4730284SMartin Radev p9dev->config_size = config_size;
16141c7850f9SSasha Levin
1615e277a1b4SG. Campana strncpy(p9dev->root_dir, root, sizeof(p9dev->root_dir));
1616e277a1b4SG. Campana p9dev->root_dir[sizeof(p9dev->root_dir)-1] = '\x00';
1617e277a1b4SG. Campana
1618867b15ccSJean-Philippe Brucker p9dev->tag_len = tag_length;
1619867b15ccSJean-Philippe Brucker if (p9dev->tag_len > MAX_TAG_LEN) {
162054f6802dSPekka Enberg err = -EINVAL;
1621b4422bf3SAneesh Kumar K.V goto free_p9dev_config;
162254f6802dSPekka Enberg }
16231c7850f9SSasha Levin
1624e4730284SMartin Radev memcpy(&p9dev->config->tag, tag_name, tag_length);
16251c7850f9SSasha Levin
1626c7838fbdSSasha Levin list_add(&p9dev->list, &devs);
1627b4422bf3SAneesh Kumar K.V
1628d278197dSAsias He if (compat_id == -1)
162952f34d2cSAsias He compat_id = virtio_compat_add_message("virtio-9p", "CONFIG_NET_9P_VIRTIO");
1630e59662b3SSasha Levin
1631e4730284SMartin Radev return 0;
163254f6802dSPekka Enberg
1633b4422bf3SAneesh Kumar K.V free_p9dev_config:
1634b4422bf3SAneesh Kumar K.V free(p9dev->config);
1635b4422bf3SAneesh Kumar K.V free_p9dev:
1636b4422bf3SAneesh Kumar K.V free(p9dev);
163754f6802dSPekka Enberg return err;
16381c7850f9SSasha Levin }
1639