Merge remote-tracking branch 'aneesh/for-upstream-7' into staging
This commit is contained in:
		
						commit
						d439b79d73
					
				| 
						 | 
				
			
			@ -310,6 +310,7 @@ hw-obj-$(CONFIG_SOUND) += $(sound-obj-y)
 | 
			
		|||
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-xattr-user.o virtio-9p-posix-acl.o
 | 
			
		||||
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-coth.o cofs.o codir.o cofile.o
 | 
			
		||||
9pfs-nested-$(CONFIG_VIRTFS) += coxattr.o virtio-9p-handle.o
 | 
			
		||||
9pfs-nested-$(CONFIG_VIRTFS) += virtio-9p-synth.o
 | 
			
		||||
 | 
			
		||||
hw-obj-$(CONFIG_REALLY_VIRTFS) += $(addprefix 9pfs/, $(9pfs-nested-y))
 | 
			
		||||
$(addprefix 9pfs/, $(9pfs-nested-y)): QEMU_CFLAGS+=$(GLIB_CFLAGS)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -2562,7 +2562,7 @@ fi
 | 
			
		|||
open_by_hande_at=no
 | 
			
		||||
cat > $TMPC << EOF
 | 
			
		||||
#include <fcntl.h>
 | 
			
		||||
int main(void) { struct file_handle *fh; open_by_handle_at(0, fh, 0); }
 | 
			
		||||
int main(void) { struct file_handle fh; open_by_handle_at(0, &fh, 0); }
 | 
			
		||||
EOF
 | 
			
		||||
