diff options
Diffstat (limited to 'hw/9pfs')
| -rw-r--r-- | hw/9pfs/codir.c | 16 | ||||
| -rw-r--r-- | hw/9pfs/cofile.c | 61 | ||||
| -rw-r--r-- | hw/9pfs/cofs.c | 2 | ||||
| -rw-r--r-- | hw/9pfs/virtio-9p-coth.h | 9 | ||||
| -rw-r--r-- | hw/9pfs/virtio-9p-debug.c | 646 | ||||
| -rw-r--r-- | hw/9pfs/virtio-9p-debug.h | 6 | ||||
| -rw-r--r-- | hw/9pfs/virtio-9p-device.c | 70 | ||||
| -rw-r--r-- | hw/9pfs/virtio-9p-handle.c | 198 | ||||
| -rw-r--r-- | hw/9pfs/virtio-9p-local.c | 215 | ||||
| -rw-r--r-- | hw/9pfs/virtio-9p-synth.c | 571 | ||||
| -rw-r--r-- | hw/9pfs/virtio-9p-synth.h | 50 | ||||
| -rw-r--r-- | hw/9pfs/virtio-9p.c | 232 | ||||
| -rw-r--r-- | hw/9pfs/virtio-9p.h | 62 |
13 files changed, 1254 insertions, 884 deletions
diff --git a/hw/9pfs/codir.c b/hw/9pfs/codir.c index 72732e7c53..9b6d47d91d 100644 --- a/hw/9pfs/codir.c +++ b/hw/9pfs/codir.c @@ -29,7 +29,7 @@ int v9fs_co_readdir_r(V9fsPDU *pdu, V9fsFidState *fidp, struct dirent *dent, v9fs_co_run_in_worker( { errno = 0; - err = s->ops->readdir_r(&s->ctx, fidp->fs.dir, dent, result); + err = s->ops->readdir_r(&s->ctx, &fidp->fs, dent, result); if (!*result && errno) { err = -errno; } else { @@ -49,7 +49,7 @@ off_t v9fs_co_telldir(V9fsPDU *pdu, V9fsFidState *fidp) } v9fs_co_run_in_worker( { - err = s->ops->telldir(&s->ctx, fidp->fs.dir); + err = s->ops->telldir(&s->ctx, &fidp->fs); if (err < 0) { err = -errno; } @@ -65,7 +65,7 @@ void v9fs_co_seekdir(V9fsPDU *pdu, V9fsFidState *fidp, off_t offset) } v9fs_co_run_in_worker( { - s->ops->seekdir(&s->ctx, fidp->fs.dir, offset); + s->ops->seekdir(&s->ctx, &fidp->fs, offset); }); } @@ -77,7 +77,7 @@ void v9fs_co_rewinddir(V9fsPDU *pdu, V9fsFidState *fidp) } v9fs_co_run_in_worker( { - s->ops->rewinddir(&s->ctx, fidp->fs.dir); + s->ops->rewinddir(&s->ctx, &fidp->fs); }); } @@ -129,8 +129,8 @@ int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp) v9fs_path_read_lock(s); v9fs_co_run_in_worker( { - fidp->fs.dir = s->ops->opendir(&s->ctx, &fidp->path); - if (!fidp->fs.dir) { + err = s->ops->opendir(&s->ctx, &fidp->path, &fidp->fs); + if (err < 0) { err = -errno; } else { err = 0; @@ -146,7 +146,7 @@ int v9fs_co_opendir(V9fsPDU *pdu, V9fsFidState *fidp) return err; } -int v9fs_co_closedir(V9fsPDU *pdu, DIR *dir) +int v9fs_co_closedir(V9fsPDU *pdu, V9fsFidOpenState *fs) { int err; V9fsState *s = pdu->s; @@ -156,7 +156,7 @@ int v9fs_co_closedir(V9fsPDU *pdu, DIR *dir) } v9fs_co_run_in_worker( { - err = s->ops->closedir(&s->ctx, dir); + err = s->ops->closedir(&s->ctx, fs); if (err < 0) { err = -errno; } diff --git a/hw/9pfs/cofile.c b/hw/9pfs/cofile.c index 7ad4bec005..586b0382f6 100644 --- a/hw/9pfs/cofile.c +++ b/hw/9pfs/cofile.c @@ -17,6 +17,30 @@ #include "qemu-coroutine.h" #include "virtio-9p-coth.h" +int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t st_mode, + V9fsStatDotl *v9stat) +{ + int err = 0; + V9fsState *s = pdu->s; + + if (v9fs_request_cancelled(pdu)) { + return -EINTR; + } + if (s->ctx.exops.get_st_gen) { + v9fs_path_read_lock(s); + v9fs_co_run_in_worker( + { + err = s->ctx.exops.get_st_gen(&s->ctx, path, st_mode, + &v9stat->st_gen); + if (err < 0) { + err = -errno; + } + }); + v9fs_path_unlock(s); + } + return err; +} + int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf) { int err; @@ -37,7 +61,7 @@ int v9fs_co_lstat(V9fsPDU *pdu, V9fsPath *path, struct stat *stbuf) return err; } -int v9fs_co_fstat(V9fsPDU *pdu, int fd, struct stat *stbuf) +int v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, struct stat *stbuf) { int err; V9fsState *s = pdu->s; @@ -47,7 +71,7 @@ int v9fs_co_fstat(V9fsPDU *pdu, int fd, struct stat *stbuf) } v9fs_co_run_in_worker( { - err = s->ops->fstat(&s->ctx, fd, stbuf); + err = s->ops->fstat(&s->ctx, &fidp->fs, stbuf); if (err < 0) { err = -errno; } @@ -66,8 +90,8 @@ int v9fs_co_open(V9fsPDU *pdu, V9fsFidState *fidp, int flags) v9fs_path_read_lock(s); v9fs_co_run_in_worker( { - fidp->fs.fd = s->ops->open(&s->ctx, &fidp->path, flags); - if (fidp->fs.fd == -1) { + err = s->ops->open(&s->ctx, &fidp->path, flags, &fidp->fs); + if (err == -1) { err = -errno; } else { err = 0; @@ -106,9 +130,9 @@ int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid, v9fs_path_read_lock(s); v9fs_co_run_in_worker( { - fidp->fs.fd = s->ops->open2(&s->ctx, &fidp->path, - name->data, flags, &cred); - if (fidp->fs.fd == -1) { + err = s->ops->open2(&s->ctx, &fidp->path, + name->data, flags, &cred, &fidp->fs); + if (err < 0) { err = -errno; } else { v9fs_path_init(&path); @@ -117,12 +141,12 @@ int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid, err = s->ops->lstat(&s->ctx, &path, stbuf); if (err < 0) { err = -errno; - s->ops->close(&s->ctx, fidp->fs.fd); + s->ops->close(&s->ctx, &fidp->fs); } else { v9fs_path_copy(&fidp->path, &path); } } else { - s->ops->close(&s->ctx, fidp->fs.fd); + s->ops->close(&s->ctx, &fidp->fs); } v9fs_path_free(&path); } @@ -137,7 +161,7 @@ int v9fs_co_open2(V9fsPDU *pdu, V9fsFidState *fidp, V9fsString *name, gid_t gid, return err; } -int v9fs_co_close(V9fsPDU *pdu, int fd) +int v9fs_co_close(V9fsPDU *pdu, V9fsFidOpenState *fs) { int err; V9fsState *s = pdu->s; @@ -147,7 +171,7 @@ int v9fs_co_close(V9fsPDU *pdu, int fd) } v9fs_co_run_in_worker( { - err = s->ops->close(&s->ctx, fd); + err = s->ops->close(&s->ctx, fs); if (err < 0) { err = -errno; } @@ -160,16 +184,15 @@ int v9fs_co_close(V9fsPDU *pdu, int fd) int v9fs_co_fsync(V9fsPDU *pdu, V9fsFidState *fidp, int datasync) { - int fd, err; + int err; V9fsState *s = pdu->s; if (v9fs_request_cancelled(pdu)) { return -EINTR; } - fd = fidp->fs.fd; v9fs_co_run_in_worker( { - err = s->ops->fsync(&s->ctx, fd, datasync); + err = s->ops->fsync(&s->ctx, &fidp->fs, datasync); if (err < 0) { err = -errno; } @@ -202,16 +225,15 @@ int v9fs_co_link(V9fsPDU *pdu, V9fsFidState *oldfid, int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp, struct iovec *iov, int iovcnt, int64_t offset) { - int fd, err; + int err; V9fsState *s = pdu->s; if (v9fs_request_cancelled(pdu)) { return -EINTR; } - fd = fidp->fs.fd; v9fs_co_run_in_worker( { - err = s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset); + err = s->ops->pwritev(&s->ctx, &fidp->fs, iov, iovcnt, offset); if (err < 0) { err = -errno; } @@ -222,16 +244,15 @@ int v9fs_co_pwritev(V9fsPDU *pdu, V9fsFidState *fidp, int v9fs_co_preadv(V9fsPDU *pdu, V9fsFidState *fidp, struct iovec *iov, int iovcnt, int64_t offset) { - int fd, err; + int err; V9fsState *s = pdu->s; if (v9fs_request_cancelled(pdu)) { return -EINTR; } - fd = fidp->fs.fd; v9fs_co_run_in_worker( { - err = s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset); + err = s->ops->preadv(&s->ctx, &fidp->fs, iov, iovcnt, offset); if (err < 0) { err = -errno; } diff --git a/hw/9pfs/cofs.c b/hw/9pfs/cofs.c index 68745add1e..83f125bd47 100644 --- a/hw/9pfs/cofs.c +++ b/hw/9pfs/cofs.c @@ -323,7 +323,7 @@ int v9fs_co_name_to_path(V9fsPDU *pdu, V9fsPath *dirpath, int err; V9fsState *s = pdu->s; - if (s->ctx.flags & PATHNAME_FSCONTEXT) { + if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { err = s->ops->name_to_path(&s->ctx, dirpath, name, path); if (err < 0) { err = -errno; diff --git a/hw/9pfs/virtio-9p-coth.h b/hw/9pfs/virtio-9p-coth.h index 4630080e53..c4b74b0221 100644 --- a/hw/9pfs/virtio-9p-coth.h +++ b/hw/9pfs/virtio-9p-coth.h @@ -80,7 +80,7 @@ extern int v9fs_co_rename(V9fsPDU *, V9fsPath *, V9fsPath *); extern int v9fs_co_unlinkat(V9fsPDU *, V9fsPath *, V9fsString *, int flags); extern int v9fs_co_renameat(V9fsPDU *, V9fsPath *, V9fsString *, V9fsPath *, V9fsString *); -extern int v9fs_co_fstat(V9fsPDU *, int, struct stat *); +extern int v9fs_co_fstat(V9fsPDU *, V9fsFidState *, struct stat *); extern int v9fs_co_opendir(V9fsPDU *, V9fsFidState *); extern int v9fs_co_open(V9fsPDU *, V9fsFidState *, int); extern int v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *, @@ -88,8 +88,8 @@ extern int v9fs_co_open2(V9fsPDU *, V9fsFidState *, V9fsString *, extern int v9fs_co_lsetxattr(V9fsPDU *, V9fsPath *, V9fsString *, void *, size_t, int); extern int v9fs_co_lremovexattr(V9fsPDU *, V9fsPath *, V9fsString *); -extern int v9fs_co_closedir(V9fsPDU *, DIR *); -extern int v9fs_co_close(V9fsPDU *, int); +extern int v9fs_co_closedir(V9fsPDU *, V9fsFidOpenState *); +extern int v9fs_co_close(V9fsPDU *, V9fsFidOpenState *); extern int v9fs_co_fsync(V9fsPDU *, V9fsFidState *, int); extern int v9fs_co_symlink(V9fsPDU *, V9fsFidState *, V9fsString *, const char *, gid_t, struct stat *); @@ -101,4 +101,7 @@ extern int v9fs_co_preadv(V9fsPDU *, V9fsFidState *, struct iovec *, int, int64_t); extern int v9fs_co_name_to_path(V9fsPDU *, V9fsPath *, const char *, V9fsPath *); +extern int v9fs_co_st_gen(V9fsPDU *pdu, V9fsPath *path, mode_t, + V9fsStatDotl *v9stat); + #endif diff --git a/hw/9pfs/virtio-9p-debug.c b/hw/9pfs/virtio-9p-debug.c deleted file mode 100644 index 96925f04a4..0000000000 --- a/hw/9pfs/virtio-9p-debug.c +++ /dev/null @@ -1,646 +0,0 @@ -/* - * Virtio 9p PDU debug - * - * Copyright IBM, Corp. 2010 - * - * Authors: - * Anthony Liguori <aliguori@us.ibm.com> - * - * This work is licensed under the terms of the GNU GPL, version 2. See - * the COPYING file in the top-level directory. - * - */ - -#include "hw/virtio.h" -#include "hw/pc.h" -#include "virtio-9p.h" -#include "virtio-9p-debug.h" - -#define BUG_ON(cond) assert(!(cond)) - -static FILE *llogfile; - -static struct iovec *get_sg(V9fsPDU *pdu, int rx) -{ - if (rx) { - return pdu->elem.in_sg; - } - return pdu->elem.out_sg; -} - -static int get_sg_count(V9fsPDU *pdu, int rx) -{ - if (rx) { - return pdu->elem.in_num; - } - return pdu->elem.out_num; - -} - -static void pprint_int8(V9fsPDU *pdu, int rx, size_t *offsetp, - const char *name) -{ - size_t copied; - int count = get_sg_count(pdu, rx); - size_t offset = *offsetp; - struct iovec *sg = get_sg(pdu, rx); - int8_t value; - - copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); - - BUG_ON(copied != sizeof(value)); - offset += sizeof(value); - fprintf(llogfile, "%s=0x%x", name, value); - *offsetp = offset; -} - -static void pprint_int16(V9fsPDU *pdu, int rx, size_t *offsetp, - const char *name) -{ - size_t copied; - int count = get_sg_count(pdu, rx); - struct iovec *sg = get_sg(pdu, rx); - size_t offset = *offsetp; - int16_t value; - - - copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); - - BUG_ON(copied != sizeof(value)); - offset += sizeof(value); - fprintf(llogfile, "%s=0x%x", name, value); - *offsetp = offset; -} - -static void pprint_int32(V9fsPDU *pdu, int rx, size_t *offsetp, - const char *name) -{ - size_t copied; - int count = get_sg_count(pdu, rx); - struct iovec *sg = get_sg(pdu, rx); - size_t offset = *offsetp; - int32_t value; - - - copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); - - BUG_ON(copied != sizeof(value)); - offset += sizeof(value); - fprintf(llogfile, "%s=0x%x", name, value); - *offsetp = offset; -} - -static void pprint_int64(V9fsPDU *pdu, int rx, size_t *offsetp, - const char *name) -{ - size_t copied; - int count = get_sg_count(pdu, rx); - struct iovec *sg = get_sg(pdu, rx); - size_t offset = *offsetp; - int64_t value; - - - copied = do_pdu_unpack(&value, sg, count, offset, sizeof(value)); - - BUG_ON(copied != sizeof(value)); - offset += sizeof(value); - fprintf(llogfile, "%s=0x%" PRIx64, name, value); - *offsetp = offset; -} - -static void pprint_str(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) -{ - int sg_count = get_sg_count(pdu, rx); - struct iovec *sg = get_sg(pdu, rx); - size_t offset = *offsetp; - uint16_t tmp_size, size; - size_t result; - size_t copied = 0; - int i = 0; - - /* get the size */ - copied = do_pdu_unpack(&tmp_size, sg, sg_count, offset, sizeof(tmp_size)); - BUG_ON(copied != sizeof(tmp_size)); - size = le16_to_cpupu(&tmp_size); - offset += copied; - - fprintf(llogfile, "%s=", name); - for (i = 0; size && i < sg_count; i++) { - size_t len; - if (offset >= sg[i].iov_len) { - /* skip this sg */ - offset -= sg[i].iov_len; - continue; - } else { - len = MIN(sg[i].iov_len - offset, size); - result = fwrite(sg[i].iov_base + offset, 1, len, llogfile); - BUG_ON(result != len); - size -= len; - copied += len; - if (size) { - offset = 0; - continue; - } - } - } - *offsetp += copied; -} - -static void pprint_qid(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) -{ - fprintf(llogfile, "%s={", name); - pprint_int8(pdu, rx, offsetp, "type"); - pprint_int32(pdu, rx, offsetp, ", version"); - pprint_int64(pdu, rx, offsetp, ", path"); - fprintf(llogfile, "}"); -} - -static void pprint_stat(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) -{ - fprintf(llogfile, "%s={", name); - pprint_int16(pdu, rx, offsetp, "size"); - pprint_int16(pdu, rx, offsetp, ", type"); - pprint_int32(pdu, rx, offsetp, ", dev"); - pprint_qid(pdu, rx, offsetp, ", qid"); - pprint_int32(pdu, rx, offsetp, ", mode"); - pprint_int32(pdu, rx, offsetp, ", atime"); - pprint_int32(pdu, rx, offsetp, ", mtime"); - pprint_int64(pdu, rx, offsetp, ", length"); - pprint_str(pdu, rx, offsetp, ", name"); - pprint_str(pdu, rx, offsetp, ", uid"); - pprint_str(pdu, rx, offsetp, ", gid"); - pprint_str(pdu, rx, offsetp, ", muid"); - pprint_str(pdu, rx, offsetp, ", extension"); - pprint_int32(pdu, rx, offsetp, ", uid"); - pprint_int32(pdu, rx, offsetp, ", gid"); - pprint_int32(pdu, rx, offsetp, ", muid"); - fprintf(llogfile, "}"); -} - -static void pprint_stat_dotl(V9fsPDU *pdu, int rx, size_t *offsetp, - const char *name) -{ - fprintf(llogfile, "%s={", name); - pprint_qid(pdu, rx, offsetp, "qid"); - pprint_int32(pdu, rx, offsetp, ", st_mode"); - pprint_int64(pdu, rx, offsetp, ", st_nlink"); - pprint_int32(pdu, rx, offsetp, ", st_uid"); - pprint_int32(pdu, rx, offsetp, ", st_gid"); - pprint_int64(pdu, rx, offsetp, ", st_rdev"); - pprint_int64(pdu, rx, offsetp, ", st_size"); - pprint_int64(pdu, rx, offsetp, ", st_blksize"); - pprint_int64(pdu, rx, offsetp, ", st_blocks"); - pprint_int64(pdu, rx, offsetp, ", atime"); - pprint_int64(pdu, rx, offsetp, ", atime_nsec"); - pprint_int64(pdu, rx, offsetp, ", mtime"); - pprint_int64(pdu, rx, offsetp, ", mtime_nsec"); - pprint_int64(pdu, rx, offsetp, ", ctime"); - pprint_int64(pdu, rx, offsetp, ", ctime_nsec"); - fprintf(llogfile, "}"); -} - - - -static void pprint_strs(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) -{ - int sg_count = get_sg_count(pdu, rx); - struct iovec *sg = get_sg(pdu, rx); - size_t offset = *offsetp; - uint16_t tmp_count, count, i; - size_t copied = 0; - - fprintf(llogfile, "%s={", name); - - /* Get the count */ - copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count)); - BUG_ON(copied != sizeof(tmp_count)); - count = le16_to_cpupu(&tmp_count); - offset += copied; - - for (i = 0; i < count; i++) { - char str[512]; - if (i) { - fprintf(llogfile, ", "); - } - snprintf(str, sizeof(str), "[%d]", i); - pprint_str(pdu, rx, &offset, str); - } - - fprintf(llogfile, "}"); - - *offsetp = offset; -} - -static void pprint_qids(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) -{ - int sg_count = get_sg_count(pdu, rx); - struct iovec *sg = get_sg(pdu, rx); - size_t offset = *offsetp; - uint16_t tmp_count, count, i; - size_t copied = 0; - - fprintf(llogfile, "%s={", name); - - copied = do_pdu_unpack(&tmp_count, sg, sg_count, offset, sizeof(tmp_count)); - BUG_ON(copied != sizeof(tmp_count)); - count = le16_to_cpupu(&tmp_count); - offset += copied; - - for (i = 0; i < count; i++) { - char str[512]; - if (i) { - fprintf(llogfile, ", "); - } - snprintf(str, sizeof(str), "[%d]", i); - pprint_qid(pdu, rx, &offset, str); - } - - fprintf(llogfile, "}"); - - *offsetp = offset; -} - -static void pprint_sg(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) -{ - struct iovec *sg = get_sg(pdu, rx); - unsigned int count; - int i; - - if (rx) { - count = pdu->elem.in_num; - } else { - count = pdu->elem.out_num; - } - - fprintf(llogfile, "%s={", name); - for (i = 0; i < count; i++) { - if (i) { - fprintf(llogfile, ", "); - } - fprintf(llogfile, "(%p, 0x%zx)", sg[i].iov_base, sg[i].iov_len); - } - fprintf(llogfile, "}"); -} - -/* FIXME: read from a directory fid returns serialized stat_t's */ -#ifdef DEBUG_DATA -static void pprint_data(V9fsPDU *pdu, int rx, size_t *offsetp, const char *name) -{ - struct iovec *sg = get_sg(pdu, rx); - size_t offset = *offsetp; - unsigned int count; - int32_t size; - int total, i, j; - ssize_t len; - - if (rx) { - count = pdu->elem.in_num; - } else { - count = pdu->elem.out_num; - } - - BUG_ON((offset + sizeof(size)) > sg[0].iov_len); - - memcpy(&size, sg[0].iov_base + offset, sizeof(size)); - offset += sizeof(size); - - fprintf(llogfile, "size: %x\n", size); - - sg[0].iov_base += 11; /* skip header */ - sg[0].iov_len -= 11; - - total = 0; - for (i = 0; i < count; i++) { - total += sg[i].iov_len; - if (total >= size) { - /* trim sg list so writev does the right thing */ - sg[i].iov_len -= (total - size); - i++; - break; - } - } - - fprintf(llogfile, "%s={\"", name); - fflush(llogfile); - for (j = 0; j < i; j++) { - if (j) { - fprintf(llogfile, "\", \""); - fflush(llogfile); - } - - do { - len = writev(fileno(llogfile), &sg[j], 1); - } while (len == -1 && errno == EINTR); - fprintf(llogfile, "len == %ld: %m\n", len); - BUG_ON(len != sg[j].iov_len); - } - fprintf(llogfile, "\"}"); - - sg[0].iov_base -= 11; - sg[0].iov_len += 11; - -} -#endif - -void pprint_pdu(V9fsPDU *pdu) -{ - size_t offset = 7; - - if (llogfile == NULL) { - llogfile = fopen("/tmp/pdu.log", "w"); - } - - BUG_ON(!llogfile); - - switch (pdu->id) { - case P9_TREADDIR: - fprintf(llogfile, "TREADDIR: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int64(pdu, 0, &offset, ", initial offset"); - pprint_int32(pdu, 0, &offset, ", max count"); - break; - case P9_RREADDIR: - fprintf(llogfile, "RREADDIR: ("); - pprint_int32(pdu, 1, &offset, "count"); -#ifdef DEBUG_DATA - pprint_data(pdu, 1, &offset, ", data"); -#endif - break; - case P9_TMKDIR: - fprintf(llogfile, "TMKDIR: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_str(pdu, 0, &offset, "name"); - pprint_int32(pdu, 0, &offset, "mode"); - pprint_int32(pdu, 0, &offset, "gid"); - break; - case P9_RMKDIR: - fprintf(llogfile, "RMKDIR: ("); - pprint_qid(pdu, 0, &offset, "qid"); - break; - case P9_TVERSION: - fprintf(llogfile, "TVERSION: ("); - pprint_int32(pdu, 0, &offset, "msize"); - pprint_str(pdu, 0, &offset, ", version"); - break; - case P9_RVERSION: - fprintf(llogfile, "RVERSION: ("); - pprint_int32(pdu, 1, &offset, "msize"); - pprint_str(pdu, 1, &offset, ", version"); - break; - case P9_TGETATTR: - fprintf(llogfile, "TGETATTR: ("); - pprint_int32(pdu, 0, &offset, "fid"); - break; - case P9_RGETATTR: - fprintf(llogfile, "RGETATTR: ("); - pprint_stat_dotl(pdu, 1, &offset, "getattr"); - break; - case P9_TAUTH: - fprintf(llogfile, "TAUTH: ("); - pprint_int32(pdu, 0, &offset, "afid"); - pprint_str(pdu, 0, &offset, ", uname"); - pprint_str(pdu, 0, &offset, ", aname"); - pprint_int32(pdu, 0, &offset, ", n_uname"); - break; - case P9_RAUTH: - fprintf(llogfile, "RAUTH: ("); - pprint_qid(pdu, 1, &offset, "qid"); - break; - case P9_TATTACH: - fprintf(llogfile, "TATTACH: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int32(pdu, 0, &offset, ", afid"); - pprint_str(pdu, 0, &offset, ", uname"); - pprint_str(pdu, 0, &offset, ", aname"); - pprint_int32(pdu, 0, &offset, ", n_uname"); - break; - case P9_RATTACH: - fprintf(llogfile, "RATTACH: ("); - pprint_qid(pdu, 1, &offset, "qid"); - break; - case P9_TERROR: - fprintf(llogfile, "TERROR: ("); - break; - case P9_RERROR: - fprintf(llogfile, "RERROR: ("); - pprint_str(pdu, 1, &offset, "ename"); - pprint_int32(pdu, 1, &offset, ", ecode"); - break; - case P9_TFLUSH: - fprintf(llogfile, "TFLUSH: ("); - pprint_int16(pdu, 0, &offset, "oldtag"); - break; - case P9_RFLUSH: - fprintf(llogfile, "RFLUSH: ("); - break; - case P9_TWALK: - fprintf(llogfile, "TWALK: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int32(pdu, 0, &offset, ", newfid"); - pprint_strs(pdu, 0, &offset, ", wnames"); - break; - case P9_RWALK: - fprintf(llogfile, "RWALK: ("); - pprint_qids(pdu, 1, &offset, "wqids"); - break; - case P9_TOPEN: - fprintf(llogfile, "TOPEN: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int8(pdu, 0, &offset, ", mode"); - break; - case P9_ROPEN: - fprintf(llogfile, "ROPEN: ("); - pprint_qid(pdu, 1, &offset, "qid"); - pprint_int32(pdu, 1, &offset, ", iounit"); - break; - case P9_TCREATE: - fprintf(llogfile, "TCREATE: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_str(pdu, 0, &offset, ", name"); - pprint_int32(pdu, 0, &offset, ", perm"); - pprint_int8(pdu, 0, &offset, ", mode"); - pprint_str(pdu, 0, &offset, ", extension"); - break; - case P9_RCREATE: - fprintf(llogfile, "RCREATE: ("); - pprint_qid(pdu, 1, &offset, "qid"); - pprint_int32(pdu, 1, &offset, ", iounit"); - break; - case P9_TSYMLINK: - fprintf(llogfile, "TSYMLINK: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_str(pdu, 0, &offset, ", name"); - pprint_str(pdu, 0, &offset, ", symname"); - pprint_int32(pdu, 0, &offset, ", gid"); - break; - case P9_RSYMLINK: - fprintf(llogfile, "RSYMLINK: ("); - pprint_qid(pdu, 1, &offset, "qid"); - break; - case P9_TLCREATE: - fprintf(llogfile, "TLCREATE: ("); - pprint_int32(pdu, 0, &offset, "dfid"); - pprint_str(pdu, 0, &offset, ", name"); - pprint_int32(pdu, 0, &offset, ", flags"); - pprint_int32(pdu, 0, &offset, ", mode"); - pprint_int32(pdu, 0, &offset, ", gid"); - break; - case P9_RLCREATE: - fprintf(llogfile, "RLCREATE: ("); - pprint_qid(pdu, 1, &offset, "qid"); - pprint_int32(pdu, 1, &offset, ", iounit"); - break; - case P9_TMKNOD: - fprintf(llogfile, "TMKNOD: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_str(pdu, 0, &offset, "name"); - pprint_int32(pdu, 0, &offset, "mode"); - pprint_int32(pdu, 0, &offset, "major"); - pprint_int32(pdu, 0, &offset, "minor"); - pprint_int32(pdu, 0, &offset, "gid"); - break; - case P9_RMKNOD: - fprintf(llogfile, "RMKNOD: )"); - pprint_qid(pdu, 0, &offset, "qid"); - break; - case P9_TREADLINK: - fprintf(llogfile, "TREADLINK: ("); - pprint_int32(pdu, 0, &offset, "fid"); - break; - case P9_RREADLINK: - fprintf(llogfile, "RREADLINK: ("); - pprint_str(pdu, 0, &offset, "target"); - break; - case P9_TREAD: - fprintf(llogfile, "TREAD: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int64(pdu, 0, &offset, ", offset"); - pprint_int32(pdu, 0, &offset, ", count"); - pprint_sg(pdu, 0, &offset, ", sg"); - break; - case P9_RREAD: - fprintf(llogfile, "RREAD: ("); - pprint_int32(pdu, 1, &offset, "count"); - pprint_sg(pdu, 1, &offset, ", sg"); - offset = 7; -#ifdef DEBUG_DATA - pprint_data(pdu, 1, &offset, ", data"); -#endif - break; - case P9_TWRITE: - fprintf(llogfile, "TWRITE: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int64(pdu, 0, &offset, ", offset"); - pprint_int32(pdu, 0, &offset, ", count"); - break; - case P9_RWRITE: - fprintf(llogfile, "RWRITE: ("); - pprint_int32(pdu, 1, &offset, "count"); - break; - case P9_TCLUNK: - fprintf(llogfile, "TCLUNK: ("); - pprint_int32(pdu, 0, &offset, "fid"); - break; - case P9_RCLUNK: - fprintf(llogfile, "RCLUNK: ("); - break; - case P9_TFSYNC: - fprintf(llogfile, "TFSYNC: ("); - pprint_int32(pdu, 0, &offset, "fid"); - break; - case P9_RFSYNC: - fprintf(llogfile, "RFSYNC: ("); - break; - case P9_TLINK: - fprintf(llogfile, "TLINK: ("); - pprint_int32(pdu, 0, &offset, "dfid"); - pprint_int32(pdu, 0, &offset, ", fid"); - pprint_str(pdu, 0, &offset, ", newpath"); - break; - case P9_RLINK: - fprintf(llogfile, "RLINK: ("); - break; - case P9_TREMOVE: - fprintf(llogfile, "TREMOVE: ("); - pprint_int32(pdu, 0, &offset, "fid"); - break; - case P9_RREMOVE: - fprintf(llogfile, "RREMOVE: ("); - break; - case P9_TSTAT: - fprintf(llogfile, "TSTAT: ("); - pprint_int32(pdu, 0, &offset, "fid"); - break; - case P9_RSTAT: - fprintf(llogfile, "RSTAT: ("); - offset += 2; /* ignored */ - pprint_stat(pdu, 1, &offset, "stat"); - break; - case P9_TWSTAT: - fprintf(llogfile, "TWSTAT: ("); - pprint_int32(pdu, 0, &offset, "fid"); - offset += 2; /* ignored */ - pprint_stat(pdu, 0, &offset, ", stat"); - break; - case P9_RWSTAT: - fprintf(llogfile, "RWSTAT: ("); - break; - case P9_TXATTRWALK: - fprintf(llogfile, "TXATTRWALK: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int32(pdu, 0, &offset, ", newfid"); - pprint_str(pdu, 0, &offset, ", xattr name"); - break; - case P9_RXATTRWALK: - fprintf(llogfile, "RXATTRWALK: ("); - pprint_int64(pdu, 1, &offset, "xattrsize"); - case P9_TXATTRCREATE: - fprintf(llogfile, "TXATTRCREATE: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_str(pdu, 0, &offset, ", name"); - pprint_int64(pdu, 0, &offset, ", xattrsize"); - pprint_int32(pdu, 0, &offset, ", flags"); - break; - case P9_RXATTRCREATE: - fprintf(llogfile, "RXATTRCREATE: ("); - break; - case P9_TLOCK: - fprintf(llogfile, "TLOCK: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int8(pdu, 0, &offset, ", type"); - pprint_int32(pdu, 0, &offset, ", flags"); - pprint_int64(pdu, 0, &offset, ", start"); - pprint_int64(pdu, 0, &offset, ", length"); - pprint_int32(pdu, 0, &offset, ", proc_id"); - pprint_str(pdu, 0, &offset, ", client_id"); - break; - case P9_RLOCK: - fprintf(llogfile, "RLOCK: ("); - pprint_int8(pdu, 0, &offset, "status"); - break; - case P9_TGETLOCK: - fprintf(llogfile, "TGETLOCK: ("); - pprint_int32(pdu, 0, &offset, "fid"); - pprint_int8(pdu, 0, &offset, ", type"); - pprint_int64(pdu, 0, &offset, ", start"); - pprint_int64(pdu, 0, &offset, ", length"); - pprint_int32(pdu, 0, &offset, ", proc_id"); - pprint_str(pdu, 0, &offset, ", client_id"); - break; - case P9_RGETLOCK: - fprintf(llogfile, "RGETLOCK: ("); - pprint_int8(pdu, 0, &offset, "type"); - pprint_int64(pdu, 0, &offset, ", start"); - pprint_int64(pdu, 0, &offset, ", length"); - pprint_int32(pdu, 0, &offset, ", proc_id"); - pprint_str(pdu, 0, &offset, ", client_id"); - break; - default: - fprintf(llogfile, "unknown(%d): (", pdu->id); - break; - } - - fprintf(llogfile, ")\n"); - /* Flush the log message out */ - fflush(llogfile); -} diff --git a/hw/9pfs/virtio-9p-debug.h b/hw/9pfs/virtio-9p-debug.h deleted file mode 100644 index d9a249118d..0000000000 --- a/hw/9pfs/virtio-9p-debug.h +++ /dev/null @@ -1,6 +0,0 @@ -#ifndef _QEMU_VIRTIO_9P_DEBUG_H -#define _QEMU_VIRTIO_9P_DEBUG_H - -void pprint_pdu(V9fsPDU *pdu); - -#endif diff --git a/hw/9pfs/virtio-9p-device.c b/hw/9pfs/virtio-9p-device.c index 513e181c82..bba4c54762 100644 --- a/hw/9pfs/virtio-9p-device.c +++ b/hw/9pfs/virtio-9p-device.c @@ -49,7 +49,8 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) V9fsState *s; int i, len; struct stat stat; - FsTypeEntry *fse; + FsDriverEntry *fse; + V9fsPath path; s = (V9fsState *)virtio_common_init("virtio-9p", VIRTIO_ID_9P, @@ -82,55 +83,33 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) exit(1); } - if (!strcmp(fse->security_model, "passthrough")) { - /* Files on the Fileserver set to client user credentials */ - s->ctx.fs_sm = SM_PASSTHROUGH; + s->ctx.export_flags = fse->export_flags; + s->ctx.fs_root = g_strdup(fse->path); + s->ctx.exops.get_st_gen = NULL; + + if (fse->export_flags & V9FS_SM_PASSTHROUGH) { s->ctx.xops = passthrough_xattr_ops; - } else if (!strcmp(fse->security_model, "mapped")) { - /* Files on the fileserver are set to QEMU credentials. - * Client user credentials are saved in extended attributes. - */ - s->ctx.fs_sm = SM_MAPPED; + } else if (fse->export_flags & V9FS_SM_MAPPED) { s->ctx.xops = mapped_xattr_ops; - } else if (!strcmp(fse->security_model, "none")) { - /* - * Files on the fileserver are set to QEMU credentials. - */ - s->ctx.fs_sm = SM_NONE; - s->ctx.xops = none_xattr_ops; - } else { - fprintf(stderr, "Default to security_model=none. You may want" - " enable advanced security model using " - "security option:\n\t security_model=passthrough\n\t " - "security_model=mapped\n"); - s->ctx.fs_sm = SM_NONE; + } else if (fse->export_flags & V9FS_SM_NONE) { s->ctx.xops = none_xattr_ops; } - if (lstat(fse->path, &stat)) { - fprintf(stderr, "share path %s does not exist\n", fse->path); - exit(1); - } else if (!S_ISDIR(stat.st_mode)) { - fprintf(stderr, "share path %s is not a directory\n", fse->path); - exit(1); - } - - s->ctx.fs_root = g_strdup(fse->path); len = strlen(conf->tag); if (len > MAX_TAG_LEN) { - len = MAX_TAG_LEN; + fprintf(stderr, "mount tag '%s' (%d bytes) is longer than " + "maximum (%d bytes)", conf->tag, len, MAX_TAG_LEN); + exit(1); } /* s->tag is non-NULL terminated string */ s->tag = g_malloc(len); memcpy(s->tag, conf->tag, len); s->tag_len = len; s->ctx.uid = -1; - s->ctx.flags = 0; s->ops = fse->ops; s->vdev.get_features = virtio_9p_get_features; - s->config_size = sizeof(struct virtio_9p_config) + - s->tag_len; + s->config_size = sizeof(struct virtio_9p_config) + s->tag_len; s->vdev.get_config = virtio_9p_get_config; s->fid_list = NULL; qemu_co_rwlock_init(&s->rename_lock); @@ -144,6 +123,27 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) fprintf(stderr, "worker thread initialization failed\n"); exit(1); } + + /* + * Check details of export path, We need to use fs driver + * call back to do that. Since we are in the init path, we don't + * use co-routines here. + */ + v9fs_path_init(&path); + if (s->ops->name_to_path(&s->ctx, NULL, "/", &path) < 0) { + fprintf(stderr, + "error in converting name to path %s", strerror(errno)); + exit(1); + } + if (s->ops->lstat(&s->ctx, &path, &stat)) { + fprintf(stderr, "share path %s does not exist\n", fse->path); + exit(1); + } else if (!S_ISDIR(stat.st_mode)) { + fprintf(stderr, "share path %s is not a directory\n", fse->path); + exit(1); + } + v9fs_path_free(&path); + return &s->vdev; } @@ -169,6 +169,8 @@ static PCIDeviceInfo virtio_9p_info = { .revision = VIRTIO_PCI_ABI_VERSION, .class_id = 0x2, .qdev.props = (Property[]) { + DEFINE_PROP_BIT("ioeventfd", VirtIOPCIProxy, flags, + VIRTIO_PCI_FLAG_USE_IOEVENTFD_BIT, true), DEFINE_PROP_UINT32("vectors", VirtIOPCIProxy, nvectors, 2), DEFINE_VIRTIO_COMMON_FEATURES(VirtIOPCIProxy, host_features), DEFINE_PROP_STRING("mount_tag", VirtIOPCIProxy, fsconf.tag), diff --git a/hw/9pfs/virtio-9p-handle.c b/hw/9pfs/virtio-9p-handle.c index 5c8b5ed471..c38e0e7863 100644 --- a/hw/9pfs/virtio-9p-handle.c +++ b/hw/9pfs/virtio-9p-handle.c @@ -21,49 +21,56 @@ #include <sys/un.h> #include <attr/xattr.h> #include <unistd.h> - -struct handle_data { - int mountfd; - int handle_bytes; -}; - -#if __GLIBC__ <= 2 && __GLIBC_MINOR__ < 14 -struct file_handle { - unsigned int handle_bytes; - int handle_type; - unsigned char handle[0]; -}; +#include <linux/fs.h> +#ifdef CONFIG_LINUX_MAGIC_H +#include <linux/magic.h> #endif +#include <sys/ioctl.h> -#ifndef AT_EMPTY_PATH -#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */ +#ifndef XFS_SUPER_MAGIC +#define XFS_SUPER_MAGIC 0x58465342 #endif -#ifndef O_PATH -#define O_PATH 010000000 +#ifndef EXT2_SUPER_MAGIC +#define EXT2_SUPER_MAGIC 0xEF53 #endif - -#ifndef __NR_name_to_handle_at -#if defined(__i386__) -#define __NR_name_to_handle_at 341 -#define __NR_open_by_handle_at 342 -#elif defined(__x86_64__) -#define __NR_name_to_handle_at 303 -#define __NR_open_by_handle_at 304 +#ifndef REISERFS_SUPER_MAGIC +#define REISERFS_SUPER_MAGIC 0x52654973 #endif +#ifndef BTRFS_SUPER_MAGIC +#define BTRFS_SUPER_MAGIC 0x9123683E #endif -#ifdef __NR_name_to_handle_at +struct handle_data { + int mountfd; + int handle_bytes; +}; + +#ifdef CONFIG_OPEN_BY_HANDLE static inline int name_to_handle(int dirfd, const char *name, struct file_handle *fh, int *mnt_id, int flags) { - return syscall(__NR_name_to_handle_at, dirfd, name, fh, mnt_id, flags); + return name_to_handle_at(dirfd, name, fh, mnt_id, flags); } static inline int open_by_handle(int mountfd, const char *fh, int flags) { - return syscall(__NR_open_by_handle_at, mountfd, fh, flags); + return open_by_handle_at(mountfd, (struct file_handle *)fh, flags); } #else + +struct file_handle { + unsigned int handle_bytes; + int handle_type; + unsigned char handle[0]; +}; + +#ifndef AT_EMPTY_PATH +#define AT_EMPTY_PATH 0x1000 /* Allow empty relative pathname */ +#endif +#ifndef O_PATH +#define O_PATH 010000000 +#endif + static inline int name_to_handle(int dirfd, const char *name, struct file_handle *fh, int *mnt_id, int flags) { @@ -126,82 +133,105 @@ static ssize_t handle_readlink(FsContext *fs_ctx, V9fsPath *fs_path, return ret; } -static int handle_close(FsContext *ctx, int fd) +static int handle_close(FsContext *ctx, V9fsFidOpenState *fs) { - return close(fd); + return close(fs->fd); } -static int handle_closedir(FsContext *ctx, DIR *dir) +static int handle_closedir(FsContext *ctx, V9fsFidOpenState *fs) { - return closedir(dir); + return closedir(fs->dir); } -static int handle_open(FsContext *ctx, V9fsPath *fs_path, int flags) +static int handle_open(FsContext *ctx, V9fsPath *fs_path, + int flags, V9fsFidOpenState *fs) { struct handle_data *data = (struct handle_data *)ctx->private; - return open_by_handle(data->mountfd, fs_path->data, flags); + fs->fd = open_by_handle(data->mountfd, fs_path->data, flags); + return fs->fd; } -static DIR *handle_opendir(FsContext *ctx, V9fsPath *fs_path) +static int handle_opendir(FsContext *ctx, + V9fsPath *fs_path, V9fsFidOpenState *fs) { - int fd; - fd = handle_open(ctx, fs_path, O_DIRECTORY); - if (fd < 0) { - return NULL; + int ret; + ret = handle_open(ctx, fs_path, O_DIRECTORY, fs); + if (ret < 0) { + return -1; + } + fs->dir = fdopendir(ret); + if (!fs->dir) { + return -1; } - return fdopendir(fd); + return 0; } -static void handle_rewinddir(FsContext *ctx, DIR *dir) +static void handle_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) { - return rewinddir(dir); + return rewinddir(fs->dir); } -static off_t handle_telldir(FsContext *ctx, DIR *dir) +static off_t handle_telldir(FsContext *ctx, V9fsFidOpenState *fs) { - return telldir(dir); + return telldir(fs->dir); } -static int handle_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry, +static int handle_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, + struct dirent *entry, struct dirent **result) { - return readdir_r(dir, entry, result); + return readdir_r(fs->dir, entry, result); } -static void handle_seekdir(FsContext *ctx, DIR *dir, off_t off) +static void handle_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) { - return seekdir(dir, off); + return seekdir(fs->dir, off); } -static ssize_t handle_preadv(FsContext *ctx, int fd, const struct iovec *iov, +static ssize_t handle_preadv(FsContext *ctx, V9fsFidOpenState *fs, + const struct iovec *iov, int iovcnt, off_t offset) { #ifdef CONFIG_PREADV - return preadv(fd, iov, iovcnt, offset); + return preadv(fs->fd, iov, iovcnt, offset); #else - int err = lseek(fd, offset, SEEK_SET); + int err = lseek(fs->fd, offset, SEEK_SET); if (err == -1) { return err; } else { - return readv(fd, iov, iovcnt); + return readv(fs->fd, iov, iovcnt); } #endif } -static ssize_t handle_pwritev(FsContext *ctx, int fd, const struct iovec *iov, +static ssize_t handle_pwritev(FsContext *ctx, V9fsFidOpenState *fs, + const struct iovec *iov, int iovcnt, off_t offset) { + ssize_t ret; #ifdef CONFIG_PREADV - return pwritev(fd, iov, iovcnt, offset); + ret = pwritev(fs->fd, iov, iovcnt, offset); #else - int err = lseek(fd, offset, SEEK_SET); + int err = lseek(fs->fd, offset, SEEK_SET); if (err == -1) { return err; } else { - return writev(fd, iov, iovcnt); + ret = writev(fs->fd, iov, iovcnt); } #endif +#ifdef CONFIG_SYNC_FILE_RANGE + if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { + /* + * Initiate a writeback. This is not a data integrity sync. + * We want to ensure that we don't leave dirty pages in the cache + * after write when writeout=immediate is sepcified. + */ + sync_file_range(fs->fd, offset, ret, + SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); + } +#endif + return ret; } static int handle_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) @@ -254,13 +284,14 @@ static int handle_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, return ret; } -static int handle_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf) +static int handle_fstat(FsContext *fs_ctx, V9fsFidOpenState *fs, + struct stat *stbuf) { - return fstat(fd, stbuf); + return fstat(fs->fd, stbuf); } static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, - int flags, FsCred *credp) + int flags, FsCred *credp, V9fsFidOpenState *fs) { int ret; int dirfd, fd; @@ -276,6 +307,8 @@ static int handle_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, if (ret < 0) { close(fd); fd = ret; + } else { + fs->fd = fd; } } close(dirfd); @@ -367,7 +400,9 @@ static int handle_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path, const struct timespec *buf) { - int fd, ret; + int ret; +#ifdef CONFIG_UTIMENSAT + int fd; struct handle_data *data = (struct handle_data *)ctx->private; fd = open_by_handle(data->mountfd, fs_path->data, O_NONBLOCK); @@ -376,6 +411,10 @@ static int handle_utimensat(FsContext *ctx, V9fsPath *fs_path, } ret = futimens(fd, buf); close(fd); +#else + ret = -1; + errno = ENOSYS; +#endif return ret; } @@ -385,12 +424,12 @@ static int handle_remove(FsContext *ctx, const char *path) return -1; } -static int handle_fsync(FsContext *ctx, int fd, int datasync) +static int handle_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync) { if (datasync) { - return qemu_fdatasync(fd); + return qemu_fdatasync(fs->fd); } else { - return fsync(fd); + return fsync(fs->fd); } } @@ -546,16 +585,51 @@ static int handle_unlinkat(FsContext *ctx, V9fsPath *dir, return ret; } +static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path, + mode_t st_mode, uint64_t *st_gen) +{ + int err; + V9fsFidOpenState fid_open; + + /* + * Do not try to open special files like device nodes, fifos etc + * We can get fd for regular files and directories only + */ + if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) { + return 0; + } + err = handle_open(ctx, path, O_RDONLY, &fid_open); + if (err < 0) { + return err; + } + err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen); + handle_close(ctx, &fid_open); + return err; +} + static int handle_init(FsContext *ctx) { int ret, mnt_id; + struct statfs stbuf; struct file_handle fh; struct handle_data *data = g_malloc(sizeof(struct handle_data)); + data->mountfd = open(ctx->fs_root, O_DIRECTORY); if (data->mountfd < 0) { ret = data->mountfd; goto err_out; } + ret = statfs(ctx->fs_root, &stbuf); + if (!ret) { + switch (stbuf.f_type) { + case EXT2_SUPER_MAGIC: + case BTRFS_SUPER_MAGIC: + case REISERFS_SUPER_MAGIC: + case XFS_SUPER_MAGIC: + ctx->exops.get_st_gen = handle_ioc_getversion; + break; + } + } memset(&fh, 0, sizeof(struct file_handle)); ret = name_to_handle(data->mountfd, ".", &fh, &mnt_id, 0); if (ret && errno == EOVERFLOW) { diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c index 9559ff6550..782dc0ab21 100644 --- a/hw/9pfs/virtio-9p-local.c +++ b/hw/9pfs/virtio-9p-local.c @@ -20,6 +20,24 @@ #include <sys/socket.h> #include <sys/un.h> #include <attr/xattr.h> +#include <linux/fs.h> +#ifdef CONFIG_LINUX_MAGIC_H +#include <linux/magic.h> +#endif +#include <sys/ioctl.h> + +#ifndef XFS_SUPER_MAGIC +#define XFS_SUPER_MAGIC 0x58465342 +#endif +#ifndef EXT2_SUPER_MAGIC +#define EXT2_SUPER_MAGIC 0xEF53 +#endif +#ifndef REISERFS_SUPER_MAGIC +#define REISERFS_SUPER_MAGIC 0x52654973 +#endif +#ifndef BTRFS_SUPER_MAGIC +#define BTRFS_SUPER_MAGIC 0x9123683E +#endif static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) { @@ -31,7 +49,7 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) if (err) { return err; } - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { /* Actual credentials are part of extended attrs */ uid_t tmp_uid; gid_t tmp_gid; @@ -106,7 +124,7 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path, * If we fail to change ownership and if we are * using security model none. Ignore the error */ - if (fs_ctx->fs_sm != SM_NONE) { + if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { return -1; } } @@ -120,7 +138,7 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, char buffer[PATH_MAX]; char *path = fs_path->data; - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { int fd; fd = open(rpath(fs_ctx, path, buffer), O_RDONLY); if (fd == -1) { @@ -131,88 +149,112 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path, } while (tsize == -1 && errno == EINTR); close(fd); return tsize; - } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || - (fs_ctx->fs_sm == SM_NONE)) { + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { tsize = readlink(rpath(fs_ctx, path, buffer), buf, bufsz); } return tsize; } -static int local_close(FsContext *ctx, int fd) +static int local_close(FsContext *ctx, V9fsFidOpenState *fs) { - return close(fd); + return close(fs->fd); } -static int local_closedir(FsContext *ctx, DIR *dir) +static int local_closedir(FsContext *ctx, V9fsFidOpenState *fs) { - return closedir(dir); + return closedir(fs->dir); } -static int local_open(FsContext *ctx, V9fsPath *fs_path, int flags) +static int local_open(FsContext *ctx, V9fsPath *fs_path, + int flags, V9fsFidOpenState *fs) { char buffer[PATH_MAX]; char *path = fs_path->data; - return open(rpath(ctx, path, buffer), flags); + fs->fd = open(rpath(ctx, path, buffer), flags); + return fs->fd; } -static DIR *local_opendir(FsContext *ctx, V9fsPath *fs_path) +static int local_opendir(FsContext *ctx, + V9fsPath *fs_path, V9fsFidOpenState *fs) { char buffer[PATH_MAX]; char *path = fs_path->data; - return opendir(rpath(ctx, path, buffer)); + fs->dir = opendir(rpath(ctx, path, buffer)); + if (!fs->dir) { + return -1; + } + return 0; } -static void local_rewinddir(FsContext *ctx, DIR *dir) +static void local_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) { - return rewinddir(dir); + return rewinddir(fs->dir); } -static off_t local_telldir(FsContext *ctx, DIR *dir) +static off_t local_telldir(FsContext *ctx, V9fsFidOpenState *fs) { - return telldir(dir); + return telldir(fs->dir); } -static int local_readdir_r(FsContext *ctx, DIR *dir, struct dirent *entry, +static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, + struct dirent *entry, struct dirent **result) { - return readdir_r(dir, entry, result); + return readdir_r(fs->dir, entry, result); } -static void local_seekdir(FsContext *ctx, DIR *dir, off_t off) +static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) { - return seekdir(dir, off); + return seekdir(fs->dir, off); } -static ssize_t local_preadv(FsContext *ctx, int fd, const struct iovec *iov, +static ssize_t local_preadv(FsContext *ctx, V9fsFidOpenState *fs, + const struct iovec *iov, int iovcnt, off_t offset) { #ifdef CONFIG_PREADV - return preadv(fd, iov, iovcnt, offset); + return preadv(fs->fd, iov, iovcnt, offset); #else - int err = lseek(fd, offset, SEEK_SET); + int err = lseek(fs->fd, offset, SEEK_SET); if (err == -1) { return err; } else { - return readv(fd, iov, iovcnt); + return readv(fs->fd, iov, iovcnt); } #endif } -static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov, +static ssize_t local_pwritev(FsContext *ctx, V9fsFidOpenState *fs, + const struct iovec *iov, int iovcnt, off_t offset) { + ssize_t ret +; #ifdef CONFIG_PREADV - return pwritev(fd, iov, iovcnt, offset); + ret = pwritev(fs->fd, iov, iovcnt, offset); #else - int err = lseek(fd, offset, SEEK_SET); + int err = lseek(fs->fd, offset, SEEK_SET); if (err == -1) { return err; } else { - return writev(fd, iov, iovcnt); + ret = writev(fs->fd, iov, iovcnt); } #endif +#ifdef CONFIG_SYNC_FILE_RANGE + if (ret > 0 && ctx->export_flags & V9FS_IMMEDIATE_WRITEOUT) { + /* + * Initiate a writeback. This is not a data integrity sync. + * We want to ensure that we don't leave dirty pages in the cache + * after write when writeout=immediate is sepcified. + */ + sync_file_range(fs->fd, offset, ret, + SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE); + } +#endif + return ret; } static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) @@ -220,10 +262,10 @@ static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) char buffer[PATH_MAX]; char *path = fs_path->data; - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { return local_set_xattr(rpath(fs_ctx, path, buffer), credp); - } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || - (fs_ctx->fs_sm == SM_NONE)) { + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode); } return -1; @@ -243,19 +285,19 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path, path = fullname.data; /* Determine the security model */ - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { err = mknod(rpath(fs_ctx, path, buffer), SM_LOCAL_MODE_BITS|S_IFREG, 0); if (err == -1) { goto out; } - local_set_xattr(rpath(fs_ctx, path, buffer), credp); + err = local_set_xattr(rpath(fs_ctx, path, buffer), credp); if (err == -1) { serrno = errno; goto err_end; } - } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || - (fs_ctx->fs_sm == SM_NONE)) { + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode, credp->fc_rdev); if (err == -1) { @@ -291,7 +333,7 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, path = fullname.data; /* Determine the security model */ - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS); if (err == -1) { goto out; @@ -302,8 +344,8 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path, serrno = errno; goto err_end; } - } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || - (fs_ctx->fs_sm == SM_NONE)) { + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode); if (err == -1) { goto out; @@ -324,30 +366,35 @@ out: return err; } -static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf) +static int local_fstat(FsContext *fs_ctx, + V9fsFidOpenState *fs, struct stat *stbuf) { int err; - err = fstat(fd, stbuf); + err = fstat(fs->fd, stbuf); if (err) { return err; } - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { /* Actual credentials are part of extended attrs */ uid_t tmp_uid; gid_t tmp_gid; mode_t tmp_mode; dev_t tmp_dev; - if (fgetxattr(fd, "user.virtfs.uid", &tmp_uid, sizeof(uid_t)) > 0) { + if (fgetxattr(fs->fd, "user.virtfs.uid", + &tmp_uid, sizeof(uid_t)) > 0) { stbuf->st_uid = tmp_uid; } - if (fgetxattr(fd, "user.virtfs.gid", &tmp_gid, sizeof(gid_t)) > 0) { + if (fgetxattr(fs->fd, "user.virtfs.gid", + &tmp_gid, sizeof(gid_t)) > 0) { stbuf->st_gid = tmp_gid; } - if (fgetxattr(fd, "user.virtfs.mode", &tmp_mode, sizeof(mode_t)) > 0) { + if (fgetxattr(fs->fd, "user.virtfs.mode", + &tmp_mode, sizeof(mode_t)) > 0) { stbuf->st_mode = tmp_mode; } - if (fgetxattr(fd, "user.virtfs.rdev", &tmp_dev, sizeof(dev_t)) > 0) { + if (fgetxattr(fs->fd, "user.virtfs.rdev", + &tmp_dev, sizeof(dev_t)) > 0) { stbuf->st_rdev = tmp_dev; } } @@ -355,7 +402,7 @@ static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf) } static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, - int flags, FsCred *credp) + int flags, FsCred *credp, V9fsFidOpenState *fs) { char *path; int fd = -1; @@ -369,7 +416,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, path = fullname.data; /* Determine the security model */ - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS); if (fd == -1) { err = fd; @@ -382,8 +429,8 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, serrno = errno; goto err_end; } - } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || - (fs_ctx->fs_sm == SM_NONE)) { + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode); if (fd == -1) { err = fd; @@ -396,6 +443,7 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name, } } err = fd; + fs->fd = fd; goto out; err_end: @@ -422,7 +470,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, newpath = fullname.data; /* Determine the security model */ - if (fs_ctx->fs_sm == SM_MAPPED) { + if (fs_ctx->export_flags & V9FS_SM_MAPPED) { int fd; ssize_t oldpath_size, write_size; fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR, @@ -451,8 +499,8 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, serrno = errno; goto err_end; } - } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || - (fs_ctx->fs_sm == SM_NONE)) { + } else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { err = symlink(oldpath, rpath(fs_ctx, newpath, buffer)); if (err) { goto out; @@ -464,7 +512,7 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath, * If we fail to change ownership and if we are * using security model none. Ignore the error */ - if (fs_ctx->fs_sm != SM_NONE) { + if ((fs_ctx->export_flags & V9FS_SEC_MASK) != V9FS_SM_NONE) { serrno = errno; goto err_end; } else @@ -519,15 +567,12 @@ static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp) char *path = fs_path->data; if ((credp->fc_uid == -1 && credp->fc_gid == -1) || - (fs_ctx->fs_sm == SM_PASSTHROUGH)) { - return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid, - credp->fc_gid); - } else if (fs_ctx->fs_sm == SM_MAPPED) { + (fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) || + (fs_ctx->export_flags & V9FS_SM_NONE)) { + return lchown(rpath(fs_ctx, path, buffer), + credp->fc_uid, credp->fc_gid); + } else if (fs_ctx->export_flags & V9FS_SM_MAPPED) { return local_set_xattr(rpath(fs_ctx, path, buffer), credp); - } else if ((fs_ctx->fs_sm == SM_PASSTHROUGH) || - (fs_ctx->fs_sm == SM_NONE)) { - return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid, - credp->fc_gid); } return -1; } @@ -548,12 +593,12 @@ static int local_remove(FsContext *ctx, const char *path) return remove(rpath(ctx, path, buffer)); } -static int local_fsync(FsContext *ctx, int fd, int datasync) +static int local_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync) { if (datasync) { - return qemu_fdatasync(fd); + return qemu_fdatasync(fs->fd); } else { - return fsync(fd); + return fsync(fs->fd); } } @@ -645,10 +690,46 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir, return ret; } +static int local_ioc_getversion(FsContext *ctx, V9fsPath *path, + mode_t st_mode, uint64_t *st_gen) +{ + int err; + V9fsFidOpenState fid_open; + + /* + * Do not try to open special files like device nodes, fifos etc + * We can get fd for regular files and directories only + */ + if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) { + return 0; + } + err = local_open(ctx, path, O_RDONLY, &fid_open); + if (err < 0) { + return err; + } + err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen); + local_close(ctx, &fid_open); + return err; +} + static int local_init(FsContext *ctx) { - ctx->flags |= PATHNAME_FSCONTEXT; - return 0; + int err; + struct statfs stbuf; + + ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT; + err = statfs(ctx->fs_root, &stbuf); + if (!err) { + switch (stbuf.f_type) { + case EXT2_SUPER_MAGIC: + case BTRFS_SUPER_MAGIC: + case REISERFS_SUPER_MAGIC: + case XFS_SUPER_MAGIC: + ctx->exops.get_st_gen = local_ioc_getversion; + break; + } + } + return err; } FileOperations local_ops = { diff --git a/hw/9pfs/virtio-9p-synth.c b/hw/9pfs/virtio-9p-synth.c new file mode 100644 index 0000000000..f573616363 --- /dev/null +++ b/hw/9pfs/virtio-9p-synth.c @@ -0,0 +1,571 @@ +/* + * Virtio 9p synthetic file system support + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Malahal Naineni <malahal@us.ibm.com> + * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include "hw/virtio.h" +#include "virtio-9p.h" +#include "virtio-9p-xattr.h" +#include "fsdev/qemu-fsdev.h" +#include "virtio-9p-synth.h" + +#include <sys/stat.h> + +/* Root node for synth file system */ +V9fsSynthNode v9fs_synth_root = { + .name = "/", + .actual_attr = { + .mode = 0555 | S_IFDIR, + .nlink = 1, + }, + .attr = &v9fs_synth_root.actual_attr, +}; + +static QemuMutex v9fs_synth_mutex; +static int v9fs_synth_node_count; +/* set to 1 when the synth fs is ready */ +static int v9fs_synth_fs; + +static V9fsSynthNode *v9fs_add_dir_node(V9fsSynthNode *parent, int mode, + const char *name, + V9fsSynthNodeAttr *attr, int inode) +{ + V9fsSynthNode *node; + + /* Add directory type and remove write bits */ + mode = ((mode & 0777) | S_IFDIR) & ~(S_IWUSR | S_IWGRP | S_IWOTH); + node = g_malloc0(sizeof(V9fsSynthNode)); + if (attr) { + /* We are adding .. or . entries */ + node->attr = attr; + node->attr->nlink++; + } else { + node->attr = &node->actual_attr; + node->attr->inode = inode; + node->attr->nlink = 1; + /* We don't allow write to directories */ + node->attr->mode = mode; + node->attr->write = NULL; + node->attr->read = NULL; + } + node->private = node; + strncpy(node->name, name, sizeof(node->name)); + QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling); + return node; +} + +int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode, + const char *name, V9fsSynthNode **result) +{ + int ret; + V9fsSynthNode *node, *tmp; + + if (!v9fs_synth_fs) { + return EAGAIN; + } + if (!name || (strlen(name) >= NAME_MAX)) { + return EINVAL; + } + if (!parent) { + parent = &v9fs_synth_root; + } + qemu_mutex_lock(&v9fs_synth_mutex); + QLIST_FOREACH(tmp, &parent->child, sibling) { + if (!strcmp(tmp->name, name)) { + ret = EEXIST; + goto err_out; + } + } + /* Add the name */ + node = v9fs_add_dir_node(parent, mode, name, NULL, v9fs_synth_node_count++); + v9fs_add_dir_node(node, parent->attr->mode, "..", + parent->attr, parent->attr->inode); + v9fs_add_dir_node(node, node->attr->mode, ".", + node->attr, node->attr->inode); + *result = node; + ret = 0; +err_out: + qemu_mutex_unlock(&v9fs_synth_mutex); + return ret; +} + +int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, + const char *name, v9fs_synth_read read, + v9fs_synth_write write, void *arg) +{ + int ret; + V9fsSynthNode *node, *tmp; + + if (!v9fs_synth_fs) { + return EAGAIN; + } + if (!name || (strlen(name) >= NAME_MAX)) { + return EINVAL; + } + if (!parent) { + parent = &v9fs_synth_root; + } + + qemu_mutex_lock(&v9fs_synth_mutex); + QLIST_FOREACH(tmp, &parent->child, sibling) { + if (!strcmp(tmp->name, name)) { + ret = EEXIST; + goto err_out; + } + } + /* Add file type and remove write bits */ + mode = ((mode & 0777) | S_IFREG); + node = g_malloc0(sizeof(V9fsSynthNode)); + node->attr = &node->actual_attr; + node->attr->inode = v9fs_synth_node_count++; + node->attr->nlink = 1; + node->attr->read = read; + node->attr->write = write; + node->attr->mode = mode; + node->private = arg; + strncpy(node->name, name, sizeof(node->name)); + QLIST_INSERT_HEAD_RCU(&parent->child, node, sibling); + ret = 0; +err_out: + qemu_mutex_unlock(&v9fs_synth_mutex); + return ret; +} + +static void v9fs_synth_fill_statbuf(V9fsSynthNode *node, struct stat *stbuf) +{ + stbuf->st_dev = 0; + stbuf->st_ino = node->attr->inode; + stbuf->st_mode = node->attr->mode; + stbuf->st_nlink = node->attr->nlink; + stbuf->st_uid = 0; + stbuf->st_gid = 0; + stbuf->st_rdev = 0; + stbuf->st_size = 0; + stbuf->st_blksize = 0; + stbuf->st_blocks = 0; + stbuf->st_atime = 0; + stbuf->st_mtime = 0; + stbuf->st_ctime = 0; +} + +static int v9fs_synth_lstat(FsContext *fs_ctx, + V9fsPath *fs_path, struct stat *stbuf) +{ + V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data; + + v9fs_synth_fill_statbuf(node, stbuf); + return 0; +} + +static int v9fs_synth_fstat(FsContext *fs_ctx, + V9fsFidOpenState *fs, struct stat *stbuf) +{ + V9fsSynthOpenState *synth_open = fs->private; + v9fs_synth_fill_statbuf(synth_open->node, stbuf); + return 0; +} + +static int v9fs_synth_opendir(FsContext *ctx, + V9fsPath *fs_path, V9fsFidOpenState *fs) +{ + V9fsSynthOpenState *synth_open; + V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data; + + synth_open = g_malloc(sizeof(*synth_open)); + synth_open->node = node; + node->open_count++; + fs->private = synth_open; + return 0; +} + +static int v9fs_synth_closedir(FsContext *ctx, V9fsFidOpenState *fs) +{ + V9fsSynthOpenState *synth_open = fs->private; + V9fsSynthNode *node = synth_open->node; + + node->open_count--; + g_free(synth_open); + fs->private = NULL; + return 0; +} + +static off_t v9fs_synth_telldir(FsContext *ctx, V9fsFidOpenState *fs) +{ + V9fsSynthOpenState *synth_open = fs->private; + return synth_open->offset; +} + +static void v9fs_synth_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off) +{ + V9fsSynthOpenState *synth_open = fs->private; + synth_open->offset = off; +} + +static void v9fs_synth_rewinddir(FsContext *ctx, V9fsFidOpenState *fs) +{ + v9fs_synth_seekdir(ctx, fs, 0); +} + +static void v9fs_synth_direntry(V9fsSynthNode *node, + struct dirent *entry, off_t off) +{ + strcpy(entry->d_name, node->name); + entry->d_ino = node->attr->inode; + entry->d_off = off + 1; +} + +static int v9fs_synth_get_dentry(V9fsSynthNode *dir, struct dirent *entry, + struct dirent **result, off_t off) +{ + int i = 0; + V9fsSynthNode *node; + + rcu_read_lock(); + QLIST_FOREACH(node, &dir->child, sibling) { + /* This is the off child of the directory */ + if (i == off) { + break; + } + i++; + } + rcu_read_unlock(); + if (!node) { + /* end of directory */ + *result = NULL; + return 0; + } + v9fs_synth_direntry(node, entry, off); + *result = entry; + return 0; +} + +static int v9fs_synth_readdir_r(FsContext *ctx, V9fsFidOpenState *fs, + struct dirent *entry, struct dirent **result) +{ + int ret; + V9fsSynthOpenState *synth_open = fs->private; + V9fsSynthNode *node = synth_open->node; + ret = v9fs_synth_get_dentry(node, entry, result, synth_open->offset); + if (!ret && *result != NULL) { + synth_open->offset++; + } + return ret; +} + +static int v9fs_synth_open(FsContext *ctx, V9fsPath *fs_path, + int flags, V9fsFidOpenState *fs) +{ + V9fsSynthOpenState *synth_open; + V9fsSynthNode *node = *(V9fsSynthNode **)fs_path->data; + + synth_open = g_malloc(sizeof(*synth_open)); + synth_open->node = node; + node->open_count++; + fs->private = synth_open; + return 0; +} + +static int v9fs_synth_open2(FsContext *fs_ctx, V9fsPath *dir_path, + const char *name, int flags, + FsCred *credp, V9fsFidOpenState *fs) +{ + errno = ENOSYS; + return -1; +} + +static int v9fs_synth_close(FsContext *ctx, V9fsFidOpenState *fs) +{ + V9fsSynthOpenState *synth_open = fs->private; + V9fsSynthNode *node = synth_open->node; + + node->open_count--; + g_free(synth_open); + fs->private = NULL; + return 0; +} + +static ssize_t v9fs_synth_pwritev(FsContext *ctx, V9fsFidOpenState *fs, + const struct iovec *iov, + int iovcnt, off_t offset) +{ + int i, count = 0, wcount; + V9fsSynthOpenState *synth_open = fs->private; + V9fsSynthNode *node = synth_open->node; + if (!node->attr->write) { + errno = EPERM; + return -1; + } + for (i = 0; i < iovcnt; i++) { + wcount = node->attr->write(iov[i].iov_base, iov[i].iov_len, + offset, node->private); + offset += wcount; + count += wcount; + /* If we wrote less than requested. we are done */ + if (wcount < iov[i].iov_len) { + break; + } + } + return count; +} + +static ssize_t v9fs_synth_preadv(FsContext *ctx, V9fsFidOpenState *fs, + const struct iovec *iov, + int iovcnt, off_t offset) +{ + int i, count = 0, rcount; + V9fsSynthOpenState *synth_open = fs->private; + V9fsSynthNode *node = synth_open->node; + if (!node->attr->read) { + errno = EPERM; + return -1; + } + for (i = 0; i < iovcnt; i++) { + rcount = node->attr->read(iov[i].iov_base, iov[i].iov_len, + offset, node->private); + offset += rcount; + count += rcount; + /* If we read less than requested. we are done */ + if (rcount < iov[i].iov_len) { + break; + } + } + return count; +} + +static int v9fs_synth_truncate(FsContext *ctx, V9fsPath *path, off_t offset) +{ + errno = ENOSYS; + return -1; +} + +static int v9fs_synth_chmod(FsContext *fs_ctx, V9fsPath *path, FsCred *credp) +{ + errno = EPERM; + return -1; +} + +static int v9fs_synth_mknod(FsContext *fs_ctx, V9fsPath *path, + const char *buf, FsCred *credp) +{ + errno = EPERM; + return -1; +} + +static int v9fs_synth_mkdir(FsContext *fs_ctx, V9fsPath *path, + const char *buf, FsCred *credp) +{ + errno = EPERM; + return -1; +} + +static ssize_t v9fs_synth_readlink(FsContext *fs_ctx, V9fsPath *path, + char *buf, size_t bufsz) +{ + errno = ENOSYS; + return -1; +} + +static int v9fs_synth_symlink(FsContext *fs_ctx, const char *oldpath, + V9fsPath *newpath, const char *buf, FsCred *credp) +{ + errno = EPERM; + return -1; +} + +static int v9fs_synth_link(FsContext *fs_ctx, V9fsPath *oldpath, + V9fsPath *newpath, const char *buf) +{ + errno = EPERM; + return -1; +} + +static int v9fs_synth_rename(FsContext *ctx, const char *oldpath, + const char *newpath) +{ + errno = EPERM; + return -1; +} + +static int v9fs_synth_chown(FsContext *fs_ctx, V9fsPath *path, FsCred *credp) +{ + errno = EPERM; + return -1; +} + +static int v9fs_synth_utimensat(FsContext *fs_ctx, V9fsPath *path, + const struct timespec *buf) +{ + errno = EPERM; + return 0; +} + +static int v9fs_synth_remove(FsContext *ctx, const char *path) +{ + errno = EPERM; + return -1; +} + +static int v9fs_synth_fsync(FsContext *ctx, V9fsFidOpenState *fs, int datasync) +{ + errno = ENOSYS; + return 0; +} + +static int v9fs_synth_statfs(FsContext *s, V9fsPath *fs_path, + struct statfs *stbuf) +{ + stbuf->f_type = 0xABCD; + stbuf->f_bsize = 512; + stbuf->f_blocks = 0; + stbuf->f_files = v9fs_synth_node_count; + stbuf->f_namelen = NAME_MAX; + return 0; +} + +static ssize_t v9fs_synth_lgetxattr(FsContext *ctx, V9fsPath *path, + const char *name, void *value, size_t size) +{ + errno = ENOTSUP; + return -1; +} + +static ssize_t v9fs_synth_llistxattr(FsContext *ctx, V9fsPath *path, + void *value, size_t size) +{ + errno = ENOTSUP; + return -1; +} + +static int v9fs_synth_lsetxattr(FsContext *ctx, V9fsPath *path, + const char *name, void *value, + size_t size, int flags) +{ + errno = ENOTSUP; + return -1; +} + +static int v9fs_synth_lremovexattr(FsContext *ctx, + V9fsPath *path, const char *name) +{ + errno = ENOTSUP; + return -1; +} + +static int v9fs_synth_name_to_path(FsContext *ctx, V9fsPath *dir_path, + const char *name, V9fsPath *target) +{ + V9fsSynthNode *node; + V9fsSynthNode *dir_node; + + /* "." and ".." are not allowed */ + if (!strcmp(name, ".") || !strcmp(name, "..")) { + errno = EINVAL; + return -1; + + } + if (!dir_path) { + dir_node = &v9fs_synth_root; + } else { + dir_node = *(V9fsSynthNode **)dir_path->data; + } + if (!strcmp(name, "/")) { + node = dir_node; + goto out; + } + /* search for the name in the childern */ + rcu_read_lock(); + QLIST_FOREACH(node, &dir_node->child, sibling) { + if (!strcmp(node->name, name)) { + break; + } + } + rcu_read_unlock(); + + if (!node) { + errno = ENOENT; + return -1; + } +out: + /* Copy the node pointer to fid */ + target->data = g_malloc(sizeof(void *)); + memcpy(target->data, &node, sizeof(void *)); + target->size = sizeof(void *); + return 0; +} + +static int v9fs_synth_renameat(FsContext *ctx, V9fsPath *olddir, + const char *old_name, V9fsPath *newdir, + const char *new_name) +{ + errno = EPERM; + return -1; +} + +static int v9fs_synth_unlinkat(FsContext *ctx, V9fsPath *dir, + const char *name, int flags) +{ + errno = EPERM; + return -1; +} + +static int v9fs_synth_init(FsContext *ctx) +{ + QLIST_INIT(&v9fs_synth_root.child); + qemu_mutex_init(&v9fs_synth_mutex); + + /* Add "." and ".." entries for root */ + v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode, + "..", v9fs_synth_root.attr, v9fs_synth_root.attr->inode); + v9fs_add_dir_node(&v9fs_synth_root, v9fs_synth_root.attr->mode, + ".", v9fs_synth_root.attr, v9fs_synth_root.attr->inode); + + /* Mark the subsystem is ready for use */ + v9fs_synth_fs = 1; + return 0; +} + +FileOperations synth_ops = { + .init = v9fs_synth_init, + .lstat = v9fs_synth_lstat, + .readlink = v9fs_synth_readlink, + .close = v9fs_synth_close, + .closedir = v9fs_synth_closedir, + .open = v9fs_synth_open, + .opendir = v9fs_synth_opendir, + .rewinddir = v9fs_synth_rewinddir, + .telldir = v9fs_synth_telldir, + .readdir_r = v9fs_synth_readdir_r, + .seekdir = v9fs_synth_seekdir, + .preadv = v9fs_synth_preadv, + .pwritev = v9fs_synth_pwritev, + .chmod = v9fs_synth_chmod, + .mknod = v9fs_synth_mknod, + .mkdir = v9fs_synth_mkdir, + .fstat = v9fs_synth_fstat, + .open2 = v9fs_synth_open2, + .symlink = v9fs_synth_symlink, + .link = v9fs_synth_link, + .truncate = v9fs_synth_truncate, + .rename = v9fs_synth_rename, + .chown = v9fs_synth_chown, + .utimensat = v9fs_synth_utimensat, + .remove = v9fs_synth_remove, + .fsync = v9fs_synth_fsync, + .statfs = v9fs_synth_statfs, + .lgetxattr = v9fs_synth_lgetxattr, + .llistxattr = v9fs_synth_llistxattr, + .lsetxattr = v9fs_synth_lsetxattr, + .lremovexattr = v9fs_synth_lremovexattr, + .name_to_path = v9fs_synth_name_to_path, + .renameat = v9fs_synth_renameat, + .unlinkat = v9fs_synth_unlinkat, +}; diff --git a/hw/9pfs/virtio-9p-synth.h b/hw/9pfs/virtio-9p-synth.h new file mode 100644 index 0000000000..e03f434633 --- /dev/null +++ b/hw/9pfs/virtio-9p-synth.h @@ -0,0 +1,50 @@ +/* + * Virtio 9p + * + * Copyright IBM, Corp. 2011 + * + * Authors: + * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> + * + * This work is licensed under the terms of the GNU GPL, version 2. See + * the COPYING file in the top-level directory. + * + */ + +#include <unistd.h> +#include <sys/types.h> +#include <limits.h> + +typedef struct V9fsSynthNode V9fsSynthNode; +typedef ssize_t (*v9fs_synth_read)(void *buf, int len, off_t offset, + void *arg); +typedef ssize_t (*v9fs_synth_write)(void *buf, int len, off_t offset, + void *arg); +typedef struct V9fsSynthNodeAttr { + int mode; + int inode; + int nlink; + v9fs_synth_read read; + v9fs_synth_write write; +} V9fsSynthNodeAttr; + +struct V9fsSynthNode { + QLIST_HEAD(, V9fsSynthNode) child; + QLIST_ENTRY(V9fsSynthNode) sibling; + char name[NAME_MAX]; + V9fsSynthNodeAttr *attr; + V9fsSynthNodeAttr actual_attr; + void *private; + int open_count; +}; + +typedef struct V9fsSynthOpenState { + off_t offset; + V9fsSynthNode *node; +} V9fsSynthOpenState; + +extern int qemu_v9fs_synth_mkdir(V9fsSynthNode *parent, int mode, + const char *name, V9fsSynthNode **result); +extern int qemu_v9fs_synth_add_file(V9fsSynthNode *parent, int mode, + const char *name, v9fs_synth_read read, + v9fs_synth_write write, void *arg); diff --git a/hw/9pfs/virtio-9p.c b/hw/9pfs/virtio-9p.c index c01c31aa25..0777ece816 100644 --- a/hw/9pfs/virtio-9p.c +++ b/hw/9pfs/virtio-9p.c @@ -17,11 +17,10 @@ #include "hw/virtio-pci.h" #include "virtio-9p.h" #include "fsdev/qemu-fsdev.h" -#include "virtio-9p-debug.h" #include "virtio-9p-xattr.h" #include "virtio-9p-coth.h" +#include "trace.h" -int debug_9p_pdu; int open_fd_hw; int total_open_fd; static int open_fd_rc; @@ -72,6 +71,55 @@ static int omode_to_uflags(int8_t mode) return ret; } +static int dotl_to_at_flags(int flags) +{ + int rflags = 0; + if (flags & P9_DOTL_AT_REMOVEDIR) { + rflags |= AT_REMOVEDIR; + } + return rflags; +} + +struct dotl_openflag_map { + int dotl_flag; + int open_flag; +}; + +static int dotl_to_open_flags(int flags) +{ + int i; + /* + * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY + * and P9_DOTL_NOACCESS + */ + int oflags = flags & O_ACCMODE; + + struct dotl_openflag_map dotl_oflag_map[] = { + { P9_DOTL_CREATE, O_CREAT }, + { P9_DOTL_EXCL, O_EXCL }, + { P9_DOTL_NOCTTY , O_NOCTTY }, + { P9_DOTL_TRUNC, O_TRUNC }, + { P9_DOTL_APPEND, O_APPEND }, + { P9_DOTL_NONBLOCK, O_NONBLOCK } , + { P9_DOTL_DSYNC, O_DSYNC }, + { P9_DOTL_FASYNC, FASYNC }, + { P9_DOTL_DIRECT, O_DIRECT }, + { P9_DOTL_LARGEFILE, O_LARGEFILE }, + { P9_DOTL_DIRECTORY, O_DIRECTORY }, + { P9_DOTL_NOFOLLOW, O_NOFOLLOW }, + { P9_DOTL_NOATIME, O_NOATIME }, + { P9_DOTL_SYNC, O_SYNC }, + }; + + for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) { + if (flags & dotl_oflag_map[i].dotl_flag) { + oflags |= dotl_oflag_map[i].open_flag; + } + } + + return oflags; +} + void cred_init(FsCred *credp) { credp->fc_uid = -1; @@ -80,6 +128,21 @@ void cred_init(FsCred *credp) credp->fc_rdev = -1; } +static int get_dotl_openflags(V9fsState *s, int oflags) +{ + int flags; + /* + * Filter the client open flags + */ + flags = dotl_to_open_flags(oflags); + flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT); + /* + * Ignore direct disk access hint until the server supports it. + */ + flags &= ~O_DIRECT; + return flags; +} + void v9fs_string_init(V9fsString *str) { str->data = NULL; @@ -392,11 +455,11 @@ static int free_fid(V9fsPDU *pdu, V9fsFidState *fidp) if (fidp->fid_type == P9_FID_FILE) { /* If we reclaimed the fd no need to close */ if (fidp->fs.fd != -1) { - retval = v9fs_co_close(pdu, fidp->fs.fd); + retval = v9fs_co_close(pdu, &fidp->fs); } } else if (fidp->fid_type == P9_FID_DIR) { if (fidp->fs.dir != NULL) { - retval = v9fs_co_closedir(pdu, fidp->fs.dir); + retval = v9fs_co_closedir(pdu, &fidp->fs); } } else if (fidp->fid_type == P9_FID_XATTR) { retval = v9fs_xattr_fid_clunk(pdu, fidp); @@ -504,9 +567,9 @@ void v9fs_reclaim_fd(V9fsPDU *pdu) f = reclaim_list; reclaim_list = f->rclm_lst; if (f->fid_type == P9_FID_FILE) { - v9fs_co_close(pdu, f->fs_reclaim.fd); + v9fs_co_close(pdu, &f->fs_reclaim); } else if (f->fid_type == P9_FID_DIR) { - v9fs_co_closedir(pdu, f->fs_reclaim.dir); + v9fs_co_closedir(pdu, &f->fs_reclaim); } f->rclm_lst = NULL; /* @@ -621,9 +684,6 @@ static V9fsPDU *alloc_pdu(V9fsState *s) static void free_pdu(V9fsState *s, V9fsPDU *pdu) { if (pdu) { - if (debug_9p_pdu) { - pprint_pdu(pdu); - } /* * Cancelled pdu are added back to the freelist * by flush request . @@ -909,6 +969,7 @@ static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len) if (s->proto_version == V9FS_PROTO_2000L) { id = P9_RLERROR; } + trace_v9fs_rerror(pdu->tag, pdu->id, err); /* Trace ERROR */ } /* fill out the header */ @@ -1210,6 +1271,11 @@ static void v9fs_fix_path(V9fsPath *dst, V9fsPath *src, int len) dst->size++; } +static inline bool is_ro_export(FsContext *ctx) +{ + return ctx->export_flags & V9FS_RDONLY; +} + static void v9fs_version(void *opaque) { V9fsPDU *pdu = opaque; @@ -1218,6 +1284,7 @@ static void v9fs_version(void *opaque) size_t offset = 7; pdu_unmarshal(pdu, offset, "ds", &s->msize, &version); + trace_v9fs_version(pdu->tag, pdu->id, s->msize, version.data); if (!strcmp(version.data, "9P2000.u")) { s->proto_version = V9FS_PROTO_2000U; @@ -1228,6 +1295,8 @@ static void v9fs_version(void *opaque) } offset += pdu_marshal(pdu, offset, "ds", s->msize, &version); + trace_v9fs_version_return(pdu->tag, pdu->id, s->msize, version.data); + complete_pdu(s, pdu, offset); v9fs_string_free(&version); @@ -1246,6 +1315,7 @@ static void v9fs_attach(void *opaque) ssize_t err; pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname); + trace_v9fs_attach(pdu->tag, pdu->id, fid, afid, uname.data, aname.data); fidp = alloc_fid(s, fid); if (fidp == NULL) { @@ -1267,6 +1337,8 @@ static void v9fs_attach(void *opaque) } offset += pdu_marshal(pdu, offset, "Q", &qid); err = offset; + trace_v9fs_attach_return(pdu->tag, pdu->id, + qid.type, qid.version, qid.path); out: put_fid(pdu, fidp); out_nofid: @@ -1287,6 +1359,7 @@ static void v9fs_stat(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "d", &fid); + trace_v9fs_stat(pdu->tag, pdu->id, fid); fidp = get_fid(pdu, fid); if (fidp == NULL) { @@ -1303,6 +1376,8 @@ static void v9fs_stat(void *opaque) } offset += pdu_marshal(pdu, offset, "wS", 0, &v9stat); err = offset; + trace_v9fs_stat_return(pdu->tag, pdu->id, v9stat.mode, + v9stat.atime, v9stat.mtime, v9stat.length); v9fs_stat_free(&v9stat); out: put_fid(pdu, fidp); @@ -1323,6 +1398,7 @@ static void v9fs_getattr(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "dq", &fid, &request_mask); + trace_v9fs_getattr(pdu->tag, pdu->id, fid, request_mask); fidp = get_fid(pdu, fid); if (fidp == NULL) { @@ -1338,8 +1414,20 @@ static void v9fs_getattr(void *opaque) goto out; } stat_to_v9stat_dotl(s, &stbuf, &v9stat_dotl); + + /* fill st_gen if requested and supported by underlying fs */ + if (request_mask & P9_STATS_GEN) { + retval = v9fs_co_st_gen(pdu, &fidp->path, stbuf.st_mode, &v9stat_dotl); + if (retval < 0) { + goto out; + } + v9stat_dotl.st_result_mask |= P9_STATS_GEN; + } retval = offset; retval += pdu_marshal(pdu, offset, "A", &v9stat_dotl); + trace_v9fs_getattr_return(pdu->tag, pdu->id, v9stat_dotl.st_result_mask, + v9stat_dotl.st_mode, v9stat_dotl.st_uid, + v9stat_dotl.st_gid); out: put_fid(pdu, fidp); out_nofid: @@ -1470,6 +1558,8 @@ static void v9fs_walk(void *opaque) offset += pdu_unmarshal(pdu, offset, "ddw", &fid, &newfid, &nwnames); + trace_v9fs_walk(pdu->tag, pdu->id, fid, newfid, nwnames); + if (nwnames && nwnames <= P9_MAXWELEM) { wnames = g_malloc0(sizeof(wnames[0]) * nwnames); qids = g_malloc0(sizeof(qids[0]) * nwnames); @@ -1518,6 +1608,7 @@ static void v9fs_walk(void *opaque) v9fs_path_copy(&newfidp->path, &path); } err = v9fs_walk_marshal(pdu, nwnames, qids); + trace_v9fs_walk_return(pdu->tag, pdu->id, nwnames, qids); out: put_fid(pdu, fidp); if (newfidp) { @@ -1560,10 +1651,10 @@ static int32_t get_iounit(V9fsPDU *pdu, V9fsPath *path) static void v9fs_open(void *opaque) { int flags; - int iounit; int32_t fid; int32_t mode; V9fsQID qid; + int iounit = 0; ssize_t err = 0; size_t offset = 7; struct stat stbuf; @@ -1576,6 +1667,8 @@ static void v9fs_open(void *opaque) } else { pdu_unmarshal(pdu, offset, "db", &fid, &mode); } + trace_v9fs_open(pdu->tag, pdu->id, fid, mode); + fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -ENOENT; @@ -1598,13 +1691,18 @@ static void v9fs_open(void *opaque) err = offset; } else { if (s->proto_version == V9FS_PROTO_2000L) { - flags = mode; - flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT); - /* Ignore direct disk access hint until the server supports it. */ - flags &= ~O_DIRECT; + flags = get_dotl_openflags(s, mode); } else { flags = omode_to_uflags(mode); } + if (is_ro_export(&s->ctx)) { + if (mode & O_WRONLY || mode & O_RDWR || + mode & O_APPEND || mode & O_TRUNC) { + err = -EROFS; + goto out; + } + flags |= O_NOATIME; + } err = v9fs_co_open(pdu, fidp, flags); if (err < 0) { goto out; @@ -1622,6 +1720,8 @@ static void v9fs_open(void *opaque) offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit); err = offset; } + trace_v9fs_open_return(pdu->tag, pdu->id, + qid.type, qid.version, qid.path, iounit); out: put_fid(pdu, fidp); out_nofid: @@ -1643,6 +1743,7 @@ static void v9fs_lcreate(void *opaque) pdu_unmarshal(pdu, offset, "dsddd", &dfid, &name, &flags, &mode, &gid); + trace_v9fs_lcreate(pdu->tag, pdu->id, dfid, flags, mode, gid); fidp = get_fid(pdu, dfid); if (fidp == NULL) { @@ -1650,8 +1751,7 @@ static void v9fs_lcreate(void *opaque) goto out_nofid; } - /* Ignore direct disk access hint until the server supports it. */ - flags &= ~O_DIRECT; + flags = get_dotl_openflags(pdu->s, flags); err = v9fs_co_open2(pdu, fidp, &name, gid, flags | O_CREAT, mode, &stbuf); if (err < 0) { @@ -1670,6 +1770,8 @@ static void v9fs_lcreate(void *opaque) stat_to_qid(&stbuf, &qid); offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit); err = offset; + trace_v9fs_lcreate_return(pdu->tag, pdu->id, + qid.type, qid.version, qid.path, iounit); out: put_fid(pdu, fidp); out_nofid: @@ -1688,6 +1790,8 @@ static void v9fs_fsync(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "dd", &fid, &datasync); + trace_v9fs_fsync(pdu->tag, pdu->id, fid, datasync); + fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -ENOENT; @@ -1712,6 +1816,7 @@ static void v9fs_clunk(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "d", &fid); + trace_v9fs_clunk(pdu->tag, pdu->id, fid); fidp = clunk_fid(s, fid); if (fidp == NULL) { @@ -1828,6 +1933,7 @@ static void v9fs_read(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "dqd", &fid, &off, &max_count); + trace_v9fs_read(pdu->tag, pdu->id, fid, off, max_count); fidp = get_fid(pdu, fid); if (fidp == NULL) { @@ -1883,6 +1989,7 @@ static void v9fs_read(void *opaque) } else { err = -EINVAL; } + trace_v9fs_read_return(pdu->tag, pdu->id, count, err); out: put_fid(pdu, fidp); out_nofid: @@ -1970,6 +2077,8 @@ static void v9fs_readdir(void *opaque) pdu_unmarshal(pdu, offset, "dqd", &fid, &initial_offset, &max_count); + trace_v9fs_readdir(pdu->tag, pdu->id, fid, initial_offset, max_count); + fidp = get_fid(pdu, fid); if (fidp == NULL) { retval = -EINVAL; @@ -1992,6 +2101,7 @@ static void v9fs_readdir(void *opaque) retval = offset; retval += pdu_marshal(pdu, offset, "d", count); retval += count; + trace_v9fs_readdir_return(pdu->tag, pdu->id, count, retval); out: put_fid(pdu, fidp); out_nofid: @@ -2059,6 +2169,7 @@ static void v9fs_write(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "dqdv", &fid, &off, &count, sg, &cnt); + trace_v9fs_write(pdu->tag, pdu->id, fid, off, count, cnt); fidp = get_fid(pdu, fid); if (fidp == NULL) { @@ -2102,6 +2213,7 @@ static void v9fs_write(void *opaque) } while (total < count && len > 0); offset += pdu_marshal(pdu, offset, "d", total); err = offset; + trace_v9fs_write_return(pdu->tag, pdu->id, total, err); out: put_fid(pdu, fidp); out_nofid: @@ -2129,6 +2241,8 @@ static void v9fs_create(void *opaque) pdu_unmarshal(pdu, offset, "dsdbs", &fid, &name, &perm, &mode, &extension); + trace_v9fs_create(pdu->tag, pdu->id, fid, name.data, perm, mode); + fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -EINVAL; @@ -2259,6 +2373,8 @@ static void v9fs_create(void *opaque) stat_to_qid(&stbuf, &qid); offset += pdu_marshal(pdu, offset, "Qd", &qid, iounit); err = offset; + trace_v9fs_create_return(pdu->tag, pdu->id, + qid.type, qid.version, qid.path, iounit); out: put_fid(pdu, fidp); out_nofid: @@ -2282,6 +2398,7 @@ static void v9fs_symlink(void *opaque) size_t offset = 7; pdu_unmarshal(pdu, offset, "dssd", &dfid, &name, &symname, &gid); + trace_v9fs_symlink(pdu->tag, pdu->id, dfid, name.data, symname.data, gid); dfidp = get_fid(pdu, dfid); if (dfidp == NULL) { @@ -2295,6 +2412,8 @@ static void v9fs_symlink(void *opaque) stat_to_qid(&stbuf, &qid); offset += pdu_marshal(pdu, offset, "Q", &qid); err = offset; + trace_v9fs_symlink_return(pdu->tag, pdu->id, + qid.type, qid.version, qid.path); out: put_fid(pdu, dfidp); out_nofid: @@ -2312,6 +2431,7 @@ static void v9fs_flush(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "w", &tag); + trace_v9fs_flush(pdu->tag, pdu->id, tag); QLIST_FOREACH(cancel_pdu, &s->active_list, next) { if (cancel_pdu->tag == tag) { @@ -2342,6 +2462,7 @@ static void v9fs_link(void *opaque) int err = 0; pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name); + trace_v9fs_link(pdu->tag, pdu->id, dfid, oldfid, name.data); dfidp = get_fid(pdu, dfid); if (dfidp == NULL) { @@ -2375,6 +2496,7 @@ static void v9fs_remove(void *opaque) V9fsPDU *pdu = opaque; pdu_unmarshal(pdu, offset, "d", &fid); + trace_v9fs_remove(pdu->tag, pdu->id, fid); fidp = get_fid(pdu, fid); if (fidp == NULL) { @@ -2382,7 +2504,7 @@ static void v9fs_remove(void *opaque) goto out_nofid; } /* if fs driver is not path based, return EOPNOTSUPP */ - if (!pdu->s->ctx.flags & PATHNAME_FSCONTEXT) { + if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) { err = -EOPNOTSUPP; goto out_err; } @@ -2417,6 +2539,7 @@ static void v9fs_unlinkat(void *opaque) V9fsPDU *pdu = opaque; pdu_unmarshal(pdu, offset, "dsd", &dfid, &name, &flags); + flags = dotl_to_at_flags(flags); dfidp = get_fid(pdu, dfid); if (dfidp == NULL) { @@ -2528,7 +2651,7 @@ static void v9fs_rename(void *opaque) } BUG_ON(fidp->fid_type != P9_FID_NONE); /* if fs driver is not path based, return EOPNOTSUPP */ - if (!pdu->s->ctx.flags & PATHNAME_FSCONTEXT) { + if (!(pdu->s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT)) { err = -EOPNOTSUPP; goto out; } @@ -2601,7 +2724,7 @@ static int v9fs_complete_renameat(V9fsPDU *pdu, int32_t olddirfid, if (err < 0) { goto out; } - if (s->ctx.flags & PATHNAME_FSCONTEXT) { + if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { /* Only for path based fid we need to do the below fixup */ v9fs_fix_fid_paths(pdu, &olddirfidp->path, old_name, &newdirfidp->path, new_name); @@ -2653,6 +2776,8 @@ static void v9fs_wstat(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "dwS", &fid, &unused, &v9stat); + trace_v9fs_wstat(pdu->tag, pdu->id, fid, + v9stat.mode, v9stat.atime, v9stat.mtime); fidp = get_fid(pdu, fid); if (fidp == NULL) { @@ -2821,6 +2946,7 @@ static void v9fs_mknod(void *opaque) pdu_unmarshal(pdu, offset, "dsdddd", &fid, &name, &mode, &major, &minor, &gid); + trace_v9fs_mknod(pdu->tag, pdu->id, fid, mode, major, minor); fidp = get_fid(pdu, fid); if (fidp == NULL) { @@ -2835,6 +2961,8 @@ static void v9fs_mknod(void *opaque) stat_to_qid(&stbuf, &qid); err = offset; err += pdu_marshal(pdu, offset, "Q", &qid); + trace_v9fs_mknod_return(pdu->tag, pdu->id, + qid.type, qid.version, qid.path); out: put_fid(pdu, fidp); out_nofid: @@ -2865,6 +2993,10 @@ static void v9fs_lock(void *opaque) pdu_unmarshal(pdu, offset, "dbdqqds", &fid, &flock->type, &flock->flags, &flock->start, &flock->length, &flock->proc_id, &flock->client_id); + + trace_v9fs_lock(pdu->tag, pdu->id, fid, + flock->type, flock->start, flock->length); + status = P9_LOCK_ERROR; /* We support only block flag now (that too ignored currently) */ @@ -2877,7 +3009,7 @@ static void v9fs_lock(void *opaque) err = -ENOENT; goto out_nofid; } - err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf); + err = v9fs_co_fstat(pdu, fidp, &stbuf); if (err < 0) { goto out; } @@ -2887,6 +3019,7 @@ out: out_nofid: err = offset; err += pdu_marshal(pdu, offset, "b", status); + trace_v9fs_lock_return(pdu->tag, pdu->id, status); complete_pdu(s, pdu, err); v9fs_string_free(&flock->client_id); g_free(flock); @@ -2911,20 +3044,25 @@ static void v9fs_getlock(void *opaque) &glock->start, &glock->length, &glock->proc_id, &glock->client_id); + trace_v9fs_getlock(pdu->tag, pdu->id, fid, + glock->type, glock->start, glock->length); + fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -ENOENT; goto out_nofid; } - err = v9fs_co_fstat(pdu, fidp->fs.fd, &stbuf); + err = v9fs_co_fstat(pdu, fidp, &stbuf); if (err < 0) { goto out; } - glock->type = F_UNLCK; + glock->type = P9_LOCK_TYPE_UNLCK; offset += pdu_marshal(pdu, offset, "bqqds", glock->type, glock->start, glock->length, glock->proc_id, &glock->client_id); err = offset; + trace_v9fs_getlock_return(pdu->tag, pdu->id, glock->type, glock->start, + glock->length, glock->proc_id); out: put_fid(pdu, fidp); out_nofid: @@ -2948,6 +3086,8 @@ static void v9fs_mkdir(void *opaque) pdu_unmarshal(pdu, offset, "dsdd", &fid, &name, &mode, &gid); + trace_v9fs_mkdir(pdu->tag, pdu->id, fid, name.data, mode, gid); + fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -ENOENT; @@ -2960,6 +3100,8 @@ static void v9fs_mkdir(void *opaque) stat_to_qid(&stbuf, &qid); offset += pdu_marshal(pdu, offset, "Q", &qid); err = offset; + trace_v9fs_mkdir_return(pdu->tag, pdu->id, + qid.type, qid.version, qid.path, err); out: put_fid(pdu, fidp); out_nofid: @@ -2980,6 +3122,8 @@ static void v9fs_xattrwalk(void *opaque) V9fsState *s = pdu->s; pdu_unmarshal(pdu, offset, "dds", &fid, &newfid, &name); + trace_v9fs_xattrwalk(pdu->tag, pdu->id, fid, newfid, name.data); + file_fidp = get_fid(pdu, fid); if (file_fidp == NULL) { err = -ENOENT; @@ -3050,6 +3194,7 @@ static void v9fs_xattrwalk(void *opaque) offset += pdu_marshal(pdu, offset, "q", size); err = offset; } + trace_v9fs_xattrwalk_return(pdu->tag, pdu->id, size); out: put_fid(pdu, file_fidp); if (xattr_fidp) { @@ -3075,6 +3220,7 @@ static void v9fs_xattrcreate(void *opaque) pdu_unmarshal(pdu, offset, "dsqd", &fid, &name, &size, &flags); + trace_v9fs_xattrcreate(pdu->tag, pdu->id, fid, name.data, size, flags); file_fidp = get_fid(pdu, fid); if (file_fidp == NULL) { @@ -3111,6 +3257,7 @@ static void v9fs_readlink(void *opaque) V9fsFidState *fidp; pdu_unmarshal(pdu, offset, "d", &fid); + trace_v9fs_readlink(pdu->tag, pdu->id, fid); fidp = get_fid(pdu, fid); if (fidp == NULL) { err = -ENOENT; @@ -3124,6 +3271,7 @@ static void v9fs_readlink(void *opaque) } offset += pdu_marshal(pdu, offset, "s", &target); err = offset; + trace_v9fs_readlink_return(pdu->tag, pdu->id, target.data); v9fs_string_free(&target); out: put_fid(pdu, fidp); @@ -3174,20 +3322,54 @@ static void v9fs_op_not_supp(void *opaque) complete_pdu(pdu->s, pdu, -EOPNOTSUPP); } +static void v9fs_fs_ro(void *opaque) +{ + V9fsPDU *pdu = opaque; + complete_pdu(pdu->s, pdu, -EROFS); +} + +static inline bool is_read_only_op(V9fsPDU *pdu) +{ + switch (pdu->id) { + case P9_TREADDIR: + case P9_TSTATFS: + case P9_TGETATTR: + case P9_TXATTRWALK: + case P9_TLOCK: + case P9_TGETLOCK: + case P9_TREADLINK: + case P9_TVERSION: + case P9_TLOPEN: + case P9_TATTACH: + case P9_TSTAT: + case P9_TWALK: + case P9_TCLUNK: + case P9_TFSYNC: + case P9_TOPEN: + case P9_TREAD: + case P9_TAUTH: + case P9_TFLUSH: + return 1; + default: + return 0; + } +} + static void submit_pdu(V9fsState *s, V9fsPDU *pdu) { Coroutine *co; CoroutineEntry *handler; - if (debug_9p_pdu) { - pprint_pdu(pdu); - } if (pdu->id >= ARRAY_SIZE(pdu_co_handlers) || (pdu_co_handlers[pdu->id] == NULL)) { handler = v9fs_op_not_supp; } else { handler = pdu_co_handlers[pdu->id]; } + + if (is_ro_export(&s->ctx) && !is_read_only_op(pdu)) { + handler = v9fs_fs_ro; + } co = qemu_coroutine_create(handler); qemu_coroutine_enter(co, pdu); } diff --git a/hw/9pfs/virtio-9p.h b/hw/9pfs/virtio-9p.h index 60b8a56e57..7f883563d6 100644 --- a/hw/9pfs/virtio-9p.h +++ b/hw/9pfs/virtio-9p.h @@ -204,20 +204,29 @@ typedef struct V9fsXattr int flags; } V9fsXattr; +/* + * Filled by fs driver on open and other + * calls. + */ +union V9fsFidOpenState { + int fd; + DIR *dir; + V9fsXattr xattr; + /* + * private pointer for fs drivers, that + * have its own internal representation of + * open files. + */ + void *private; +}; + struct V9fsFidState { int fid_type; int32_t fid; V9fsPath path; - union { - int fd; - DIR *dir; - V9fsXattr xattr; - } fs; - union { - int fd; - DIR *dir; - } fs_reclaim; + V9fsFidOpenState fs; + V9fsFidOpenState fs_reclaim; int flags; int open_flags; uid_t uid; @@ -352,6 +361,35 @@ typedef struct V9fsMkState { V9fsString fullname; } V9fsMkState; +/* 9p2000.L open flags */ +#define P9_DOTL_RDONLY 00000000 +#define P9_DOTL_WRONLY 00000001 +#define P9_DOTL_RDWR 00000002 +#define P9_DOTL_NOACCESS 00000003 +#define P9_DOTL_CREATE 00000100 +#define P9_DOTL_EXCL 00000200 +#define P9_DOTL_NOCTTY 00000400 +#define P9_DOTL_TRUNC 00001000 +#define P9_DOTL_APPEND 00002000 +#define P9_DOTL_NONBLOCK 00004000 +#define P9_DOTL_DSYNC 00010000 +#define P9_DOTL_FASYNC 00020000 +#define P9_DOTL_DIRECT 00040000 +#define P9_DOTL_LARGEFILE 00100000 +#define P9_DOTL_DIRECTORY 00200000 +#define P9_DOTL_NOFOLLOW 00400000 +#define P9_DOTL_NOATIME 01000000 +#define P9_DOTL_CLOEXEC 02000000 +#define P9_DOTL_SYNC 04000000 + +/* 9p2000.L at flags */ +#define P9_DOTL_AT_REMOVEDIR 0x200 + +/* 9P2000.L lock type */ +#define P9_LOCK_TYPE_RDLCK 0 +#define P9_LOCK_TYPE_WRLCK 1 +#define P9_LOCK_TYPE_UNLCK 2 + #define P9_LOCK_SUCCESS 0 #define P9_LOCK_BLOCKED 1 #define P9_LOCK_ERROR 2 @@ -393,21 +431,21 @@ static inline size_t do_pdu_unpack(void *dst, struct iovec *sg, int sg_count, static inline void v9fs_path_write_lock(V9fsState *s) { - if (s->ctx.flags & PATHNAME_FSCONTEXT) { + if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { qemu_co_rwlock_wrlock(&s->rename_lock); } } static inline void v9fs_path_read_lock(V9fsState *s) { - if (s->ctx.flags & PATHNAME_FSCONTEXT) { + if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { qemu_co_rwlock_rdlock(&s->rename_lock); } } static inline void v9fs_path_unlock(V9fsState *s) { - if (s->ctx.flags & PATHNAME_FSCONTEXT) { + if (s->ctx.export_flags & V9FS_PATHNAME_FSCONTEXT) { qemu_co_rwlock_unlock(&s->rename_lock); } } |