hw/9pfs: Add support to use named socket for proxy FS
Add option to use named socket for communicating between proxy helper and qemu proxy FS. Access to socket can be given by using command line options -u and -g. Signed-off-by: M. Mohan Kumar <mohan@in.ibm.com> Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
This commit is contained in:
parent
a2d8f1beb1
commit
84a87cc4cc
@ -57,6 +57,8 @@ typedef struct extended_ops {
|
|||||||
*/
|
*/
|
||||||
#define V9FS_SM_NONE 0x00000010
|
#define V9FS_SM_NONE 0x00000010
|
||||||
#define V9FS_RDONLY 0x00000020
|
#define V9FS_RDONLY 0x00000020
|
||||||
|
#define V9FS_PROXY_SOCK_FD 0x00000040
|
||||||
|
#define V9FS_PROXY_SOCK_NAME 0x00000080
|
||||||
|
|
||||||
#define V9FS_SEC_MASK 0x0000001C
|
#define V9FS_SEC_MASK 0x0000001C
|
||||||
|
|
||||||
|
@ -57,6 +57,9 @@ static struct option helper_opts[] = {
|
|||||||
{"fd", required_argument, NULL, 'f'},
|
{"fd", required_argument, NULL, 'f'},
|
||||||
{"path", required_argument, NULL, 'p'},
|
{"path", required_argument, NULL, 'p'},
|
||||||
{"nodaemon", no_argument, NULL, 'n'},
|
{"nodaemon", no_argument, NULL, 'n'},
|
||||||
|
{"socket", required_argument, NULL, 's'},
|
||||||
|
{"uid", required_argument, NULL, 'u'},
|
||||||
|
{"gid", required_argument, NULL, 'g'},
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool is_daemon;
|
static bool is_daemon;
|
||||||
@ -695,11 +698,61 @@ err_out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* create unix domain socket and return the descriptor */
|
||||||
|
static int proxy_socket(const char *path, uid_t uid, gid_t gid)
|
||||||
|
{
|
||||||
|
int sock, client;
|
||||||
|
struct sockaddr_un proxy, qemu;
|
||||||
|
socklen_t size;
|
||||||
|
|
||||||
|
/* requested socket already exists, refuse to start */
|
||||||
|
if (!access(path, F_OK)) {
|
||||||
|
do_log(LOG_CRIT, "socket already exists\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
sock = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
|
if (sock < 0) {
|
||||||
|
do_perror("socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* mask other part of mode bits */
|
||||||
|
umask(7);
|
||||||
|
|
||||||
|
proxy.sun_family = AF_UNIX;
|
||||||
|
strcpy(proxy.sun_path, path);
|
||||||
|
if (bind(sock, (struct sockaddr *)&proxy,
|
||||||
|
sizeof(struct sockaddr_un)) < 0) {
|
||||||
|
do_perror("bind");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (chown(proxy.sun_path, uid, gid) < 0) {
|
||||||
|
do_perror("chown");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (listen(sock, 1) < 0) {
|
||||||
|
do_perror("listen");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
client = accept(sock, (struct sockaddr *)&qemu, &size);
|
||||||
|
if (client < 0) {
|
||||||
|
do_perror("accept");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return client;
|
||||||
|
}
|
||||||
|
|
||||||
static void usage(char *prog)
|
static void usage(char *prog)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "usage: %s\n"
|
fprintf(stderr, "usage: %s\n"
|
||||||
" -p|--path <path> 9p path to export\n"
|
" -p|--path <path> 9p path to export\n"
|
||||||
" {-f|--fd <socket-descriptor>} socket file descriptor to be used\n"
|
" {-f|--fd <socket-descriptor>} socket file descriptor to be used\n"
|
||||||
|
" {-s|--socket <socketname> socket file used for communication\n"
|
||||||
|
" \t-u|--uid <uid> -g|--gid <gid>} - uid:gid combination to give "
|
||||||
|
" access to this socket\n"
|
||||||
|
" \tNote: -s & -f can not be used together\n"
|
||||||
" [-n|--nodaemon] Run as a normal program\n",
|
" [-n|--nodaemon] Run as a normal program\n",
|
||||||
basename(prog));
|
basename(prog));
|
||||||
}
|
}
|
||||||
@ -939,7 +992,10 @@ err_out:
|
|||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int sock;
|
int sock;
|
||||||
|
uid_t own_u;
|
||||||
|
gid_t own_g;
|
||||||
char *rpath = NULL;
|
char *rpath = NULL;
|
||||||
|
char *sock_name = NULL;
|
||||||
struct stat stbuf;
|
struct stat stbuf;
|
||||||
int c, option_index;
|
int c, option_index;
|
||||||
#ifdef FS_IOC_GETVERSION
|
#ifdef FS_IOC_GETVERSION
|
||||||
@ -949,9 +1005,10 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
is_daemon = true;
|
is_daemon = true;
|
||||||
sock = -1;
|
sock = -1;
|
||||||
|
own_u = own_g = -1;
|
||||||
while (1) {
|
while (1) {
|
||||||
option_index = 0;
|
option_index = 0;
|
||||||
c = getopt_long(argc, argv, "p:nh?f:", helper_opts,
|
c = getopt_long(argc, argv, "p:nh?f:s:u:g:", helper_opts,
|
||||||
&option_index);
|
&option_index);
|
||||||
if (c == -1) {
|
if (c == -1) {
|
||||||
break;
|
break;
|
||||||
@ -966,6 +1023,15 @@ int main(int argc, char **argv)
|
|||||||
case 'f':
|
case 'f':
|
||||||
sock = atoi(optarg);
|
sock = atoi(optarg);
|
||||||
break;
|
break;
|
||||||
|
case 's':
|
||||||
|
sock_name = strdup(optarg);
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
own_u = atoi(optarg);
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
own_g = atoi(optarg);
|
||||||
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
case 'h':
|
case 'h':
|
||||||
default:
|
default:
|
||||||
@ -975,8 +1041,16 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Parameter validation */
|
/* Parameter validation */
|
||||||
if (sock == -1 || rpath == NULL) {
|
if ((sock_name == NULL && sock == -1) || rpath == NULL) {
|
||||||
fprintf(stderr, "socket descriptor or path not specified\n");
|
fprintf(stderr, "socket, socket descriptor or path not specified\n");
|
||||||
|
usage(argv[0]);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*sock_name && (own_u == -1 || own_g == -1)) {
|
||||||
|
fprintf(stderr, "owner uid:gid not specified, ");
|
||||||
|
fprintf(stderr,
|
||||||
|
"owner uid:gid specifies who can access the socket file\n");
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@ -1001,6 +1075,12 @@ int main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
|
|
||||||
do_log(LOG_INFO, "Started\n");
|
do_log(LOG_INFO, "Started\n");
|
||||||
|
if (*sock_name) {
|
||||||
|
sock = proxy_socket(sock_name, own_u, own_g);
|
||||||
|
if (sock < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
get_version = false;
|
get_version = false;
|
||||||
#ifdef FS_IOC_GETVERSION
|
#ifdef FS_IOC_GETVERSION
|
||||||
|
@ -46,6 +46,10 @@ Path to export for proxy filesystem driver
|
|||||||
Use given file descriptor as socket descriptor for communicating with
|
Use given file descriptor as socket descriptor for communicating with
|
||||||
qemu proxy fs drier. Usually a helper like libvirt will create
|
qemu proxy fs drier. Usually a helper like libvirt will create
|
||||||
socketpair and pass one of the fds as parameter to -f|--fd
|
socketpair and pass one of the fds as parameter to -f|--fd
|
||||||
|
@item -s|--socket socket-file
|
||||||
|
Creates named socket file for communicating with qemu proxy fs driver
|
||||||
|
@item -u|--uid uid -g|--gid gid
|
||||||
|
uid:gid combination to give access to named socket file
|
||||||
@item -n|--nodaemon
|
@item -n|--nodaemon
|
||||||
Run as a normal program. By default program will run in daemon mode
|
Run as a normal program. By default program will run in daemon mode
|
||||||
@end table
|
@end table
|
||||||
|
@ -1095,15 +1095,49 @@ static int proxy_ioc_getversion(FsContext *fs_ctx, V9fsPath *path,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs)
|
static int connect_namedsocket(const char *path)
|
||||||
{
|
{
|
||||||
const char *sock_fd = qemu_opt_get(opts, "sock_fd");
|
int sockfd, size;
|
||||||
|
struct sockaddr_un helper;
|
||||||
|
|
||||||
if (sock_fd) {
|
sockfd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||||
fprintf(stderr, "sock_fd option not specified\n");
|
if (sockfd < 0) {
|
||||||
|
fprintf(stderr, "socket %s\n", strerror(errno));
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fs->path = g_strdup(sock_fd);
|
strcpy(helper.sun_path, path);
|
||||||
|
helper.sun_family = AF_UNIX;
|
||||||
|
size = strlen(helper.sun_path) + sizeof(helper.sun_family);
|
||||||
|
if (connect(sockfd, (struct sockaddr *)&helper, size) < 0) {
|
||||||
|
fprintf(stderr, "socket error\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* remove the socket for security reasons */
|
||||||
|
unlink(path);
|
||||||
|
return sockfd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int proxy_parse_opts(QemuOpts *opts, struct FsDriverEntry *fs)
|
||||||
|
{
|
||||||
|
const char *socket = qemu_opt_get(opts, "socket");
|
||||||
|
const char *sock_fd = qemu_opt_get(opts, "sock_fd");
|
||||||
|
|
||||||
|
if (!socket && !sock_fd) {
|
||||||
|
fprintf(stderr, "socket and sock_fd none of the option specified\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (socket && sock_fd) {
|
||||||
|
fprintf(stderr, "Both socket and sock_fd options specified\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (socket) {
|
||||||
|
fs->path = g_strdup(socket);
|
||||||
|
fs->export_flags = V9FS_PROXY_SOCK_NAME;
|
||||||
|
} else {
|
||||||
|
fs->path = g_strdup(sock_fd);
|
||||||
|
fs->export_flags = V9FS_PROXY_SOCK_FD;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1112,10 +1146,14 @@ static int proxy_init(FsContext *ctx)
|
|||||||
V9fsProxy *proxy = g_malloc(sizeof(V9fsProxy));
|
V9fsProxy *proxy = g_malloc(sizeof(V9fsProxy));
|
||||||
int sock_id;
|
int sock_id;
|
||||||
|
|
||||||
sock_id = atoi(ctx->fs_root);
|
if (ctx->export_flags & V9FS_PROXY_SOCK_NAME) {
|
||||||
if (sock_id < 0) {
|
sock_id = connect_namedsocket(ctx->fs_root);
|
||||||
fprintf(stderr, "socket descriptor not initialized\n");
|
} else {
|
||||||
return -1;
|
sock_id = atoi(ctx->fs_root);
|
||||||
|
if (sock_id < 0) {
|
||||||
|
fprintf(stderr, "socket descriptor not initialized\n");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g_free(ctx->fs_root);
|
g_free(ctx->fs_root);
|
||||||
|
|
||||||
|
@ -211,6 +211,10 @@ QemuOptsList qemu_fsdev_opts = {
|
|||||||
}, {
|
}, {
|
||||||
.name = "readonly",
|
.name = "readonly",
|
||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
|
|
||||||
|
}, {
|
||||||
|
.name = "socket",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
}, {
|
}, {
|
||||||
.name = "sock_fd",
|
.name = "sock_fd",
|
||||||
.type = QEMU_OPT_NUMBER,
|
.type = QEMU_OPT_NUMBER,
|
||||||
@ -243,6 +247,9 @@ QemuOptsList qemu_virtfs_opts = {
|
|||||||
}, {
|
}, {
|
||||||
.name = "readonly",
|
.name = "readonly",
|
||||||
.type = QEMU_OPT_BOOL,
|
.type = QEMU_OPT_BOOL,
|
||||||
|
}, {
|
||||||
|
.name = "socket",
|
||||||
|
.type = QEMU_OPT_STRING,
|
||||||
}, {
|
}, {
|
||||||
.name = "sock_fd",
|
.name = "sock_fd",
|
||||||
.type = QEMU_OPT_NUMBER,
|
.type = QEMU_OPT_NUMBER,
|
||||||
|
@ -552,12 +552,12 @@ 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|passthrough|none}]\n"
|
||||||
" [,writeout=immediate][,readonly][,sock_fd=sock_fd]\n",
|
" [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n",
|
||||||
QEMU_ARCH_ALL)
|
QEMU_ARCH_ALL)
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
|
|
||||||
@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,sock_fd=@var{sock_fd}]
|
@item -fsdev @var{fsdriver},id=@var{id},path=@var{path},[security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,socket=@var{socket}|sock_fd=@var{sock_fd}]
|
||||||
@findex -fsdev
|
@findex -fsdev
|
||||||
Define a new file system device. Valid options are:
|
Define a new file system device. Valid options are:
|
||||||
@table @option
|
@table @option
|
||||||
@ -590,6 +590,9 @@ reported as written by the storage subsystem.
|
|||||||
@item readonly
|
@item readonly
|
||||||
Enables exporting 9p share as a readonly mount for guests. By default
|
Enables exporting 9p share as a readonly mount for guests. By default
|
||||||
read-write access is given.
|
read-write access is given.
|
||||||
|
@item socket=@var{socket}
|
||||||
|
Enables proxy filesystem driver to use passed socket file for communicating
|
||||||
|
with virtfs-proxy-helper
|
||||||
@item sock_fd=@var{sock_fd}
|
@item sock_fd=@var{sock_fd}
|
||||||
Enables proxy filesystem driver to use passed socket descriptor for
|
Enables proxy filesystem driver to use passed socket descriptor for
|
||||||
communicating with virtfs-proxy-helper. Usually a helper like libvirt
|
communicating with virtfs-proxy-helper. Usually a helper like libvirt
|
||||||
@ -614,12 +617,12 @@ 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|passthrough|none]\n"
|
||||||
" [,writeout=immediate][,readonly][,sock_fd=sock_fd]\n",
|
" [,writeout=immediate][,readonly][,socket=socket|sock_fd=sock_fd]\n",
|
||||||
QEMU_ARCH_ALL)
|
QEMU_ARCH_ALL)
|
||||||
|
|
||||||
STEXI
|
STEXI
|
||||||
|
|
||||||
@item -virtfs @var{fsdriver}[,path=@var{path}],mount_tag=@var{mount_tag}[,security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,sock_fd=@var{sock_fd}]
|
@item -virtfs @var{fsdriver}[,path=@var{path}],mount_tag=@var{mount_tag}[,security_model=@var{security_model}][,writeout=@var{writeout}][,readonly][,socket=@var{socket}|sock_fd=@var{sock_fd}]
|
||||||
@findex -virtfs
|
@findex -virtfs
|
||||||
|
|
||||||
The general form of a Virtual File system pass-through options are:
|
The general form of a Virtual File system pass-through options are:
|
||||||
@ -653,6 +656,10 @@ reported as written by the storage subsystem.
|
|||||||
@item readonly
|
@item readonly
|
||||||
Enables exporting 9p share as a readonly mount for guests. By default
|
Enables exporting 9p share as a readonly mount for guests. By default
|
||||||
read-write access is given.
|
read-write access is given.
|
||||||
|
@item socket=@var{socket}
|
||||||
|
Enables proxy filesystem driver to use passed socket file for
|
||||||
|
communicating with virtfs-proxy-helper. Usually a helper like libvirt
|
||||||
|
will create socketpair and pass one of the fds as sock_fd
|
||||||
@item sock_fd
|
@item sock_fd
|
||||||
Enables proxy filesystem driver to use passed 'sock_fd' as the socket
|
Enables proxy filesystem driver to use passed 'sock_fd' as the socket
|
||||||
descriptor for interfacing with virtfs-proxy-helper
|
descriptor for interfacing with virtfs-proxy-helper
|
||||||
|
6
vl.c
6
vl.c
@ -2661,7 +2661,7 @@ int main(int argc, char **argv, char **envp)
|
|||||||
case QEMU_OPTION_virtfs: {
|
case QEMU_OPTION_virtfs: {
|
||||||
QemuOpts *fsdev;
|
QemuOpts *fsdev;
|
||||||
QemuOpts *device;
|
QemuOpts *device;
|
||||||
const char *writeout, *sock_fd;
|
const char *writeout, *sock_fd, *socket;
|
||||||
|
|
||||||
olist = qemu_find_opts("virtfs");
|
olist = qemu_find_opts("virtfs");
|
||||||
if (!olist) {
|
if (!olist) {
|
||||||
@ -2701,6 +2701,10 @@ int main(int argc, char **argv, char **envp)
|
|||||||
qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path"));
|
qemu_opt_set(fsdev, "path", qemu_opt_get(opts, "path"));
|
||||||
qemu_opt_set(fsdev, "security_model",
|
qemu_opt_set(fsdev, "security_model",
|
||||||
qemu_opt_get(opts, "security_model"));
|
qemu_opt_get(opts, "security_model"));
|
||||||
|
socket = qemu_opt_get(opts, "socket");
|
||||||
|
if (socket) {
|
||||||
|
qemu_opt_set(fsdev, "socket", socket);
|
||||||
|
}
|
||||||
sock_fd = qemu_opt_get(opts, "sock_fd");
|
sock_fd = qemu_opt_get(opts, "sock_fd");
|
||||||
if (sock_fd) {
|
if (sock_fd) {
|
||||||
qemu_opt_set(fsdev, "sock_fd", sock_fd);
|
qemu_opt_set(fsdev, "sock_fd", sock_fd);
|
||||||
|
Loading…
Reference in New Issue
Block a user