if compile_prog "" "" ; then
 | 
			
		||||
    open_by_handle_at=yes
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -56,10 +56,12 @@ typedef struct extended_ops {
 | 
			
		|||
 * On failure ignore the error.
 | 
			
		||||
 */
 | 
			
		||||
#define V9FS_SM_NONE                0x00000010
 | 
			
		||||
 | 
			
		||||
#define V9FS_RDONLY                 0x00000020
 | 
			
		||||
 | 
			
		||||
#define V9FS_SEC_MASK               0x0000001C
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
typedef struct FsContext
 | 
			
		||||
{
 | 
			
		||||
    uid_t uid;
 | 
			
		||||
| 
						 | 
				
			
			@ -76,6 +78,8 @@ typedef struct V9fsPath {
 | 
			
		|||
    char *data;
 | 
			
		||||
} V9fsPath;
 | 
			
		||||
 | 
			
		||||
typedef union V9fsFidOpenState V9fsFidOpenState;
 | 
			
		||||
 | 
			
		||||
void cred_init(FsCred *);
 | 
			
		||||
 | 
			
		||||
typedef struct FileOperations
 | 
			
		||||
| 
						 | 
				
			
			@ -92,22 +96,26 @@ typedef struct FileOperations
 | 
			
		|||
                   const char *, FsCred *);
 | 
			
		||||
    int (*link)(FsContext *, V9fsPath *, V9fsPath *, const char *);
 | 
			
		||||
    int (*setuid)(FsContext *, uid_t);
 | 
			
		||||
    int (*close)(FsContext *, int);
 | 
			
		||||
    int (*closedir)(FsContext *, DIR *);
 | 
			
		||||
    DIR *(*opendir)(FsContext *, V9fsPath *);
 | 
			
		||||
    int (*open)(FsContext *, V9fsPath *, int);
 | 
			
		||||
    int (*open2)(FsContext *, V9fsPath *, const char *, int, FsCred *);
 | 
			
		||||
    void (*rewinddir)(FsContext *, DIR *);
 | 
			
		||||
    off_t (*telldir)(FsContext *, DIR *);
 | 
			
		||||
    int (*readdir_r)(FsContext *, DIR *, struct dirent *, struct dirent **);
 | 
			
		||||
    void (*seekdir)(FsContext *, DIR *, off_t);
 | 
			
		||||
    ssize_t (*preadv)(FsContext *, int, const struct iovec *, int, off_t);
 | 
			
		||||
    ssize_t (*pwritev)(FsContext *, int, const struct iovec *, int, off_t);
 | 
			
		||||
    int (*close)(FsContext *, V9fsFidOpenState *);
 | 
			
		||||
    int (*closedir)(FsContext *, V9fsFidOpenState *);
 | 
			
		||||
    int (*opendir)(FsContext *, V9fsPath *, V9fsFidOpenState *);
 | 
			
		||||
    int (*open)(FsContext *, V9fsPath *, int, V9fsFidOpenState *);
 | 
			
		||||
    int (*open2)(FsContext *, V9fsPath *, const char *,
 | 
			
		||||
                 int, FsCred *, V9fsFidOpenState *);
 | 
			
		||||
    void (*rewinddir)(FsContext *, V9fsFidOpenState *);
 | 
			
		||||
    off_t (*telldir)(FsContext *, V9fsFidOpenState *);
 | 
			
		||||
    int (*readdir_r)(FsContext *, V9fsFidOpenState *,
 | 
			
		||||
                     struct dirent *, struct dirent **);
 | 
			
		||||
    void (*seekdir)(FsContext *, V9fsFidOpenState *, off_t);
 | 
			
		||||
    ssize_t (*preadv)(FsContext *, V9fsFidOpenState *,
 | 
			
		||||
                      const struct iovec *, int, off_t);
 | 
			
		||||
    ssize_t (*pwritev)(FsContext *, V9fsFidOpenState *,
 | 
			
		||||
                       const struct iovec *, int, off_t);
 | 
			
		||||
    int (*mkdir)(FsContext *, V9fsPath *, const char *, FsCred *);
 | 
			
		||||
    int (*fstat)(FsContext *, int, struct stat *);
 | 
			
		||||
    int (*fstat)(FsContext *, V9fsFidOpenState *, struct stat *);
 | 
			
		||||
    int (*rename)(FsContext *, const char *, const char *);
 | 
			
		||||
    int (*truncate)(FsContext *, V9fsPath *, off_t);
 | 
			
		||||
    int (*fsync)(FsContext *, int, int);
 | 
			
		||||
    int (*fsync)(FsContext *, V9fsFidOpenState *, int);
 | 
			
		||||
    int (*statfs)(FsContext *s, V9fsPath *path, struct statfs *stbuf);
 | 
			
		||||
    ssize_t (*lgetxattr)(FsContext *, V9fsPath *,
 | 
			
		||||
                         const char *, void *, size_t);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -24,6 +24,7 @@ static QTAILQ_HEAD(FsDriverEntry_head, FsDriverListEntry) fsdriver_entries =
 | 
			
		|||
static FsDriverTable FsDrivers[] = {
 | 
			
		||||
    { .name = "local", .ops = &local_ops},
 | 
			
		||||
    { .name = "handle", .ops = &handle_ops},
 | 
			
		||||
    { .name = "synth", .ops = &synth_ops},
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
int qemu_fsdev_add(QemuOpts *opts)
 | 
			
		||||
| 
						 | 
				
			
			@ -35,7 +36,7 @@ int qemu_fsdev_add(QemuOpts *opts)
 | 
			
		|||
    const char *path = qemu_opt_get(opts, "path");
 | 
			
		||||
    const char *sec_model = qemu_opt_get(opts, "security_model");
 | 
			
		||||
    const char *writeout = qemu_opt_get(opts, "writeout");
 | 
			
		||||
 | 
			
		||||
    bool ro = qemu_opt_get_bool(opts, "readonly", 0);
 | 
			
		||||
 | 
			
		||||
    if (!fsdev_id) {
 | 
			
		||||
        fprintf(stderr, "fsdev: No id specified\n");
 | 
			
		||||
| 
						 | 
				
			
			@ -86,6 +87,11 @@ int qemu_fsdev_add(QemuOpts *opts)
 | 
			
		|||
            fsle->fse.export_flags |= V9FS_IMMEDIATE_WRITEOUT;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (ro) {
 | 
			
		||||
        fsle->fse.export_flags |= V9FS_RDONLY;
 | 
			
		||||
    } else {
 | 
			
		||||
        fsle->fse.export_flags &= ~V9FS_RDONLY;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (strcmp(fsdriver, "local")) {
 | 
			
		||||
        goto done;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -53,4 +53,5 @@ int qemu_fsdev_add(QemuOpts *opts);
 | 
			
		|||
FsDriverEntry *get_fsdev_fsentry(char *id);
 | 
			
		||||
extern FileOperations local_ops;
 | 
			
		||||
extern FileOperations handle_ops;
 | 
			
		||||
extern FileOperations synth_ops;
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -61,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -71,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;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -90,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -130,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);
 | 
			
		||||
| 
						 | 
				
			
			@ -141,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);
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -161,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -171,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;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -184,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;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -226,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;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			@ -246,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;
 | 
			
		||||
            }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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 *);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -133,81 +133,91 @@ 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;
 | 
			
		||||
    }
 | 
			
		||||
    return fdopendir(fd);
 | 
			
		||||
    fs->dir = fdopendir(ret);
 | 
			
		||||
    if (!fs->dir) {
 | 
			
		||||
        return -1;
 | 
			
		||||
    }
 | 
			
		||||
    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
 | 
			
		||||
    ret = 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 {
 | 
			
		||||
        ret = writev(fd, iov, iovcnt);
 | 
			
		||||
        ret = writev(fs->fd, iov, iovcnt);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CONFIG_SYNC_FILE_RANGE
 | 
			
		||||
| 
						 | 
				
			
			@ -217,7 +227,7 @@ static ssize_t handle_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
 | 
			
		|||
         * We want to ensure that we don't leave dirty pages in the cache
 | 
			
		||||
         * after write when writeout=immediate is sepcified.
 | 
			
		||||
         */
 | 
			
		||||
        sync_file_range(fd, offset, ret,
 | 
			
		||||
        sync_file_range(fs->fd, offset, ret,
 | 
			
		||||
                        SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -274,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -296,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);
 | 
			
		||||
| 
						 | 
				
			
			@ -411,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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -575,7 +588,8 @@ static int handle_unlinkat(FsContext *ctx, V9fsPath *dir,
 | 
			
		|||
static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
 | 
			
		||||
                                 mode_t st_mode, uint64_t *st_gen)
 | 
			
		||||
{
 | 
			
		||||
    int err, fd;
 | 
			
		||||
    int err;
 | 
			
		||||
    V9fsFidOpenState fid_open;
 | 
			
		||||
 | 
			
		||||
    /*
 | 
			
		||||
     * Do not try to open special files like device nodes, fifos etc
 | 
			
		||||
| 
						 | 
				
			
			@ -584,12 +598,12 @@ static int handle_ioc_getversion(FsContext *ctx, V9fsPath *path,
 | 
			
		|||
    if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
 | 
			
		||||
            return 0;
 | 
			
		||||
    }
 | 
			
		||||
    fd = handle_open(ctx, path, O_RDONLY);
 | 
			
		||||
    if (fd < 0) {
 | 
			
		||||
        return fd;
 | 
			
		||||
    err = handle_open(ctx, path, O_RDONLY, &fid_open);
 | 
			
		||||
    if (err < 0) {
 | 
			
		||||
        return err;
 | 
			
		||||
    }
 | 
			
		||||
    err = ioctl(fd, FS_IOC_GETVERSION, st_gen);
 | 
			
		||||
    handle_close(ctx, fd);
 | 
			
		||||
    err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
 | 
			
		||||
    handle_close(ctx, &fid_open);
 | 
			
		||||
    return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -156,81 +156,91 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
 | 
			
		|||
    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
 | 
			
		||||
    ret = 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 {
 | 
			
		||||
        ret = writev(fd, iov, iovcnt);
 | 
			
		||||
        ret = writev(fs->fd, iov, iovcnt);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
#ifdef CONFIG_SYNC_FILE_RANGE
 | 
			
		||||
| 
						 | 
				
			
			@ -240,7 +250,7 @@ static ssize_t local_pwritev(FsContext *ctx, int fd, const struct iovec *iov,
 | 
			
		|||
         * We want to ensure that we don't leave dirty pages in the cache
 | 
			
		||||
         * after write when writeout=immediate is sepcified.
 | 
			
		||||
         */
 | 
			
		||||
        sync_file_range(fd, offset, ret,
 | 
			
		||||
        sync_file_range(fs->fd, offset, ret,
 | 
			
		||||
                        SYNC_FILE_RANGE_WAIT_BEFORE | SYNC_FILE_RANGE_WRITE);
 | 
			
		||||
    }
 | 
			
		||||
#endif
 | 
			
		||||
| 
						 | 
				
			
			@ -281,7 +291,7 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
 | 
			
		|||
        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;
 | 
			
		||||
| 
						 | 
				
			
			@ -356,10 +366,11 @@ 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;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -370,16 +381,20 @@ static int local_fstat(FsContext *fs_ctx, int fd, struct stat *stbuf)
 | 
			
		|||
        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;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -387,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -428,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:
 | 
			
		||||
| 
						 | 
				
			
			@ -551,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->export_flags & V9FS_SM_PASSTHROUGH)) {
 | 
			
		||||
        return lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
 | 
			
		||||
                credp->fc_gid);
 | 
			
		||||
        (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->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);
 | 
			
		||||
    }
 | 
			
		||||
    return -1;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -580,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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -680,7 +693,9 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
 | 
			
		|||
