From: "M. Mohan Kumar" <mo...@in.ibm.com>
Signed-off-by: M. Mohan Kumar <mo...@in.ibm.com> --- hw/9pfs/virtio-9p-chroot-worker.c | 52 ++++++++++++++++++++++++++++++++- hw/9pfs/virtio-9p-chroot.c | 59 ++++++++++++++++++++++++++++++++++++- hw/9pfs/virtio-9p-chroot.h | 3 ++ hw/9pfs/virtio-9p-local.c | 30 +++++++++++++++++++ 4 files changed, 142 insertions(+), 2 deletions(-) diff --git a/hw/9pfs/virtio-9p-chroot-worker.c b/hw/9pfs/virtio-9p-chroot-worker.c index 8ca4805..c4ebb96 100644 --- a/hw/9pfs/virtio-9p-chroot-worker.c +++ b/hw/9pfs/virtio-9p-chroot-worker.c @@ -66,6 +66,29 @@ static void chroot_sendfd(int sockfd, int fd, int fd_valid) } } +/* Send special information and error status to qemu process */ +static void chroot_sendspecial(int sockfd, void *buff, int size, int error) +{ + int retval; + + /* If there is an error, send NULL buff also set status to error */ + if (error) { + memset(buff, 0, size); + } + do { + retval = send(sockfd, &error, sizeof(error), 0); + } while (retval < 0 && errno == EINTR); + if (retval < 0) { + _exit(1); + } + do { + retval = send(sockfd, buff, size, 0); + } while (retval < 0 && errno == EINTR); + if (retval < 0) { + _exit(1); + } +} + /* Read V9fsFileObjectRequest sent by QEMU process */ static int chroot_read_request(int sockfd, V9fsFileObjectRequest *request) { @@ -267,6 +290,7 @@ int v9fs_chroot(FsContext *fs_ctx) pid_t pid; uint32_t code; int retval, valid_fd; + char *buff; if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd_pair) < 0) { error_report("socketpair %s", strerror(errno)); @@ -346,7 +370,33 @@ int v9fs_chroot(FsContext *fs_ctx) default: retval = -1; break; + case T_LSTAT: + buff = qemu_malloc(request.data.size); + retval = lstat(request.path.path, (struct stat *)buff); + if (retval < 0) { + retval = -errno; + } + break; + } + + /* Send the results */ + switch (request.data.type) { + case T_OPEN: + case T_CREATE: + case T_MKDIR: + case T_SYMLINK: + case T_LINK: + case T_MKNOD: + case T_REMOVE: + case T_RENAME: + case T_CHMOD: + case T_CHOWN: + chroot_sendfd(chroot_sock, retval, valid_fd); + break; + case T_LSTAT: + chroot_sendspecial(chroot_sock, buff, request.data.size, retval); + qemu_free(buff); + break; } - chroot_sendfd(chroot_sock, retval, valid_fd); } } diff --git a/hw/9pfs/virtio-9p-chroot.c b/hw/9pfs/virtio-9p-chroot.c index f5b3abc..9480ce0 100644 --- a/hw/9pfs/virtio-9p-chroot.c +++ b/hw/9pfs/virtio-9p-chroot.c @@ -77,6 +77,37 @@ static int v9fs_receivefd(int sockfd, int *sock_error) return -ENFILE; /* Ancillary data sent but not received */ } +static int qemu_recv(int sockfd, void *data, size_t size, int flags) +{ + int retval; + do { + retval = recv(sockfd, data, size, 0); + } while (retval < 0 && errno == EINTR); + return retval; +} + +/* + * Return received struct stat on success and -errno on failure. + * sock_error is set to 1 whenever there is error in socket IO + */ +static int v9fs_special_receive(int sockfd, int *sock_error, char *buff, + int size) +{ + int retval, status; + if (qemu_recv(sockfd, &status, sizeof(status), 0) <= 0) { + *sock_error = 1; + return -EIO; + } + + retval = qemu_recv(sockfd, buff, size, 0); + if (retval > 0) { + return status; + } else { + *sock_error = 1; + return -EIO; + } +} + /* * V9fsFileObjectRequest is written into the socket by QEMU process. * Then this request is read by chroot process using v9fs_read_request function @@ -94,7 +125,7 @@ static int v9fs_write_request(int sockfd, V9fsFileObjectRequest *request) /* Return opened file descriptor on success or -errno on error */ int v9fs_request(FsContext *fs_ctx, V9fsFileObjectRequest *request) { - int fd, sock_error; + int fd, sock_error = 0; qemu_mutex_lock(&fs_ctx->chroot_mutex); if (fs_ctx->chroot_socket == -1) { goto error; @@ -114,3 +145,29 @@ error: qemu_mutex_unlock(&fs_ctx->chroot_mutex); return -EIO; } + +/* Return special information on success or -errno on error */ +int v9fs_special(FsContext *fs_ctx, V9fsFileObjectRequest *request, + char *buff, int size) +{ + int retval, sock_error = 0; + qemu_mutex_lock(&fs_ctx->chroot_mutex); + if (fs_ctx->chroot_socket == -1) { + goto error; + } + if (v9fs_write_request(fs_ctx->chroot_socket, request) < 0) { + goto error; + } + retval = v9fs_special_receive(fs_ctx->chroot_socket, &sock_error, buff, + size); + if (retval < 0 && sock_error) { + goto error; + } + qemu_mutex_unlock(&fs_ctx->chroot_mutex); + return retval; +error: + close(fs_ctx->chroot_socket); + fs_ctx->chroot_socket = -1; + qemu_mutex_unlock(&fs_ctx->chroot_mutex); + return -EIO; +} diff --git a/hw/9pfs/virtio-9p-chroot.h b/hw/9pfs/virtio-9p-chroot.h index 07c6627..9ed3f4d 100644 --- a/hw/9pfs/virtio-9p-chroot.h +++ b/hw/9pfs/virtio-9p-chroot.h @@ -13,6 +13,7 @@ #define T_RENAME 8 #define T_CHMOD 9 #define T_CHOWN 10 +#define T_LSTAT 11 #define V9FS_FD_VALID INT_MAX @@ -29,6 +30,7 @@ struct V9fsFileObjectData gid_t gid; dev_t dev; int type; + int size; /* for special requests */ }; struct V9fsFileObjectPath @@ -45,6 +47,7 @@ typedef struct V9fsFileObjectRequest int v9fs_chroot(FsContext *fs_ctx); int v9fs_request(FsContext *fs_ctx, V9fsFileObjectRequest *or); +int v9fs_special(FsContext *fs_ctx, V9fsFileObjectRequest *or, char *, int); int v9fs_create_special(FsContext *fs_ctx, V9fsFileObjectRequest *request); #endif /* _QEMU_VIRTIO_9P_CHROOT_H */ diff --git a/hw/9pfs/virtio-9p-local.c b/hw/9pfs/virtio-9p-local.c index ea7d954..eab0854 100644 --- a/hw/9pfs/virtio-9p-local.c +++ b/hw/9pfs/virtio-9p-local.c @@ -81,12 +81,42 @@ static int passthrough_request(FsContext *fs_ctx, const char *old_path, return retval; } +static int passthrough_special_request(FsContext *fs_ctx, const char *path, + char *buff, int size, int type) +{ + V9fsFileObjectRequest request; + int retval; + + retval = fill_fileobjectrequest(&request, NULL, path, 0, NULL, type); + if (retval < 0) { + errno = -retval; + return -1; + } + + request.data.size = size; + if (type == T_LSTAT) { + retval = v9fs_special(fs_ctx, &request, buff, size); + } else { + return -1; + } + if (retval < 0) { + errno = -retval; + retval = -1; + } + return retval; +} + static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf) { int err; char buffer[PATH_MAX]; char *path = fs_path->data; + if (fs_ctx->fs_sm == SM_PASSTHROUGH) { + return passthrough_special_request(fs_ctx, path, (char *)stbuf, + sizeof(*stbuf), T_LSTAT); + } + err = lstat(rpath(fs_ctx, path, buffer), stbuf); if (err) { return err; -- 1.7.5.4