Merge remote-tracking branch 'aneesh/for-upstream' into staging
* aneesh/for-upstream: hw/9pfs: Remove O_NOATIME flag from 9pfs open() calls in readonly mode hw/9pfs: Update MAINTAINERS file fsdev: Fix parameter parsing for proxy helper hw/9pfs: Fix crash when mounting with synthfs hw/9pfs: Preserve S_ISGID hw/9pfs: Add new security model mapped-file.
This commit is contained in:
commit
dc717bfd05
|
@ -56,11 +56,15 @@ typedef struct extended_ops {
|
||||||
* On failure ignore the error.
|
* On failure ignore the error.
|
||||||
*/
|
*/
|
||||||
#define V9FS_SM_NONE 0x00000010
|
#define V9FS_SM_NONE 0x00000010
|
||||||
#define V9FS_RDONLY 0x00000020
|
/*
|
||||||
#define V9FS_PROXY_SOCK_FD 0x00000040
|
* uid/gid part of .virtfs_meatadata namespace
|
||||||
#define V9FS_PROXY_SOCK_NAME 0x00000080
|
*/
|
||||||
|
#define V9FS_SM_MAPPED_FILE 0x00000020
|
||||||
|
#define V9FS_RDONLY 0x00000040
|
||||||
|
#define V9FS_PROXY_SOCK_FD 0x00000080
|
||||||
|
#define V9FS_PROXY_SOCK_NAME 0x00000100
|
||||||
|
|
||||||
#define V9FS_SEC_MASK 0x0000001C
|
#define V9FS_SEC_MASK 0x0000003C
|
||||||
|
|
||||||
|
|
||||||
typedef struct FileOperations FileOperations;
|
typedef struct FileOperations FileOperations;
|
||||||
|
|
|
@ -1036,7 +1036,13 @@ int main(int argc, char **argv)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*sock_name && (own_u == -1 || own_g == -1)) {
|
if (sock_name && sock != -1) {
|
||||||
|
fprintf(stderr, "both named socket and socket descriptor specified\n");
|
||||||
|
usage(argv[0]);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sock_name && (own_u == -1 || own_g == -1)) {
|
||||||
fprintf(stderr, "owner uid:gid not specified, ");
|
fprintf(stderr, "owner uid:gid not specified, ");
|
||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"owner uid:gid specifies who can access the socket file\n");
|
"owner uid:gid specifies who can access the socket file\n");
|
||||||
|
@ -1064,7 +1070,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
do_log(LOG_INFO, "Started\n");
|
do_log(LOG_INFO, "Started\n");
|
||||||
if (*sock_name) {
|
if (sock_name) {
|
||||||
sock = proxy_socket(sock_name, own_u, own_g);
|
sock = proxy_socket(sock_name, own_u, own_g);
|
||||||
if (sock < 0) {
|
if (sock < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
|
|
|
@ -76,6 +76,20 @@ int v9fs_co_fstat(V9fsPDU *pdu, V9fsFidState *fidp, struct stat *stbuf)
|
||||||
err = -errno;
|
err = -errno;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
/*
|
||||||
|
* Some FS driver (local:mapped-file) can't support fetching attributes
|
||||||
|
* using file descriptor. Use Path name in that case.
|
||||||
|
*/
|
||||||
|
if (err == -EOPNOTSUPP) {
|
||||||
|
err = v9fs_co_lstat(pdu, &fidp->path, stbuf);
|
||||||
|
if (err == -ENOENT) {
|
||||||
|
/*
|
||||||
|
* fstat on an unlinked file. Work with partial results
|
||||||
|
* returned from s->ops->fstat
|
||||||
|
*/
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,15 +91,6 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
|
||||||
s->ctx.fs_root = NULL;
|
s->ctx.fs_root = NULL;
|
||||||
}
|
}
|
||||||
s->ctx.exops.get_st_gen = NULL;
|
s->ctx.exops.get_st_gen = NULL;
|
||||||
|
|
||||||
if (fse->export_flags & V9FS_SM_PASSTHROUGH) {
|
|
||||||
s->ctx.xops = passthrough_xattr_ops;
|
|
||||||
} else if (fse->export_flags & V9FS_SM_MAPPED) {
|
|
||||||
s->ctx.xops = mapped_xattr_ops;
|
|
||||||
} else if (fse->export_flags & V9FS_SM_NONE) {
|
|
||||||
s->ctx.xops = none_xattr_ops;
|
|
||||||
}
|
|
||||||
|
|
||||||
len = strlen(conf->tag);
|
len = strlen(conf->tag);
|
||||||
if (len > MAX_TAG_LEN - 1) {
|
if (len > MAX_TAG_LEN - 1) {
|
||||||
fprintf(stderr, "mount tag '%s' (%d bytes) is longer than "
|
fprintf(stderr, "mount tag '%s' (%d bytes) is longer than "
|
||||||
|
|
|
@ -63,11 +63,11 @@ static int handle_update_file_cred(int dirfd, const char *name, FsCred *credp)
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
ret = fchmod(fd, credp->fc_mode & 07777);
|
ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
goto err_out;
|
goto err_out;
|
||||||
}
|
}
|
||||||
ret = fchownat(fd, "", credp->fc_uid, credp->fc_gid, AT_EMPTY_PATH);
|
ret = fchmod(fd, credp->fc_mode & 07777);
|
||||||
err_out:
|
err_out:
|
||||||
close(fd);
|
close(fd);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include "qemu-xattr.h"
|
#include "qemu-xattr.h"
|
||||||
|
#include <libgen.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#ifdef CONFIG_LINUX_MAGIC_H
|
#ifdef CONFIG_LINUX_MAGIC_H
|
||||||
#include <linux/magic.h>
|
#include <linux/magic.h>
|
||||||
|
@ -39,6 +40,54 @@
|
||||||
#define BTRFS_SUPER_MAGIC 0x9123683E
|
#define BTRFS_SUPER_MAGIC 0x9123683E
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define VIRTFS_META_DIR ".virtfs_metadata"
|
||||||
|
|
||||||
|
static const char *local_mapped_attr_path(FsContext *ctx,
|
||||||
|
const char *path, char *buffer)
|
||||||
|
{
|
||||||
|
char *dir_name;
|
||||||
|
char *tmp_path = strdup(path);
|
||||||
|
char *base_name = basename(tmp_path);
|
||||||
|
|
||||||
|
/* NULL terminate the directory */
|
||||||
|
dir_name = tmp_path;
|
||||||
|
*(base_name - 1) = '\0';
|
||||||
|
|
||||||
|
snprintf(buffer, PATH_MAX, "%s/%s/%s/%s",
|
||||||
|
ctx->fs_root, dir_name, VIRTFS_META_DIR, base_name);
|
||||||
|
free(tmp_path);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ATTR_MAX 100
|
||||||
|
static void local_mapped_file_attr(FsContext *ctx, const char *path,
|
||||||
|
struct stat *stbuf)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char buf[ATTR_MAX];
|
||||||
|
char attr_path[PATH_MAX];
|
||||||
|
|
||||||
|
local_mapped_attr_path(ctx, path, attr_path);
|
||||||
|
fp = fopen(attr_path, "r");
|
||||||
|
if (!fp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(buf, 0, ATTR_MAX);
|
||||||
|
while (fgets(buf, ATTR_MAX, fp)) {
|
||||||
|
if (!strncmp(buf, "virtfs.uid", 10)) {
|
||||||
|
stbuf->st_uid = atoi(buf+11);
|
||||||
|
} else if (!strncmp(buf, "virtfs.gid", 10)) {
|
||||||
|
stbuf->st_gid = atoi(buf+11);
|
||||||
|
} else if (!strncmp(buf, "virtfs.mode", 11)) {
|
||||||
|
stbuf->st_mode = atoi(buf+12);
|
||||||
|
} else if (!strncmp(buf, "virtfs.rdev", 11)) {
|
||||||
|
stbuf->st_rdev = atoi(buf+12);
|
||||||
|
}
|
||||||
|
memset(buf, 0, ATTR_MAX);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
|
||||||
static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
|
static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -71,10 +120,103 @@ static int local_lstat(FsContext *fs_ctx, V9fsPath *fs_path, struct stat *stbuf)
|
||||||
sizeof(dev_t)) > 0) {
|
sizeof(dev_t)) > 0) {
|
||||||
stbuf->st_rdev = tmp_dev;
|
stbuf->st_rdev = tmp_dev;
|
||||||
}
|
}
|
||||||
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
|
local_mapped_file_attr(fs_ctx, path, stbuf);
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int local_create_mapped_attr_dir(FsContext *ctx, const char *path)
|
||||||
|
{
|
||||||
|
int err;
|
||||||
|
char attr_dir[PATH_MAX];
|
||||||
|
char *tmp_path = strdup(path);
|
||||||
|
|
||||||
|
snprintf(attr_dir, PATH_MAX, "%s/%s/%s",
|
||||||
|
ctx->fs_root, dirname(tmp_path), VIRTFS_META_DIR);
|
||||||
|
|
||||||
|
err = mkdir(attr_dir, 0700);
|
||||||
|
if (err < 0 && errno == EEXIST) {
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
free(tmp_path);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int local_set_mapped_file_attr(FsContext *ctx,
|
||||||
|
const char *path, FsCred *credp)
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
int ret = 0;
|
||||||
|
char buf[ATTR_MAX];
|
||||||
|
char attr_path[PATH_MAX];
|
||||||
|
int uid = -1, gid = -1, mode = -1, rdev = -1;
|
||||||
|
|
||||||
|
fp = fopen(local_mapped_attr_path(ctx, path, attr_path), "r");
|
||||||
|
if (!fp) {
|
||||||
|
goto create_map_file;
|
||||||
|
}
|
||||||
|
memset(buf, 0, ATTR_MAX);
|
||||||
|
while (fgets(buf, ATTR_MAX, fp)) {
|
||||||
|
if (!strncmp(buf, "virtfs.uid", 10)) {
|
||||||
|
uid = atoi(buf+11);
|
||||||
|
} else if (!strncmp(buf, "virtfs.gid", 10)) {
|
||||||
|
gid = atoi(buf+11);
|
||||||
|
} else if (!strncmp(buf, "virtfs.mode", 11)) {
|
||||||
|
mode = atoi(buf+12);
|
||||||
|
} else if (!strncmp(buf, "virtfs.rdev", 11)) {
|
||||||
|
rdev = atoi(buf+12);
|
||||||
|
}
|
||||||
|
memset(buf, 0, ATTR_MAX);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
goto update_map_file;
|
||||||
|
|
||||||
|
create_map_file:
|
||||||
|
ret = local_create_mapped_attr_dir(ctx, path);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
update_map_file:
|
||||||
|
fp = fopen(attr_path, "w");
|
||||||
|
if (!fp) {
|
||||||
|
ret = -1;
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (credp->fc_uid != -1) {
|
||||||
|
uid = credp->fc_uid;
|
||||||
|
}
|
||||||
|
if (credp->fc_gid != -1) {
|
||||||
|
gid = credp->fc_gid;
|
||||||
|
}
|
||||||
|
if (credp->fc_mode != -1) {
|
||||||
|
mode = credp->fc_mode;
|
||||||
|
}
|
||||||
|
if (credp->fc_rdev != -1) {
|
||||||
|
rdev = credp->fc_rdev;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (uid != -1) {
|
||||||
|
fprintf(fp, "virtfs.uid=%d\n", uid);
|
||||||
|
}
|
||||||
|
if (gid != -1) {
|
||||||
|
fprintf(fp, "virtfs.gid=%d\n", gid);
|
||||||
|
}
|
||||||
|
if (mode != -1) {
|
||||||
|
fprintf(fp, "virtfs.mode=%d\n", mode);
|
||||||
|
}
|
||||||
|
if (rdev != -1) {
|
||||||
|
fprintf(fp, "virtfs.rdev=%d\n", rdev);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
err_out:
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int local_set_xattr(const char *path, FsCred *credp)
|
static int local_set_xattr(const char *path, FsCred *credp)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
@ -115,9 +257,6 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
|
||||||
{
|
{
|
||||||
char buffer[PATH_MAX];
|
char buffer[PATH_MAX];
|
||||||
|
|
||||||
if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
|
if (lchown(rpath(fs_ctx, path, buffer), credp->fc_uid,
|
||||||
credp->fc_gid) < 0) {
|
credp->fc_gid) < 0) {
|
||||||
/*
|
/*
|
||||||
|
@ -128,6 +267,10 @@ static int local_post_create_passthrough(FsContext *fs_ctx, const char *path,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (chmod(rpath(fs_ctx, path, buffer), credp->fc_mode & 07777) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +281,8 @@ static ssize_t local_readlink(FsContext *fs_ctx, V9fsPath *fs_path,
|
||||||
char buffer[PATH_MAX];
|
char buffer[PATH_MAX];
|
||||||
char *path = fs_path->data;
|
char *path = fs_path->data;
|
||||||
|
|
||||||
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
if ((fs_ctx->export_flags & V9FS_SM_MAPPED) ||
|
||||||
|
(fs_ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
|
||||||
int fd;
|
int fd;
|
||||||
fd = open(rpath(fs_ctx, path, buffer), O_RDONLY);
|
fd = open(rpath(fs_ctx, path, buffer), O_RDONLY);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
|
@ -203,7 +347,18 @@ static int local_readdir_r(FsContext *ctx, V9fsFidOpenState *fs,
|
||||||
struct dirent *entry,
|
struct dirent *entry,
|
||||||
struct dirent **result)
|
struct dirent **result)
|
||||||
{
|
{
|
||||||
return readdir_r(fs->dir, entry, result);
|
int ret;
|
||||||
|
|
||||||
|
again:
|
||||||
|
ret = readdir_r(fs->dir, entry, result);
|
||||||
|
if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
|
if (!ret && *result != NULL &&
|
||||||
|
!strcmp(entry->d_name, VIRTFS_META_DIR)) {
|
||||||
|
/* skp the meta data directory */
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
|
static void local_seekdir(FsContext *ctx, V9fsFidOpenState *fs, off_t off)
|
||||||
|
@ -264,6 +419,8 @@ static int local_chmod(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
|
||||||
|
|
||||||
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
||||||
return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
|
return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
|
||||||
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
|
return local_set_mapped_file_attr(fs_ctx, path, credp);
|
||||||
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
||||||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
||||||
return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode);
|
return chmod(rpath(fs_ctx, path, buffer), credp->fc_mode);
|
||||||
|
@ -296,6 +453,18 @@ static int local_mknod(FsContext *fs_ctx, V9fsPath *dir_path,
|
||||||
serrno = errno;
|
serrno = errno;
|
||||||
goto err_end;
|
goto err_end;
|
||||||
}
|
}
|
||||||
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
|
|
||||||
|
err = mknod(rpath(fs_ctx, path, buffer),
|
||||||
|
SM_LOCAL_MODE_BITS|S_IFREG, 0);
|
||||||
|
if (err == -1) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
err = local_set_mapped_file_attr(fs_ctx, path, credp);
|
||||||
|
if (err == -1) {
|
||||||
|
serrno = errno;
|
||||||
|
goto err_end;
|
||||||
|
}
|
||||||
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
||||||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
||||||
err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
|
err = mknod(rpath(fs_ctx, path, buffer), credp->fc_mode,
|
||||||
|
@ -344,6 +513,17 @@ static int local_mkdir(FsContext *fs_ctx, V9fsPath *dir_path,
|
||||||
serrno = errno;
|
serrno = errno;
|
||||||
goto err_end;
|
goto err_end;
|
||||||
}
|
}
|
||||||
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
|
err = mkdir(rpath(fs_ctx, path, buffer), SM_LOCAL_DIR_MODE_BITS);
|
||||||
|
if (err == -1) {
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
credp->fc_mode = credp->fc_mode|S_IFDIR;
|
||||||
|
err = local_set_mapped_file_attr(fs_ctx, path, credp);
|
||||||
|
if (err == -1) {
|
||||||
|
serrno = errno;
|
||||||
|
goto err_end;
|
||||||
|
}
|
||||||
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
||||||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
||||||
err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
|
err = mkdir(rpath(fs_ctx, path, buffer), credp->fc_mode);
|
||||||
|
@ -404,6 +584,9 @@ static int local_fstat(FsContext *fs_ctx, int fid_type,
|
||||||
&tmp_dev, sizeof(dev_t)) > 0) {
|
&tmp_dev, sizeof(dev_t)) > 0) {
|
||||||
stbuf->st_rdev = tmp_dev;
|
stbuf->st_rdev = tmp_dev;
|
||||||
}
|
}
|
||||||
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
|
errno = EOPNOTSUPP;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
@ -436,6 +619,19 @@ static int local_open2(FsContext *fs_ctx, V9fsPath *dir_path, const char *name,
|
||||||
serrno = errno;
|
serrno = errno;
|
||||||
goto err_end;
|
goto err_end;
|
||||||
}
|
}
|
||||||
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
|
fd = open(rpath(fs_ctx, path, buffer), flags, SM_LOCAL_MODE_BITS);
|
||||||
|
if (fd == -1) {
|
||||||
|
err = fd;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
credp->fc_mode = credp->fc_mode|S_IFREG;
|
||||||
|
/* Set client credentials in .virtfs_metadata directory files */
|
||||||
|
err = local_set_mapped_file_attr(fs_ctx, path, credp);
|
||||||
|
if (err == -1) {
|
||||||
|
serrno = errno;
|
||||||
|
goto err_end;
|
||||||
|
}
|
||||||
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
||||||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
||||||
fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
|
fd = open(rpath(fs_ctx, path, buffer), flags, credp->fc_mode);
|
||||||
|
@ -506,6 +702,35 @@ static int local_symlink(FsContext *fs_ctx, const char *oldpath,
|
||||||
serrno = errno;
|
serrno = errno;
|
||||||
goto err_end;
|
goto err_end;
|
||||||
}
|
}
|
||||||
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
|
int fd;
|
||||||
|
ssize_t oldpath_size, write_size;
|
||||||
|
fd = open(rpath(fs_ctx, newpath, buffer), O_CREAT|O_EXCL|O_RDWR,
|
||||||
|
SM_LOCAL_MODE_BITS);
|
||||||
|
if (fd == -1) {
|
||||||
|
err = fd;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
/* Write the oldpath (target) to the file. */
|
||||||
|
oldpath_size = strlen(oldpath);
|
||||||
|
do {
|
||||||
|
write_size = write(fd, (void *)oldpath, oldpath_size);
|
||||||
|
} while (write_size == -1 && errno == EINTR);
|
||||||
|
|
||||||
|
if (write_size != oldpath_size) {
|
||||||
|
serrno = errno;
|
||||||
|
close(fd);
|
||||||
|
err = -1;
|
||||||
|
goto err_end;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
/* Set cleint credentials in symlink's xattr */
|
||||||
|
credp->fc_mode = credp->fc_mode|S_IFLNK;
|
||||||
|
err = local_set_mapped_file_attr(fs_ctx, newpath, credp);
|
||||||
|
if (err == -1) {
|
||||||
|
serrno = errno;
|
||||||
|
goto err_end;
|
||||||
|
}
|
||||||
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
} else if ((fs_ctx->export_flags & V9FS_SM_PASSTHROUGH) ||
|
||||||
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
(fs_ctx->export_flags & V9FS_SM_NONE)) {
|
||||||
err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
|
err = symlink(oldpath, rpath(fs_ctx, newpath, buffer));
|
||||||
|
@ -548,6 +773,21 @@ static int local_link(FsContext *ctx, V9fsPath *oldpath,
|
||||||
|
|
||||||
ret = link(rpath(ctx, oldpath->data, buffer),
|
ret = link(rpath(ctx, oldpath->data, buffer),
|
||||||
rpath(ctx, newpath.data, buffer1));
|
rpath(ctx, newpath.data, buffer1));
|
||||||
|
|
||||||
|
/* now link the virtfs_metadata files */
|
||||||
|
if (!ret && (ctx->export_flags & V9FS_SM_MAPPED_FILE)) {
|
||||||
|
/* Link the .virtfs_metadata files. Create the metada directory */
|
||||||
|
ret = local_create_mapped_attr_dir(ctx, newpath.data);
|
||||||
|
if (ret < 0) {
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
ret = link(local_mapped_attr_path(ctx, oldpath->data, buffer),
|
||||||
|
local_mapped_attr_path(ctx, newpath.data, buffer1));
|
||||||
|
if (ret < 0 && errno != ENOENT) {
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
err_out:
|
||||||
v9fs_string_free(&newpath);
|
v9fs_string_free(&newpath);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -563,8 +803,21 @@ static int local_truncate(FsContext *ctx, V9fsPath *fs_path, off_t size)
|
||||||
static int local_rename(FsContext *ctx, const char *oldpath,
|
static int local_rename(FsContext *ctx, const char *oldpath,
|
||||||
const char *newpath)
|
const char *newpath)
|
||||||
{
|
{
|
||||||
|
int err;
|
||||||
char buffer[PATH_MAX], buffer1[PATH_MAX];
|
char buffer[PATH_MAX], buffer1[PATH_MAX];
|
||||||
|
|
||||||
|
if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
|
err = local_create_mapped_attr_dir(ctx, newpath);
|
||||||
|
if (err < 0) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
/* rename the .virtfs_metadata files */
|
||||||
|
err = rename(local_mapped_attr_path(ctx, oldpath, buffer),
|
||||||
|
local_mapped_attr_path(ctx, newpath, buffer1));
|
||||||
|
if (err < 0 && errno != ENOENT) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
|
return rename(rpath(ctx, oldpath, buffer), rpath(ctx, newpath, buffer1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -580,6 +833,8 @@ static int local_chown(FsContext *fs_ctx, V9fsPath *fs_path, FsCred *credp)
|
||||||
credp->fc_uid, credp->fc_gid);
|
credp->fc_uid, credp->fc_gid);
|
||||||
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED) {
|
||||||
return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
|
return local_set_xattr(rpath(fs_ctx, path, buffer), credp);
|
||||||
|
} else if (fs_ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
|
return local_set_mapped_file_attr(fs_ctx, path, credp);
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -595,8 +850,46 @@ static int local_utimensat(FsContext *s, V9fsPath *fs_path,
|
||||||
|
|
||||||
static int local_remove(FsContext *ctx, const char *path)
|
static int local_remove(FsContext *ctx, const char *path)
|
||||||
{
|
{
|
||||||
|
int err;
|
||||||
|
struct stat stbuf;
|
||||||
char buffer[PATH_MAX];
|
char buffer[PATH_MAX];
|
||||||
|
|
||||||
|
if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
|
err = lstat(rpath(ctx, path, buffer), &stbuf);
|
||||||
|
if (err) {
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* If directory remove .virtfs_metadata contained in the
|
||||||
|
* directory
|
||||||
|
*/
|
||||||
|
if (S_ISDIR(stbuf.st_mode)) {
|
||||||
|
sprintf(buffer, "%s/%s/%s", ctx->fs_root, path, VIRTFS_META_DIR);
|
||||||
|
err = remove(buffer);
|
||||||
|
if (err < 0 && errno != ENOENT) {
|
||||||
|
/*
|
||||||
|
* We didn't had the .virtfs_metadata file. May be file created
|
||||||
|
* in non-mapped mode ?. Ignore ENOENT.
|
||||||
|
*/
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Now remove the name from parent directory
|
||||||
|
* .virtfs_metadata directory
|
||||||
|
*/
|
||||||
|
err = remove(local_mapped_attr_path(ctx, path, buffer));;
|
||||||
|
if (err < 0 && errno != ENOENT) {
|
||||||
|
/*
|
||||||
|
* We didn't had the .virtfs_metadata file. May be file created
|
||||||
|
* in non-mapped mode ?. Ignore ENOENT.
|
||||||
|
*/
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
return remove(rpath(ctx, path, buffer));
|
return remove(rpath(ctx, path, buffer));
|
||||||
|
err_out:
|
||||||
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int local_fsync(FsContext *ctx, int fid_type,
|
static int local_fsync(FsContext *ctx, int fid_type,
|
||||||
|
@ -696,12 +989,45 @@ static int local_unlinkat(FsContext *ctx, V9fsPath *dir,
|
||||||
int ret;
|
int ret;
|
||||||
V9fsString fullname;
|
V9fsString fullname;
|
||||||
char buffer[PATH_MAX];
|
char buffer[PATH_MAX];
|
||||||
|
|
||||||
v9fs_string_init(&fullname);
|
v9fs_string_init(&fullname);
|
||||||
|
|
||||||
v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
|
v9fs_string_sprintf(&fullname, "%s/%s", dir->data, name);
|
||||||
|
if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
|
if (flags == AT_REMOVEDIR) {
|
||||||
|
/*
|
||||||
|
* If directory remove .virtfs_metadata contained in the
|
||||||
|
* directory
|
||||||
|
*/
|
||||||
|
sprintf(buffer, "%s/%s/%s", ctx->fs_root,
|
||||||
|
fullname.data, VIRTFS_META_DIR);
|
||||||
|
ret = remove(buffer);
|
||||||
|
if (ret < 0 && errno != ENOENT) {
|
||||||
|
/*
|
||||||
|
* We didn't had the .virtfs_metadata file. May be file created
|
||||||
|
* in non-mapped mode ?. Ignore ENOENT.
|
||||||
|
*/
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Now remove the name from parent directory
|
||||||
|
* .virtfs_metadata directory.
|
||||||
|
*/
|
||||||
|
ret = remove(local_mapped_attr_path(ctx, fullname.data, buffer));
|
||||||
|
if (ret < 0 && errno != ENOENT) {
|
||||||
|
/*
|
||||||
|
* We didn't had the .virtfs_metadata file. May be file created
|
||||||
|
* in non-mapped mode ?. Ignore ENOENT.
|
||||||
|
*/
|
||||||
|
goto err_out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* Remove the name finally */
|
||||||
ret = remove(rpath(ctx, fullname.data, buffer));
|
ret = remove(rpath(ctx, fullname.data, buffer));
|
||||||
v9fs_string_free(&fullname);
|
v9fs_string_free(&fullname);
|
||||||
|
|
||||||
|
err_out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -736,6 +1062,19 @@ static int local_init(FsContext *ctx)
|
||||||
int err = 0;
|
int err = 0;
|
||||||
struct statfs stbuf;
|
struct statfs stbuf;
|
||||||
|
|
||||||
|
if (ctx->export_flags & V9FS_SM_PASSTHROUGH) {
|
||||||
|
ctx->xops = passthrough_xattr_ops;
|
||||||
|
} else if (ctx->export_flags & V9FS_SM_MAPPED) {
|
||||||
|
ctx->xops = mapped_xattr_ops;
|
||||||
|
} else if (ctx->export_flags & V9FS_SM_NONE) {
|
||||||
|
ctx->xops = none_xattr_ops;
|
||||||
|
} else if (ctx->export_flags & V9FS_SM_MAPPED_FILE) {
|
||||||
|
/*
|
||||||
|
* xattr operation for mapped-file and passthrough
|
||||||
|
* remain same.
|
||||||
|
*/
|
||||||
|
ctx->xops = passthrough_xattr_ops;
|
||||||
|
}
|
||||||
ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
|
ctx->export_flags |= V9FS_PATHNAME_FSCONTEXT;
|
||||||
#ifdef FS_IOC_GETVERSION
|
#ifdef FS_IOC_GETVERSION
|
||||||
/*
|
/*
|
||||||
|
@ -770,13 +1109,17 @@ static int local_parse_opts(QemuOpts *opts, struct FsDriverEntry *fse)
|
||||||
|
|
||||||
if (!strcmp(sec_model, "passthrough")) {
|
if (!strcmp(sec_model, "passthrough")) {
|
||||||
fse->export_flags |= V9FS_SM_PASSTHROUGH;
|
fse->export_flags |= V9FS_SM_PASSTHROUGH;
|
||||||
} else if (!strcmp(sec_model, "mapped")) {
|
} else if (!strcmp(sec_model, "mapped") ||
|
||||||
|
!strcmp(sec_model, "mapped-xattr")) {
|
||||||
fse->export_flags |= V9FS_SM_MAPPED;
|
fse->export_flags |= V9FS_SM_MAPPED;
|
||||||
} else if (!strcmp(sec_model, "none")) {
|
} else if (!strcmp(sec_model, "none")) {
|
||||||
fse->export_flags |= V9FS_SM_NONE;
|
fse->export_flags |= V9FS_SM_NONE;
|
||||||
|
} else if (!strcmp(sec_model, "mapped-file")) {
|
||||||
|
fse->export_flags |= V9FS_SM_MAPPED_FILE;
|
||||||
} else {
|
} else {
|
||||||
fprintf(stderr, "Invalid security model %s specified, valid options are"
|
fprintf(stderr, "Invalid security model %s specified, valid options are"
|
||||||
"\n\t [passthrough|mapped|none]\n", sec_model);
|
"\n\t [passthrough|mapped-xattr|mapped-file|none]\n",
|
||||||
|
sec_model);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -986,7 +986,7 @@ static void v9fs_attach(void *opaque)
|
||||||
s->root_fid = fid;
|
s->root_fid = fid;
|
||||||
/* disable migration */
|
/* disable migration */
|
||||||
error_set(&s->migration_blocker, QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
|
error_set(&s->migration_blocker, QERR_VIRTFS_FEATURE_BLOCKS_MIGRATION,
|
||||||
s->ctx.fs_root, s->tag);
|
s->ctx.fs_root ? s->ctx.fs_root : "NULL", s->tag);
|
||||||
migrate_add_blocker(s->migration_blocker);
|
migrate_add_blocker(s->migration_blocker);
|
||||||
out:
|
out:
|
||||||
put_fid(pdu, fidp);
|
put_fid(pdu, fidp);
|
||||||
|
@ -1391,7 +1391,6 @@ static void v9fs_open(void *opaque)
|
||||||
err = -EROFS;
|
err = -EROFS;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
flags |= O_NOATIME;
|
|
||||||
}
|
}
|
||||||
err = v9fs_co_open(pdu, fidp, flags);
|
err = v9fs_co_open(pdu, fidp, flags);
|
||||||
if (err < 0) {
|
if (err < 0) {
|
||||||
|
|
|
@ -554,7 +554,7 @@ DEFHEADING()
|
||||||
DEFHEADING(File system options:)
|
DEFHEADING(File system options:)
|
||||||
|
|
||||||
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
|
DEF("fsdev", HAS_ARG, QEMU_OPTION_fsdev,
|
||||||
"-fsdev fsdriver,id=id[,path=path,][security_model={mapped|passthrough|none}]\n"
|
"-fsdev fsdriver,id=id[,path=path,][security_model={mapped-xattr|mapped-file|passthrough|none}]\n"
|
||||||
" [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n",
|
" [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n",
|
||||||
QEMU_ARCH_ALL)
|
QEMU_ARCH_ALL)
|
||||||
|
|
||||||
|
@ -574,12 +574,13 @@ Specifies the export path for the file system device. Files under
|
||||||
this path will be available to the 9p client on the guest.
|
this path will be available to the 9p client on the guest.
|
||||||
@item security_model=@var{security_model}
|
@item security_model=@var{security_model}
|
||||||
Specifies the security model to be used for this export path.
|
Specifies the security model to be used for this export path.
|
||||||
Supported security models are "passthrough", "mapped" and "none".
|
Supported security models are "passthrough", "mapped-xattr", "mapped-file" and "none".
|
||||||
In "passthrough" security model, files are stored using the same
|
In "passthrough" security model, files are stored using the same
|
||||||
credentials as they are created on the guest. This requires qemu
|
credentials as they are created on the guest. This requires qemu
|
||||||
to run as root. In "mapped" security model, some of the file
|
to run as root. In "mapped-xattr" security model, some of the file
|
||||||
attributes like uid, gid, mode bits and link target are stored as
|
attributes like uid, gid, mode bits and link target are stored as
|
||||||
file attributes. Directories exported by this security model cannot
|
file attributes. For "mapped-file" these attributes are stored in the
|
||||||
|
hidden .virtfs_metadata directory. Directories exported by this security model cannot
|
||||||
interact with other unix tools. "none" security model is same as
|
interact with other unix tools. "none" security model is same as
|
||||||
passthrough except the sever won't report failures if it fails to
|
passthrough except the sever won't report failures if it fails to
|
||||||
set file attributes like ownership. Security model is mandatory
|
set file attributes like ownership. Security model is mandatory
|
||||||
|
@ -619,7 +620,7 @@ DEFHEADING()
|
||||||
DEFHEADING(Virtual File system pass-through options:)
|
DEFHEADING(Virtual File system pass-through options:)
|
||||||
|
|
||||||
DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
|
DEF("virtfs", HAS_ARG, QEMU_OPTION_virtfs,
|
||||||
"-virtfs local,path=path,mount_tag=tag,security_model=[mapped|passthrough|none]\n"
|
"-virtfs local,path=path,mount_tag=tag,security_model=[mapped-xattr|mapped-file|passthrough|none]\n"
|
||||||
" [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n",
|
" [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n",
|
||||||
QEMU_ARCH_ALL)
|
QEMU_ARCH_ALL)
|
||||||
|
|
||||||
|
@ -640,12 +641,13 @@ Specifies the export path for the file system device. Files under
|
||||||
this path will be available to the 9p client on the guest.
|
this path will be available to the 9p client on the guest.
|
||||||
@item security_model=@var{security_model}
|
@item security_model=@var{security_model}
|
||||||
Specifies the security model to be used for this export path.
|
Specifies the security model to be used for this export path.
|
||||||
Supported security models are "passthrough", "mapped" and "none".
|
Supported security models are "passthrough", "mapped-xattr", "mapped-file" and "none".
|
||||||
In "passthrough" security model, files are stored using the same
|
In "passthrough" security model, files are stored using the same
|
||||||
credentials as they are created on the guest. This requires qemu
|
credentials as they are created on the guest. This requires qemu
|
||||||
to run as root. In "mapped" security model, some of the file
|
to run as root. In "mapped-xattr" security model, some of the file
|
||||||
attributes like uid, gid, mode bits and link target are stored as
|
attributes like uid, gid, mode bits and link target are stored as
|
||||||
file attributes. Directories exported by this security model cannot
|
file attributes. For "mapped-file" these attributes are stored in the
|
||||||
|
hidden .virtfs_metadata directory. Directories exported by this security model cannot
|
||||||
interact with other unix tools. "none" security model is same as
|
interact with other unix tools. "none" security model is same as
|
||||||
passthrough except the sever won't report failures if it fails to
|
passthrough except the sever won't report failures if it fails to
|
||||||
set file attributes like ownership. Security model is mandatory only
|
set file attributes like ownership. Security model is mandatory only
|
||||||
|
|
Loading…
Reference in New Issue