static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
 | 
			
		||||
                                mode_t st_mode, uint64_t *st_gen)
 | 
			
		||||
{
 | 
			
		||||
    int err, fd;
 | 
			
		||||
    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
 | 
			
		||||
| 
						 | 
				
			
			@ -688,12 +703,12 @@ static int local_ioc_getversion(FsContext *ctx, V9fsPath *path,
 | 
			
		|||
    if (!S_ISREG(st_mode) && !S_ISDIR(st_mode)) {
 | 
			
		||||
            return 0;
 | 
			
		||||
    }
 | 
			
		||||
    fd = local_open(ctx, path, O_RDONLY);
 | 
			
		||||
    if (fd < 0) {
 | 
			
		||||
        return fd;
 | 
			
		||||
    err = local_open(ctx, path, O_RDONLY, &fid_open);
 | 
			
		||||
    if (err < 0) {
 | 
			
		||||
        return err;
 | 
			
		||||
    }
 | 
			
		||||
    err = ioctl(fd, FS_IOC_GETVERSION, st_gen);
 | 
			
		||||
    local_close(ctx, fd);
 | 
			
		||||
    err = ioctl(fid_open.fd, FS_IOC_GETVERSION, st_gen);
 | 
			
		||||
    local_close(ctx, &fid_open);
 | 
			
		||||
    return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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,
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -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);
 | 
			
		||||
| 
						 | 
				
			
			@ -455,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);
 | 
			
		||||
| 
						 | 
				
			
			@ -567,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;
 | 
			
		||||
        /*
 | 
			
		||||
| 
						 | 
				
			
			@ -1271,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;
 | 
			
		||||
| 
						 | 
				
			
			@ -1690,6 +1695,14 @@ static void v9fs_open(void *opaque)
 | 
			
		|||
        } 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;
 | 
			
		||||
| 
						 | 
				
			
			@ -2996,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;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -3039,7 +3052,7 @@ static void v9fs_getlock(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;
 | 
			
		||||
    }
 | 
			
		||||
| 
						 | 
				
			
			@ -3309,6 +3322,39 @@ 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;
 | 
			
		||||
| 
						 | 
				
			
			@ -3320,6 +3366,10 @@ static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
 | 
			
		|||
    } 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);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -180,7 +180,11 @@ QemuOptsList qemu_fsdev_opts = {
 | 
			
		|||
        }, {
 | 
			
		||||
            .name = "writeout",
 | 
			
		||||
            .type = QEMU_OPT_STRING,
 | 
			
		||||
        }, {
 | 
			
		||||
            .name = "readonly",
 | 
			
		||||
            .type = QEMU_OPT_BOOL,
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        { /*End of list */ }
 | 
			
		||||
    },
 | 
			
		||||
};
 | 
			
		||||
| 
						 | 
				
			
			@ -205,6 +209,9 @@ QemuOptsList qemu_virtfs_opts = {
 | 
			
		|||
        }, {
 | 
			
		||||
            .name = "writeout",
 | 
			
		||||
            .type = QEMU_OPT_STRING,
 | 
			
		||||
        }, {
 | 
			
		||||
            .name = "readonly",
 | 
			
		||||
            .type = QEMU_OPT_BOOL,
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        { /*End of list */ }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -168,7 +168,7 @@ QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list,
 | 
			
		|||
    return NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int parse_option_bool(const char *name, const char *value, int *ret)
 | 
			
		||||
static int parse_option_bool(const char *name, const char *value, bool *ret)
 | 
			
		||||
{
 | 
			
		||||
    if (value != NULL) {
 | 
			
		||||
        if (!strcmp(value, "on")) {
 | 
			
		||||
| 
						 | 
				
			
			@ -258,7 +258,7 @@ static int parse_option_size(const char *name, const char *value, uint64_t *ret)
 | 
			
		|||
int set_option_parameter(QEMUOptionParameter *list, const char *name,
 | 
			
		||||
    const char *value)
 | 
			
		||||
{
 | 
			
		||||
    int flag;
 | 
			
		||||
    bool flag;
 | 
			
		||||
 | 
			
		||||
    // Find a matching parameter
 | 
			
		||||
    list = get_option_parameter(list, name);
 | 
			
		||||
| 
						 | 
				
			
			@ -508,7 +508,7 @@ struct QemuOpt {
 | 
			
		|||
 | 
			
		||||
    const QemuOptDesc *desc;
 | 
			
		||||
    union {
 | 
			
		||||
        int      boolean;
 | 
			
		||||
        bool boolean;
 | 
			
		||||
        uint64_t uint;
 | 
			
		||||
    } value;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -542,7 +542,7 @@ const char *qemu_opt_get(QemuOpts *opts, const char *name)
 | 
			
		|||
    return opt ? opt->str : NULL;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval)
 | 
			
		||||
bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval)
 | 
			
		||||
{
 | 
			
		||||
    QemuOpt *opt = qemu_opt_find(opts, name);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -636,6 +636,37 @@ int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
 | 
			
		|||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val)
 | 
			
		||||
{
 | 
			
		||||
    QemuOpt *opt;
 | 
			
		||||
    const QemuOptDesc *desc = opts->list->desc;
 | 
			
		||||
    int i;
 | 
			
		||||
 | 
			
		||||
    for (i = 0; desc[i].name != NULL; i++) {
 | 
			
		||||
        if (strcmp(desc[i].name, name) == 0) {
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if (desc[i].name == NULL) {
 | 
			
		||||
        if (i == 0) {
 | 
			
		||||
            /* empty list -> allow any */;
 | 
			
		||||
        } else {
 | 
			
		||||
            qerror_report(QERR_INVALID_PARAMETER, name);
 | 
			
		||||
            return -1;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    opt = g_malloc0(sizeof(*opt));
 | 
			
		||||
    opt->name = g_strdup(name);
 | 
			
		||||
    opt->opts = opts;
 | 
			
		||||
    QTAILQ_INSERT_TAIL(&opts->head, opt, next);
 | 
			
		||||
    if (desc[i].name != NULL) {
 | 
			
		||||
        opt->desc = desc+i;
 | 
			
		||||
    }
 | 
			
		||||
    opt->value.boolean = !!val;
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
 | 
			
		||||
                     int abort_on_failure)
 | 
			
		||||
{
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -105,10 +105,11 @@ struct QemuOptsList {
 | 
			
		|||
};
 | 
			
		||||
 | 
			
		||||
const char *qemu_opt_get(QemuOpts *opts, const char *name);
 | 
			
		||||
int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval);
 | 
			
		||||
bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval);
 | 
			
		||||
uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval);
 | 
			
		||||
uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval);
 | 
			
		||||
int qemu_opt_set(QemuOpts *opts, const char *name, const char *value);
 | 
			
		||||
int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val);
 | 
			
		||||
typedef int (*qemu_opt_loopfunc)(const char *name, const char *value, void *opaque);
 | 
			
		||||
int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
 | 
			
		||||
                     int abort_on_failure);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -528,12 +528,12 @@ DEFHEADING(File system options:)
 | 
			
		|||
 | 
			
		||||
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
 | 
			
		||||
    "-fsdev fsdriver,id=id,path=path,[security_model={mapped|passthrough|none}]\n"
 | 
			
		||||
    "       [,writeout=immediate]\n",
 | 
			
		||||
    "       [,writeout=immediate][,readonly]\n",
 | 
			
		||||
    QEMU_ARCH_ALL)
 | 
			
		||||
 | 
			
		||||
STEXI
 | 
			
		||||
 | 
			
		||||
@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}]
 | 
			
		||||
@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}][,readonly]
 | 
			
		||||
@findex -fsdev
 | 
			
		||||
Define a new file system device. Valid options are:
 | 
			
		||||
@table @option
 | 
			
		||||
| 
						 | 
				
			
			@ -563,6 +563,9 @@ This is an optional argument. The only supported value is "immediate".
 | 
			
		|||
This means that host page cache will be used to read and write data but
 | 
			
		||||
write notification will be sent to the guest only when the data has been
 | 
			
		||||
reported as written by the storage subsystem.
 | 
			
		||||
@item readonly
 | 
			
		||||
Enables exporting 9p share as a readonly mount for guests. By default
 | 
			
		||||
read-write access is given.
 | 
			
		||||
@end table
 | 
			
		||||
 | 
			
		||||
-fsdev option is used along with -device driver "virtio-9p-pci".
 | 
			
		||||
| 
						 | 
				
			
			@ -583,12 +586,12 @@ DEFHEADING(Virtual File system pass-through options:)
 | 
			
		|||
 | 
			
		||||
DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
 | 
			
		||||
    "-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n"
 | 
			
		||||
    "        [,writeout=immediate]\n",
 | 
			
		||||
    "        [,writeout=immediate][,readonly]\n",
 | 
			
		||||
    QEMU_ARCH_ALL)
 | 
			
		||||
 | 
			
		||||
STEXI
 | 
			
		||||
 | 
			
		||||
@item -virtfs @var{fsdriver},path=@var{path},mount_tag=@var{mount_tag},security_model=@var{security_model}[,writeout=@var{writeout}]
 | 
			
		||||
@item -virtfs @var{fsdriver},path=@var{path},mount_tag=@var{mount_tag},security_model=@var{security_model}[,writeout=@var{writeout}][,readonly]
 | 
			
		||||
@findex -virtfs
 | 
			
		||||
 | 
			
		||||
The general form of a Virtual File system pass-through options are:
 | 
			
		||||
| 
						 | 
				
			
			@ -619,9 +622,21 @@ This is an optional argument. The only supported value is "immediate".
 | 
			
		|||
This means that host page cache will be used to read and write data but
 | 
			
		||||
write notification will be sent to the guest only when the data has been
 | 
			
		||||
reported as written by the storage subsystem.
 | 
			
		||||
@item readonly
 | 
			
		||||
Enables exporting 9p share as a readonly mount for guests. By default
 | 
			
		||||
read-write access is given.
 | 
			
		||||
@end table
 | 
			
		||||
ETEXI
 | 
			
		||||
 | 
			
		||||
DEF("virtfs_synth", 0, QEMU_OPTION_virtfs_synth,
 | 
			
		||||
    "-virtfs_synth Create synthetic file system image\n",
 | 
			
		||||
    QEMU_ARCH_ALL)
 | 
			
		||||
STEXI
 | 
			
		||||
@item -virtfs_synth
 | 
			
		||||
@findex -virtfs_synth
 | 
			
		||||
Create synthetic file system image
 | 
			
		||||
ETEXI
 | 
			
		||||
 | 
			
		||||
DEFHEADING()
 | 
			
		||||
 | 
			
		||||
DEF("name", HAS_ARG, QEMU_OPTION_name,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										13
									
								
								qemu-queue.h
								
								
								
								
							
							
						
						
									
										13
									
								
								qemu-queue.h
								
								
								
								
							| 
						 | 
				
			
			@ -76,6 +76,8 @@
 | 
			
		|||
 * For details on the use of these macros, see the queue(3) manual page.
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
#include "qemu-barrier.h" /* for smp_wmb() */
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * List definitions.
 | 
			
		||||
 */
 | 
			
		||||
| 
						 | 
				
			
			@ -122,6 +124,17 @@ struct {                                                                \
 | 
			
		|||
        (elm)->field.le_prev = &(head)->lh_first;                       \
 | 
			
		||||
} while (/*CONSTCOND*/0)
 | 
			
		||||
 | 
			
		||||
#define QLIST_INSERT_HEAD_RCU(head, elm, field) do {                    \
 | 
			
		||||
        (elm)->field.le_prev = &(head)->lh_first;                       \
 | 
			
		||||
        (elm)->field.le_next = (head)->lh_first;                        \
 | 
			
		||||
        smp_wmb(); /* fill elm before linking it */                     \
 | 
			
		||||
        if ((head)->lh_first != NULL)  {                                \
 | 
			
		||||
            (head)->lh_first->field.le_prev = &(elm)->field.le_next;    \
 | 
			
		||||
        }                                                               \
 | 
			
		||||
        (head)->lh_first = (elm);                                       \
 | 
			
		||||
        smp_wmb();                                                      \
 | 
			
		||||
} while (/* CONSTCOND*/0)
 | 
			
		||||
 | 
			
		||||
#define QLIST_REMOVE(elm, field) do {                                   \
 | 
			
		||||
        if ((elm)->field.le_next != NULL)                               \
 | 
			
		||||
                (elm)->field.le_next->field.le_prev =                   \
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,6 +19,9 @@ void qemu_mutex_lock(QemuMutex *mutex);
 | 
			
		|||
int qemu_mutex_trylock(QemuMutex *mutex);
 | 
			
		||||
void qemu_mutex_unlock(QemuMutex *mutex);
 | 
			
		||||
 | 
			
		||||
#define rcu_read_lock() do { } while (0)
 | 
			
		||||
#define rcu_read_unlock() do { } while (0)
 | 
			
		||||
 | 
			
		||||
void qemu_cond_init(QemuCond *cond);
 | 
			
		||||
void qemu_cond_destroy(QemuCond *cond);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										20
									
								
								vl.c
								
								
								
								
							
							
						
						
									
										20
									
								
								vl.c
								
								
								
								
							| 
						 | 
				
			
			@ -2707,6 +2707,8 @@ int main(int argc, char **argv, char **envp)
 | 
			
		|||
                qemu_opt_set(fsdev, "security_model",
 | 
			
		||||
                             qemu_opt_get(opts, "security_model"));
 | 
			
		||||
 | 
			
		||||
                qemu_opt_set_bool(fsdev, "readonly",
 | 
			
		||||
                                qemu_opt_get_bool(opts, "readonly", 0));
 | 
			
		||||
                device = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
 | 
			
		||||
                qemu_opt_set(device, "driver", "virtio-9p-pci");
 | 
			
		||||
                qemu_opt_set(device, "fsdev",
 | 
			
		||||
| 
						 | 
				
			
			@ -2715,6 +2717,24 @@ int main(int argc, char **argv, char **envp)
 | 
			
		|||
                             qemu_opt_get(opts, "mount_tag"));
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case QEMU_OPTION_virtfs_synth: {
 | 
			
		||||
                QemuOpts *fsdev;
 | 
			
		||||
                QemuOpts *device;
 | 
			
		||||
 | 
			
		||||
                fsdev = qemu_opts_create(qemu_find_opts("fsdev"), "v_synth", 1);
 | 
			
		||||
                if (!fsdev) {
 | 
			
		||||
                    fprintf(stderr, "duplicate option: %s\n", "virtfs_synth");
 | 
			
		||||
                    exit(1);
 | 
			
		||||
                }
 | 
			
		||||
                qemu_opt_set(fsdev, "fsdriver", "synth");
 | 
			
		||||
                qemu_opt_set(fsdev, "path", "/"); /* ignored */
 | 
			
		||||
 | 
			
		||||
                device = qemu_opts_create(qemu_find_opts("device"), NULL, 0);
 | 
			
		||||
                qemu_opt_set(device, "driver", "virtio-9p-pci");
 | 
			
		||||
                qemu_opt_set(device, "fsdev", "v_synth");
 | 
			
		||||
                qemu_opt_set(device, "mount_tag", "v_synth");
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
            case QEMU_OPTION_serial:
 | 
			
		||||
                add_device_config(DEV_SERIAL, optarg);
 | 
			
		||||
                default_serial = 0;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue