: Use GLib threadpool in 9pfs.
cover : Use GLib threadpool in 9pfs.
Hi,
This patchset enables the use of GLib threadpool infrastructure in 9pfs. It contains the following patches:
1/3 - Move the paio_signal_handler to a generic location. 2/3 - Helper routines to use GLib threadpool infrastructure in 9pfs. 3/3 - Convert v9fs_stat to threaded model.
As a prerequisite, before these patches are applied, we need to apply Anthony's patch "Add support for glib based threading and convert qemu thread to use it" found at
http://www.mail-archive.com/[email protected]/msg52791.html
Testing carried out:
This patchset has been tested by running the following autotest suites successfully:
* Dbench
* Fsstress
* Connecthon
* Tuxera POSIX.
Please let me know your comments.
-arun
PATCH 1/3 : Move the paio_signal_handler to a generic location.
* Arun R Bharadwaj <[email protected]> [2011-03-15 16:04:53]:
Author: Arun R Bharadwaj <[email protected]> Date: Thu Mar 10 14:45:25 2011 +0530
Move the paio_signal_handler to a generic location.
The paio subsystem uses the signal, SIGUSR2. So move the signal handler to a more generic place such that other subsystems like 9pfs can also use it.
TODO: I have moved the signal handler code to qemu-thread.c, which is NOT the right place. I need suggestions as to where is the right place to put it.
posix-aio-compat.c +12 -22
@@ -28,6 +28,7 @@#include "qemu-common.h" #include "trace.h" #include "block_int.h" +#include "qemu-thread.h" #include "block/raw-posix-aio.h"
@@ -302,6 +303,8 @@ static ssize_t handle_aiocb_rw(struct qemu_paiocb *aiocb)return nbytes; } +static PosixAioState *posix_aio_state; +static void *aio_thread (void *unused) {pid_t pid;
@@ -356,6 +359,15 @@ static void *aio_thread(void *unused) idle_threads++;mutex_unlock (&lock); +if (posix_aio_state) { +char byte =0 ; +ssize_t ret; + + ret =write (posix_aio_state->wfd, &byte,sizeof (byte)); +if (ret <0 && errno !=EAGAIN ) +die ("write()" ); + } +if (kill (pid, aiocb->ev_signo))die ("kill failed" ); }
@@ -497,22 +509,6 @@ static int posix_aio_flush(void *opaque)return !!s->first_aio; } -static PosixAioState *posix_aio_state; - -static void aio_signal_handler (int signum) -{ -if (posix_aio_state) { -char byte =0 ; -ssize_t ret; - - ret =write (posix_aio_state->wfd, &byte,sizeof (byte)); -if (ret <0 && errno !=EAGAIN ) -die ("write()" ); - } - -qemu_service_io (); -} -static void paio_remove (struct qemu_paiocb *acb) {struct qemu_paiocb **pacb;
@@ -616,7 +612,6 @@ BlockDriverAIOCB *paio_ioctl(BlockDriverState *bs, int fd,int paio_init (void ) { -struct sigaction act;PosixAioState *s;int fds[2 ];int ret;
@@ -626,11 +621,6 @@ int paio_init(void) s =qemu_malloc (sizeof (PosixAioState)); -sigfillset (&act.sa_mask); - act.sa_flags =0 ;/* do not restart syscalls to interrupt select() */ - act.sa_handler = aio_signal_handler; -sigaction (SIGUSR2 , &act,NULL ); - s->first_aio =NULL ;if (qemu_pipe (fds) ==-1 ) {fprintf (stderr,"failed to create pipe\n" );
qemu-thread.c +15 -0
@@ -149,3 +149,18 @@ void qemu_thread_exit(void *retval) {g_thread_exit (retval); } + +void sigusr2_signal_handler (int signum) +{ +qemu_service_io (); +} + +void register_sigusr2_signal_handler (void ) +{ +struct sigaction act; + +sigfillset (&act.sa_mask); + act.sa_flags =0 ;/* do not restart syscalls to interrupt select() */ + act.sa_handler = sigusr2_signal_handler; +sigaction (SIGUSR2 , &act,NULL ); +}
qemu-thread.h +2 -0
@@ -41,5 +41,7 @@ void qemu_thread_signal(QemuThread *thread, int sig);void qemu_thread_self (QemuThread *thread);int qemu_thread_equal (QemuThread *thread1,QemuThread *thread2);void qemu_thread_exit (void *retval); +void sigusr2_signal_handler (int signum); +void register_sigusr2_signal_handler (void );#endif
vl.c +3 -0
@@ -148,6 +148,7 @@ int main(int argc, char **argv)#include "qemu-config.h" #include "qemu-objects.h" #include "qemu-options.h" +#include "qemu-thread.h" #ifdef CONFIG_VIRTFS #include "fsdev/qemu-fsdev.h" #endif
@@ -3003,6 +3004,8 @@ int main(int argc, char **argv, char **envp) } } +register_sigusr2_signal_handler (); +if (qemu_opts_foreach (qemu_find_opts ("mon" ), mon_init_func,NULL ,1 ) !=0 ) {exit (1 ); }
[Qemu-devel] Re: [v1 PATCH 1/3]: Move the paio_signal_handler to a generic location.
Quoted 7 lines · Arun R Bharadwaj
* Arun R Bharadwaj <[email protected]> [2011-03-15 16:04:53]:
Author: Arun R Bharadwaj <[email protected]>
Date: Thu Mar 10 14:45:25 2011 +0530Move the
paio_signal_handlerto a generic location.
Quoted 7 lines
The paio subsystem uses the signal, SIGUSR2. So move the signal handler to a more generic place such that other subsystems like 9pfs can also use it.
TODO: I have moved the signal handler code to
qemu-thread.c, which is NOT the right place. I need suggestions as to where is the right place to put it.
I think os-posix.c would be appropriate. Please check how this affects Windows host and linux-user builds.
posix-aio-compat.c static void *aio_thread(void *unused) · line 362
Quoted 5 lines
posix-aio-compat.c +1
-0@@ -356,6 +359,15 @@ static void *aio_thread(void *unused) idle_threads++; mutex_unlock(&lock); + if (posix_aio_state) {
If we get here posix_aio_state must be non-NULL. Please remove the check.
qemu-thread.c void qemu_thread_exit(void *retval) · line 153
Quoted 1 line
qemu-thread.c +1
-0+void sigusr2_signal_handler (int signum)
static void sigusr2_signal_handler(int signum)
Stefan
[Qemu-devel] Re: [v1 PATCH 1/3]: Move the paio_signal_handler to a generic location.
Quoted 13 lines · Stefan Hajnoczi
Quoted 11 lines · Arun R Bharadwaj
* Arun R Bharadwaj <[email protected]> [2011-03-15 16:04:53]:
Author: Arun R Bharadwaj <[email protected]>
Date: Thu Mar 10 14:45:25 2011 +0530Move the
paio_signal_handlerto a generic location.The paio subsystem uses the signal, SIGUSR2. So move the signal handler to a more generic place such that other subsystems like 9pfs can also use it.
Quoted 7 lines
Quoted 3 lines
TODO: I have moved the signal handler code to
qemu-thread.c, which is NOT the right place. I need suggestions as to where is the right place to put it.I think
os-posix.cwould be appropriate. Please check how this affects Windows host and linux-user builds.
Anthony's reply negates this point. I will remove the signalling code and also check the behaviour of Windows host and linux-user builds.
Quoted 8 lines
posix-aio-compat.c static void *aio_thread(void *unused) · line 362
Quoted 5 lines
posix-aio-compat.c +1
-0@@ -356,6 +359,15 @@ static void *aio_thread(void *unused) idle_threads++; mutex_unlock(&lock); + if (posix_aio_state) {If we get here
posix_aio_statemust be non-NULL. Please remove the check.
Yes, will remove this.
Quoted 4 lines
qemu-thread.c void qemu_thread_exit(void *retval) · line 153
Quoted 1 line
qemu-thread.c +1
-0+void sigusr2_signal_handler (int signum)static void
sigusr2_signal_handler(int signum)
Thanks for noticing this.
Quoted 1 line
Stefan
PATCH 2/3 : Helper routines to use GLib threadpool infrastructure in 9pfs.
In reply to Arun R Bharadwaj* Arun R Bharadwaj <[email protected]> [2011-03-15 16:04:53]:
Author: Arun R Bharadwaj <[email protected]> Date: Thu Mar 10 15:11:49 2011 +0530
Helper routines to use GLib threadpool infrastructure in 9pfs.
This patch creates helper routines to make use of the threadpool infrastructure provided by GLib. This is based on the prototype patch by Anthony which does a similar thing for posix-aio-compat.c
An example use case is provided in the next patch where one of the syscalls in 9pfs is converted into the threaded model using these helper routines.
hw/9pfs/virtio-9p.c +103 -1
@@ -18,6 +18,8 @@#include "fsdev/qemu-fsdev.h" #include "virtio-9p-debug.h" #include "virtio-9p-xattr.h" +#include "signal.h" +#include "qemu-thread.h" int debug_9p_pdu;static void v9fs_reclaim_fd (V9fsState *s);
@@ -36,6 +38,89 @@ enum { Oappend = 0x80, }; +typedef struct V9fsPool { +GThreadPool *pool; +GList *requests; +int rfd; +int wfd; +}V9fsPool ; + +static V9fsPool v9fs_pool; + +static void v9fs_qemu_submit_request (V9fsRequest *req) +{ +V9fsPool *p = &v9fs_pool; + + p->requests =g_list_append (p->requests, req); +g_thread_pool_push (v9fs_pool.pool, req,NULL ); +} + +static void die2 (int err,const char *what) +{ +fprintf (stderr,"%s failed: %s\n" , what,strerror (err)); +abort (); +} + +static void die (const char *what) +{ +die2 (errno, what); +} + +static void v9fs_qemu_process_post_ops (void *arg) +{ +struct V9fsPool *p = &v9fs_pool; +struct V9fsPostOp *post_op; +char byte; +ssize_t len; +GList *cur_req, *next_req; + +do { + len =read (p->rfd, &byte,sizeof (byte)); + }while (len ==-1 && errno ==EINTR ); + +for (cur_req = p->requests; cur_req !=NULL ; cur_req = next_req) { +V9fsRequest *req = cur_req->data; + next_req =g_list_next (cur_req); + +if (!req->done) { +continue ; + } + + post_op = &req->post_op; + post_op->func (post_op->arg); + p->requests =g_list_remove_link (p->requests, cur_req); +g_list_free (p->requests); + } +} + +static inline void v9fs_thread_signal (void ) +{ +struct V9fsPool *p = &v9fs_pool; +char byte =0 ; +ssize_t ret; + +do { + ret =write (p->wfd, &byte,sizeof (byte)); + }while (ret ==-1 && errno ==EINTR ); + +if (ret <0 && errno !=EAGAIN ) { +die ("write() in v9fs" ); + } + +if (kill (getpid (),SIGUSR2 )) { +die ("kill failed" ); + } +} + +static void v9fs_thread_routine (gpointer data,gpointer user_data) +{ +V9fsRequest *req = data; + + req->func (req); +v9fs_thread_signal (); + req->done =1 ; +} +static int omode_to_uflags (int8_t mode) {int ret =0 ;
@@ -3850,7 +3935,8 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)int i, len;struct stat stat;FsTypeEntry *fse; - +int fds[2 ]; +V9fsPool *p = &v9fs_pool; s = (V9fsState *)virtio_common_init("virtio-9p", VIRTIO_ID_9P,
@@ -3939,5 +4025,21 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) s->tag_len; s->vdev.get_config = virtio_9p_get_config; +if (qemu_pipe (fds) ==-1 ) { +fprintf (stderr,"failed to create fd's for virtio-9p\n" ); +exit (1 ); + } + + p->pool =g_thread_pool_new (v9fs_thread_routine, p,8 , FALSE,NULL ); + p->rfd = fds[0 ]; + p->wfd = fds[1 ]; + +fcntl (p->rfd,F_SETFL ,O_NONBLOCK ); +fcntl (p->wfd,F_SETFL ,O_NONBLOCK ); + +qemu_set_fd_handler (p->rfd, v9fs_qemu_process_post_ops,NULL ,NULL ); + + (void ) v9fs_qemu_submit_request; +return &s->vdev; }
hw/9pfs/virtio-9p.h +14 -0
@@ -124,6 +124,20 @@ struct V9fsPDUQLIST_ENTRY (V9fsPDU) next; }; +typedef struct V9fsPostOp { +/* Post Operation routine to execute after executing syscall */ +void (*func)(void *arg); +void *arg; +}V9fsPostOp ; + +typedef struct V9fsRequest { +void (*func)(struct V9fsRequest *req); + +/* Flag to indicate that request is satisfied, ready for post-processing */ +int done; + +V9fsPostOp post_op; +}V9fsRequest ;/* FIXME * 1) change user needs to set groups and stuff
Re: [Qemu-devel] [v1 PATCH 2/3]: Helper routines to use GLib threadpool infrastructure in 9pfs.
Quoted 96 lines · Arun R Bharadwaj
* Arun R Bharadwaj<[email protected]> [2011-03-15 16:04:53]:
Author: Arun R Bharadwaj<[email protected]> Date: Thu Mar 10 15:11:49 2011 +0530Helper routines to use GLib threadpool infrastructure in 9pfs.
This patch creates helper routines to make use of the threadpool infrastructure provided by GLib. This is based on the prototype patch by Anthony which does a similar thing for
posix-aio-compat.cAn example use case is provided in the next patch where one of the syscalls in 9pfs is converted into the threaded model using these helper routines.
Signed-off-by Arun R Bharadwaj<[email protected]>Reviewed-by Aneesh Kumar K.V<[email protected]>hw/9pfs/virtio-9p.c +62
-0@@ -18,6 +18,8 @@#include "fsdev/qemu-fsdev.h" #include "virtio-9p-debug.h" #include "virtio-9p-xattr.h" +#include "signal.h" +#include "qemu-thread.h" int debug_9p_pdu;static void v9fs_reclaim_fd (V9fsState *s);@@ -36,6 +38,89 @@ enum { Oappend = 0x80, }; +typedef struct V9fsPool { +GThreadPool *pool; +GList *requests; +int rfd; +int wfd; +}V9fsPool ; + +static V9fsPool v9fs_pool; + +static void v9fs_qemu_submit_request (V9fsRequest *req) +{ +V9fsPool *p =&v9fs_pool; + + p->requests =g_list_append (p->requests, req); +g_thread_pool_push (v9fs_pool.pool, req,NULL ); +} + +static void die2 (int err,const char *what) +{ +fprintf (stderr,"%s failed: %s\n" , what,strerror (err)); +abort (); +} + +static void die (const char *what) +{ +die2 (errno, what); +} + +static void v9fs_qemu_process_post_ops (void *arg) +{ +struct V9fsPool *p =&v9fs_pool; +struct V9fsPostOp *post_op; +char byte; +ssize_t len; +GList *cur_req, *next_req; + +do { + len =read (p->rfd,&byte,sizeof (byte)); + }while (len ==-1 && errno ==EINTR ); + +for (cur_req = p->requests; cur_req !=NULL ; cur_req = next_req) { +V9fsRequest *req = cur_req->data; + next_req =g_list_next (cur_req); + +if (!req->done) { +continue ; + } + + post_op =&req->post_op; + post_op->func (post_op->arg); + p->requests =g_list_remove_link (p->requests, cur_req); +g_list_free (p->requests); + } +} + +static inline void v9fs_thread_signal (void ) +{ +struct V9fsPool *p =&v9fs_pool; +char byte =0 ; +ssize_t ret;
hw/9pfs/virtio-9p.c enum { · line 110
Quoted 10 lines
hw/9pfs/virtio-9p.c +10
-0+ +do { + ret =write (p->wfd,&byte,sizeof (byte)); + }while (ret ==-1 && errno ==EINTR ); + +if (ret<0 && errno !=EAGAIN ) { +die ("write() in v9fs" ); + } + +if (kill (getpid (),SIGUSR2 )) {
Not sure whether using pthread_kill or qemu_thread_signal is better to go with?
hw/9pfs/virtio-9p.c enum { · line 121
Quoted 11 lines
hw/9pfs/virtio-9p.c +11
-0+die ("kill failed" ); + } +} + +static void v9fs_thread_routine (gpointer data,gpointer user_data) +{ +V9fsRequest *req = data; + + req->func (req); +v9fs_thread_signal (); + req->done =1 ;
Shouldn't it be in reverse order, setting flag first and then signal:
req->done = 1;
v9fs_thread_signal();Quoted 24 lines
hw/9pfs/virtio-9p.c +9
-1+} +static int omode_to_uflags (int8_t mode) {int ret =0 ;@@ -3850,7 +3935,8 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)int i, len;struct stat stat;FsTypeEntry *fse; - +int fds[2 ]; +V9fsPool *p =&v9fs_pool; s = (V9fsState *)virtio_common_init("virtio-9p", VIRTIO_ID_9P,@@ -3939,5 +4025,21 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) s->tag_len; s->vdev.get_config = virtio_9p_get_config; +if (qemu_pipe (fds) ==-1 ) { +fprintf (stderr,"failed to create fd's for virtio-9p\n" ); +exit (1 ); + } +
hw/9pfs/virtio-9p.c VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) · line 4042
Quoted 10 lines
hw/9pfs/virtio-9p.c +10
-0+ p->pool =g_thread_pool_new (v9fs_thread_routine, p,8 , FALSE,NULL ); + p->rfd = fds[0 ]; + p->wfd = fds[1 ]; + +fcntl (p->rfd,F_SETFL ,O_NONBLOCK ); +fcntl (p->wfd,F_SETFL ,O_NONBLOCK ); + +qemu_set_fd_handler (p->rfd, v9fs_qemu_process_post_ops,NULL ,NULL ); + + (void ) v9fs_qemu_submit_request;
Do we really need it ^ ?
- Harsh
Quoted 30 lines
hw/9pfs/virtio-9p.c +1
-0+return &s->vdev; }hw/9pfs/virtio-9p.h +14
-0@@ -124,6 +124,20 @@ struct V9fsPDUQLIST_ENTRY (V9fsPDU) next; }; +typedef struct V9fsPostOp { +/* Post Operation routine to execute after executing syscall */ +void (*func)(void *arg); +void *arg; +}V9fsPostOp ; + +typedef struct V9fsRequest { +void (*func)(struct V9fsRequest *req); + +/* Flag to indicate that request is satisfied, ready for post-processing */ +int done; + +V9fsPostOp post_op; +}V9fsRequest ;/* FIXME * 1) change user needs to set groups and stuff
Re: [Qemu-devel] [v1 PATCH 2/3]: Helper routines to use GLib threadpool infrastructure in 9pfs.
Quoted 102 lines · Harsh Bora
Quoted 101 lines · Arun R Bharadwaj
* Arun R Bharadwaj<[email protected]> [2011-03-15 16:04:53]:
Author: Arun R Bharadwaj<[email protected]> Date: Thu Mar 10 15:11:49 2011 +0530Helper routines to use GLib threadpool infrastructure in 9pfs.
This patch creates helper routines to make use of the threadpool infrastructure provided by GLib. This is based on the prototype patch by Anthony which does a similar thing for
posix-aio-compat.cAn example use case is provided in the next patch where one of the syscalls in 9pfs is converted into the threaded model using these helper routines.
Signed-off-by Arun R Bharadwaj<[email protected]>Reviewed-by Aneesh Kumar K.V<[email protected]>hw/9pfs/virtio-9p.c +67
-0@@ -18,6 +18,8 @@#include "fsdev/qemu-fsdev.h" #include "virtio-9p-debug.h" #include "virtio-9p-xattr.h" +#include "signal.h" +#include "qemu-thread.h" int debug_9p_pdu;static void v9fs_reclaim_fd (V9fsState *s);@@ -36,6 +38,89 @@ enum { Oappend = 0x80, }; +typedef struct V9fsPool { +GThreadPool *pool; +GList *requests; +int rfd; +int wfd; +}V9fsPool ; + +static V9fsPool v9fs_pool; + +static void v9fs_qemu_submit_request (V9fsRequest *req) +{ +V9fsPool *p =&v9fs_pool; + + p->requests =g_list_append (p->requests, req); +g_thread_pool_push (v9fs_pool.pool, req,NULL ); +} + +static void die2 (int err,const char *what) +{ +fprintf (stderr,"%s failed: %s\n" , what,strerror (err)); +abort (); +} + +static void die (const char *what) +{ +die2 (errno, what); +} + +static void v9fs_qemu_process_post_ops (void *arg) +{ +struct V9fsPool *p =&v9fs_pool; +struct V9fsPostOp *post_op; +char byte; +ssize_t len; +GList *cur_req, *next_req; + +do { + len =read (p->rfd,&byte,sizeof (byte)); + }while (len ==-1 && errno ==EINTR ); + +for (cur_req = p->requests; cur_req !=NULL ; cur_req = next_req) { +V9fsRequest *req = cur_req->data; + next_req =g_list_next (cur_req); + +if (!req->done) { +continue ; + } + + post_op =&req->post_op; + post_op->func (post_op->arg); + p->requests =g_list_remove_link (p->requests, cur_req); +g_list_free (p->requests); + } +} + +static inline void v9fs_thread_signal (void ) +{ +struct V9fsPool *p =&v9fs_pool; +char byte =0 ; +ssize_t ret; + +do { + ret =write (p->wfd,&byte,sizeof (byte)); + }while (ret ==-1 && errno ==EINTR ); +
Quoted 9 lines
hw/9pfs/virtio-9p.c enum { · line 110
Quoted 5 lines
hw/9pfs/virtio-9p.c +5
-0+if (ret<0 && errno !=EAGAIN ) { +die ("write() in v9fs" ); + } + +if (kill (getpid (),SIGUSR2 )) {Not sure whether using
pthread_killorqemu_thread_signalis better to go with?
Please check the other replies. Looks like we don't really need signalling.
Quoted 44 lines
hw/9pfs/virtio-9p.c enum { · line 121
Quoted 11 lines
hw/9pfs/virtio-9p.c +11
-0+die ("kill failed" ); + } +} + +static void v9fs_thread_routine (gpointer data,gpointer user_data) +{ +V9fsRequest *req = data; + + req->func (req); +v9fs_thread_signal (); + req->done =1 ;Shouldn't it be in reverse order, setting flag first and then signal:
req->done = 1; v9fs_thread_signal();Quoted 28 lines
hw/9pfs/virtio-9p.c +13
-1+} +static int omode_to_uflags (int8_t mode) {int ret =0 ;@@ -3850,7 +3935,8 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)int i, len;struct stat stat;FsTypeEntry *fse; - +int fds[2 ]; +V9fsPool *p =&v9fs_pool; s = (V9fsState *)virtio_common_init("virtio-9p", VIRTIO_ID_9P,@@ -3939,5 +4025,21 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) s->tag_len; s->vdev.get_config = virtio_9p_get_config; +if (qemu_pipe (fds) ==-1 ) { +fprintf (stderr,"failed to create fd's for virtio-9p\n" ); +exit (1 ); + } + + p->pool =g_thread_pool_new (v9fs_thread_routine, p,8 , FALSE,NULL ); + p->rfd = fds[0 ]; + p->wfd = fds[1 ]; +
Quoted 9 lines
hw/9pfs/virtio-9p.c VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) · line 4042
Quoted 6 lines
hw/9pfs/virtio-9p.c +6
-0+fcntl (p->rfd,F_SETFL ,O_NONBLOCK ); +fcntl (p->wfd,F_SETFL ,O_NONBLOCK ); + +qemu_set_fd_handler (p->rfd, v9fs_qemu_process_post_ops,NULL ,NULL ); + + (void ) v9fs_qemu_submit_request;Do we really need it ^ ?
Yeah. Because till we make use of v9fs_qemu_submit_request() in the next patch, we will get a "v9fs_qemu_submit_request defined but not used" compile error.
Quoted 33 lines
- Harsh
Quoted 30 lines
hw/9pfs/virtio-9p.c +1
-0+return &s->vdev; }hw/9pfs/virtio-9p.h +14
-0@@ -124,6 +124,20 @@ struct V9fsPDUQLIST_ENTRY (V9fsPDU) next; }; +typedef struct V9fsPostOp { +/* Post Operation routine to execute after executing syscall */ +void (*func)(void *arg); +void *arg; +}V9fsPostOp ; + +typedef struct V9fsRequest { +void (*func)(struct V9fsRequest *req); + +/* Flag to indicate that request is satisfied, ready for post-processing */ +int done; + +V9fsPostOp post_op; +}V9fsRequest ;/* FIXME * 1) change user needs to set groups and stuff
[Qemu-devel] Re: [v1 PATCH 2/3]: Helper routines to use GLib threadpool infrastructure in 9pfs.
In reply to Arun R BharadwajQuoted 12 lines · Arun R Bharadwaj
* Arun R Bharadwaj<[email protected]> [2011-03-15 16:04:53]:
Author: Arun R Bharadwaj<[email protected]> Date: Thu Mar 10 15:11:49 2011 +0530Helper routines to use GLib threadpool infrastructure in 9pfs.
This patch creates helper routines to make use of the threadpool infrastructure provided by GLib. This is based on the prototype patch by Anthony which does a similar thing for
posix-aio-compat.c
Quoted 6 lines
An example use case is provided in the next patch where one of the syscalls in 9pfs is converted into the threaded model using these helper routines.
Signed-off-by Arun R Bharadwaj<[email protected]>Reviewed-by Aneesh Kumar K.V<[email protected]>
Why even bothering signaling for completion with the virtio-9p threadpool?
There's no sane guest that's going to poll on virtio-9p completion with interrupts disabled and no timer. Once we enable the I/O thread by default, it won't even be necessary for the paio layer.
Regards,
Anthony Liguori
Quoted 160 lines
hw/9pfs/virtio-9p.c +103
-1@@ -18,6 +18,8 @@#include "fsdev/qemu-fsdev.h" #include "virtio-9p-debug.h" #include "virtio-9p-xattr.h" +#include "signal.h" +#include "qemu-thread.h" int debug_9p_pdu;static void v9fs_reclaim_fd (V9fsState *s);@@ -36,6 +38,89 @@ enum { Oappend = 0x80, }; +typedef struct V9fsPool { +GThreadPool *pool; +GList *requests; +int rfd; +int wfd; +}V9fsPool ; + +static V9fsPool v9fs_pool; + +static void v9fs_qemu_submit_request (V9fsRequest *req) +{ +V9fsPool *p =&v9fs_pool; + + p->requests =g_list_append (p->requests, req); +g_thread_pool_push (v9fs_pool.pool, req,NULL ); +} + +static void die2 (int err,const char *what) +{ +fprintf (stderr,"%s failed: %s\n" , what,strerror (err)); +abort (); +} + +static void die (const char *what) +{ +die2 (errno, what); +} + +static void v9fs_qemu_process_post_ops (void *arg) +{ +struct V9fsPool *p =&v9fs_pool; +struct V9fsPostOp *post_op; +char byte; +ssize_t len; +GList *cur_req, *next_req; + +do { + len =read (p->rfd,&byte,sizeof (byte)); + }while (len ==-1 && errno ==EINTR ); + +for (cur_req = p->requests; cur_req !=NULL ; cur_req = next_req) { +V9fsRequest *req = cur_req->data; + next_req =g_list_next (cur_req); + +if (!req->done) { +continue ; + } + + post_op =&req->post_op; + post_op->func (post_op->arg); + p->requests =g_list_remove_link (p->requests, cur_req); +g_list_free (p->requests); + } +} + +static inline void v9fs_thread_signal (void ) +{ +struct V9fsPool *p =&v9fs_pool; +char byte =0 ; +ssize_t ret; + +do { + ret =write (p->wfd,&byte,sizeof (byte)); + }while (ret ==-1 && errno ==EINTR ); + +if (ret<0 && errno !=EAGAIN ) { +die ("write() in v9fs" ); + } + +if (kill (getpid (),SIGUSR2 )) { +die ("kill failed" ); + } +} + +static void v9fs_thread_routine (gpointer data,gpointer user_data) +{ +V9fsRequest *req = data; + + req->func (req); +v9fs_thread_signal (); + req->done =1 ; +} +static int omode_to_uflags (int8_t mode) {int ret =0 ;@@ -3850,7 +3935,8 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)int i, len;struct stat stat;FsTypeEntry *fse; - +int fds[2 ]; +V9fsPool *p =&v9fs_pool; s = (V9fsState *)virtio_common_init("virtio-9p", VIRTIO_ID_9P,@@ -3939,5 +4025,21 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) s->tag_len; s->vdev.get_config = virtio_9p_get_config; +if (qemu_pipe (fds) ==-1 ) { +fprintf (stderr,"failed to create fd's for virtio-9p\n" ); +exit (1 ); + } + + p->pool =g_thread_pool_new (v9fs_thread_routine, p,8 , FALSE,NULL ); + p->rfd = fds[0 ]; + p->wfd = fds[1 ]; + +fcntl (p->rfd,F_SETFL ,O_NONBLOCK ); +fcntl (p->wfd,F_SETFL ,O_NONBLOCK ); + +qemu_set_fd_handler (p->rfd, v9fs_qemu_process_post_ops,NULL ,NULL ); + + (void ) v9fs_qemu_submit_request; +return &s->vdev; }hw/9pfs/virtio-9p.h +14
-0@@ -124,6 +124,20 @@ struct V9fsPDUQLIST_ENTRY (V9fsPDU) next; }; +typedef struct V9fsPostOp { +/* Post Operation routine to execute after executing syscall */ +void (*func)(void *arg); +void *arg; +}V9fsPostOp ; + +typedef struct V9fsRequest { +void (*func)(struct V9fsRequest *req); + +/* Flag to indicate that request is satisfied, ready for post-processing */ +int done; + +V9fsPostOp post_op; +}V9fsRequest ;/* FIXME * 1) change user needs to set groups and stuff
[Qemu-devel] Re: [v1 PATCH 2/3]: Helper routines to use GLib threadpool infrastructure in 9pfs.
Quoted 22 lines · Anthony Liguori
Quoted 12 lines · Arun R Bharadwaj
* Arun R Bharadwaj<[email protected]> [2011-03-15 16:04:53]:
Author: Arun R Bharadwaj<[email protected]> Date: Thu Mar 10 15:11:49 2011 +0530Helper routines to use GLib threadpool infrastructure in 9pfs.
This patch creates helper routines to make use of the threadpool infrastructure provided by GLib. This is based on the prototype patch by Anthony which does a similar thing for
posix-aio-compat.cQuoted 6 lines
An example use case is provided in the next patch where one of the syscalls in 9pfs is converted into the threaded model using these helper routines.
Signed-off-by Arun R Bharadwaj<[email protected]>Reviewed-by Aneesh Kumar K.V<[email protected]>Why even bothering signaling for completion with the virtio-9p threadpool?
Quoted 8 lines
There's no sane guest that's going to poll on virtio-9p completion with interrupts disabled and no timer. Once we enable the I/O thread by default, it won't even be necessary for the paio layer.
Regards,
Anthony Liguori
Thanks for the information. I will remove the signalling part, test the code again and re-post.
Quoted 161 lines
Quoted 160 lines
hw/9pfs/virtio-9p.c +103
-1@@ -18,6 +18,8 @@#include "fsdev/qemu-fsdev.h" #include "virtio-9p-debug.h" #include "virtio-9p-xattr.h" +#include "signal.h" +#include "qemu-thread.h" int debug_9p_pdu;static void v9fs_reclaim_fd (V9fsState *s);@@ -36,6 +38,89 @@ enum { Oappend = 0x80, }; +typedef struct V9fsPool { +GThreadPool *pool; +GList *requests; +int rfd; +int wfd; +}V9fsPool ; + +static V9fsPool v9fs_pool; + +static void v9fs_qemu_submit_request (V9fsRequest *req) +{ +V9fsPool *p =&v9fs_pool; + + p->requests =g_list_append (p->requests, req); +g_thread_pool_push (v9fs_pool.pool, req,NULL ); +} + +static void die2 (int err,const char *what) +{ +fprintf (stderr,"%s failed: %s\n" , what,strerror (err)); +abort (); +} + +static void die (const char *what) +{ +die2 (errno, what); +} + +static void v9fs_qemu_process_post_ops (void *arg) +{ +struct V9fsPool *p =&v9fs_pool; +struct V9fsPostOp *post_op; +char byte; +ssize_t len; +GList *cur_req, *next_req; + +do { + len =read (p->rfd,&byte,sizeof (byte)); + }while (len ==-1 && errno ==EINTR ); + +for (cur_req = p->requests; cur_req !=NULL ; cur_req = next_req) { +V9fsRequest *req = cur_req->data; + next_req =g_list_next (cur_req); + +if (!req->done) { +continue ; + } + + post_op =&req->post_op; + post_op->func (post_op->arg); + p->requests =g_list_remove_link (p->requests, cur_req); +g_list_free (p->requests); + } +} + +static inline void v9fs_thread_signal (void ) +{ +struct V9fsPool *p =&v9fs_pool; +char byte =0 ; +ssize_t ret; + +do { + ret =write (p->wfd,&byte,sizeof (byte)); + }while (ret ==-1 && errno ==EINTR ); + +if (ret<0 && errno !=EAGAIN ) { +die ("write() in v9fs" ); + } + +if (kill (getpid (),SIGUSR2 )) { +die ("kill failed" ); + } +} + +static void v9fs_thread_routine (gpointer data,gpointer user_data) +{ +V9fsRequest *req = data; + + req->func (req); +v9fs_thread_signal (); + req->done =1 ; +} +static int omode_to_uflags (int8_t mode) {int ret =0 ;@@ -3850,7 +3935,8 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)int i, len;struct stat stat;FsTypeEntry *fse; - +int fds[2 ]; +V9fsPool *p =&v9fs_pool; s = (V9fsState *)virtio_common_init("virtio-9p", VIRTIO_ID_9P,@@ -3939,5 +4025,21 @@ VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf) s->tag_len; s->vdev.get_config = virtio_9p_get_config; +if (qemu_pipe (fds) ==-1 ) { +fprintf (stderr,"failed to create fd's for virtio-9p\n" ); +exit (1 ); + } + + p->pool =g_thread_pool_new (v9fs_thread_routine, p,8 , FALSE,NULL ); + p->rfd = fds[0 ]; + p->wfd = fds[1 ]; + +fcntl (p->rfd,F_SETFL ,O_NONBLOCK ); +fcntl (p->wfd,F_SETFL ,O_NONBLOCK ); + +qemu_set_fd_handler (p->rfd, v9fs_qemu_process_post_ops,NULL ,NULL ); + + (void ) v9fs_qemu_submit_request; +return &s->vdev; }hw/9pfs/virtio-9p.h +14
-0@@ -124,6 +124,20 @@ struct V9fsPDUQLIST_ENTRY (V9fsPDU) next; }; +typedef struct V9fsPostOp { +/* Post Operation routine to execute after executing syscall */ +void (*func)(void *arg); +void *arg; +}V9fsPostOp ; + +typedef struct V9fsRequest { +void (*func)(struct V9fsRequest *req); + +/* Flag to indicate that request is satisfied, ready for post-processing */ +int done; + +V9fsPostOp post_op; +}V9fsRequest ;/* FIXME * 1) change user needs to set groups and stuff
[Qemu-devel] Re: [v1 PATCH 2/3]: Helper routines to use GLib threadpool infrastructure in 9pfs.
In reply to Anthony LiguoriQuoted 5 lines · Anthony Liguori
Why even bothering signaling for completion with the virtio-9p threadpool?
There's no sane guest that's going to poll on virtio-9p completion with interrupts disabled and no timer. Once we enable the I/O thread by default, it won't even be necessary for the paio layer.
It's not just about preventing livelock under extreme cases. If you omit the signal then !CONFIG_IOTHREAD builds will see increased latency because virtfs request completion will piggy-back on other events that *do* interrupt the vcpu. I'm no fan of !CONFIG_IOTHREAD but skipping signals is currently bad practice and will continue to be until CONFIG_IOTHREAD is removed entirely.
The proper solution would be a thin abstraction for thread-safe notification that compiles out signals when CONFIG_IOTHREAD is used. Then we have one place in QEMU that does signalling correctly and we can optimize it or remove CONFIG_IOTHREAD completely without having the burden of duplicating this code in several places.
Stefan
[Qemu-devel] Re: [v1 PATCH 2/3]: Helper routines to use GLib threadpool infrastructure in 9pfs.
Quoted 10 lines · Stefan Hajnoczi
Quoted 5 lines · Anthony Liguori
Why even bothering signaling for completion with the virtio-9p threadpool?
There's no sane guest that's going to poll on virtio-9p completion with interrupts disabled and no timer. Once we enable the I/O thread by default, it won't even be necessary for the paio layer.
It's not just about preventing livelock under extreme cases. If you omit the signal then !CONFIG_IOTHREAD builds will see increased latency because virtfs request completion will piggy-back on other events that *do* interrupt the vcpu.
But realistically, the timer is firing at a high enough frequency that I doubt you'd even observe the latency.
There's an easy solution here, just do some sniff testing to see if you can tell the difference. I bet you can't.
Quoted 9 lines
I'm no fan of !CONFIG_IOTHREAD
but skipping signals is currently bad practice and will continue to be untilCONFIG_IOTHREADis removed entirely.The proper solution would be a thin abstraction for thread-safe notification that compiles out signals when
CONFIG_IOTHREADis used. Then we have one place in QEMU that does signalling correctly and we can optimize it or removeCONFIG_IOTHREADcompletely without having the burden of duplicating this code in several places.
We have probably 5 different ways to wake up a CPU. I don't think we should add a new one just for this.
!CONFIG_IOTHREAD needs to go away in the very near future. I'd rather focus on that.
Regards,
Anthony Liguori
Quoted 1 line
Stefan
[Qemu-devel] Re: [v1 PATCH 2/3]: Helper routines to use GLib threadpool infrastructure in 9pfs.
Quoted 28 lines · Anthony Liguori
Quoted 10 lines · Stefan Hajnoczi
Quoted 5 lines · Anthony Liguori
Why even bothering signaling for completion with the virtio-9p threadpool?
There's no sane guest that's going to poll on virtio-9p completion with interrupts disabled and no timer. Once we enable the I/O thread by default, it won't even be necessary for the paio layer.
It's not just about preventing livelock under extreme cases. If you omit the signal then !CONFIG_IOTHREAD builds will see increased latency because virtfs request completion will piggy-back on other events that *do* interrupt the vcpu.
But realistically, the timer is firing at a high enough frequency that I doubt you'd even observe the latency.
There's an easy solution here, just do some sniff testing to see if you can tell the difference. I bet you can't.
Quoted 9 lines
I'm no fan of !CONFIG_IOTHREAD
but skipping signals is currently bad practice and will continue to be untilCONFIG_IOTHREADis removed entirely.The proper solution would be a thin abstraction for thread-safe notification that compiles out signals when
CONFIG_IOTHREADis used. Then we have one place in QEMU that does signalling correctly and we can optimize it or removeCONFIG_IOTHREADcompletely without having the burden of duplicating this code in several places.
Quoted 5 lines
We have probably 5 different ways to wake up a CPU. I don't think we should add a new one just for this.
!CONFIG_IOTHREAD needs to go away in the very near future. I'd rather focus on that.
If that is the case, how about making VirtFS dependent on CONFIG_IOTHREAD during the configuration? This can help even if !CONFIG_IOTHREAD lingers around for some more time and would avoid any of the Stefan's concerns.
- JV
Quoted 7 lines
Regards,
Anthony Liguori
Quoted 1 line
Stefan
[Qemu-devel] Re: [v1 PATCH 2/3]: Helper routines to use GLib threadpool infrastructure in 9pfs.
Quoted 32 lines · Venkateswararao Jujjuri (JV)
Quoted 31 lines · Anthony Liguori
Quoted 10 lines · Stefan Hajnoczi
Quoted 5 lines · Anthony Liguori
Why even bothering signaling for completion with the virtio-9p threadpool?
There's no sane guest that's going to poll on virtio-9p completion with interrupts disabled and no timer. Once we enable the I/O thread by default, it won't even be necessary for the paio layer.
It's not just about preventing livelock under extreme cases. If you omit the signal then !CONFIG_IOTHREAD builds will see increased latency because virtfs request completion will piggy-back on other events that *do* interrupt the vcpu.
But realistically, the timer is firing at a high enough frequency that I doubt you'd even observe the latency.
There's an easy solution here, just do some sniff testing to see if you can tell the difference. I bet you can't.
Quoted 9 lines
I'm no fan of !CONFIG_IOTHREAD
but skipping signals is currently bad practice and will continue to be untilCONFIG_IOTHREADis removed entirely.The proper solution would be a thin abstraction for thread-safe notification that compiles out signals when
CONFIG_IOTHREADis used. Then we have one place in QEMU that does signalling correctly and we can optimize it or removeCONFIG_IOTHREADcompletely without having the burden of duplicating this code in several places.We have probably 5 different ways to wake up a CPU. I don't think we should add a new one just for this.
Quoted 6 lines
Quoted 2 lines
!CONFIG_IOTHREAD needs to go away in the very near future. I'd rather focus on that.
If that is the case, how about making VirtFS dependent on
CONFIG_IOTHREADduring the configuration? This can help even if !CONFIG_IOTHREAD lingers around for some more time and would avoid any of the Stefan's concerns.
Sounds fair.
Stefan
PATCH 3/3 : Convert v9fs_stat to threaded model.
In reply to Arun R Bharadwaj* Arun R Bharadwaj <[email protected]> [2011-03-15 16:04:53]:
Author: Harsh Prateek Bora <[email protected]> Date: Mon Mar 14 13:55:37 2011 +0530
Convert v9fs_stat to threaded model.
This patch converts v9fs_stat syscall of 9pfs to threaded model by making use of the helper routines provided created by the previous patch.
hw/9pfs/virtio-9p.c +23 -7
@@ -1458,26 +1458,35 @@ out:v9fs_string_free (&aname); } -static void v9fs_stat_post_lstat (V9fsState *s,V9fsStatState *vs,int err) +static void v9fs_stat_post_lstat (void *opaque) { -if (err ==-1 ) { - err = -errno; +V9fsStatState *vs = (V9fsStatState *)opaque; +if (vs->err ==-1 ) { + vs->err = -(vs->v9fs_errno); goto out; } - err =stat_to_v9stat (s, &vs->fidp->fsmap.path, &vs->stbuf, &vs->v9stat); -if (err) { + vs->err =stat_to_v9stat (vs->s, &vs->fidp->fsmap.path, &vs->stbuf, &vs->v9stat); +if (vs->err) { goto out; } vs->offset +=pdu_marshal (vs->pdu, vs->offset,"wS" ,0 , &vs->v9stat); - err = vs->offset; + vs->err = vs->offset; out: -complete_pdu (s, vs->pdu, err); +complete_pdu (vs->s, vs->pdu, vs->err);v9fs_stat_free (&vs->v9stat);qemu_free (vs); } +static void v9fs_stat_do_lstat (V9fsRequest *request) +{ +V9fsStatState *vs =container_of (request, V9fsStatState, request); + + vs->err =v9fs_do_lstat (vs->s, &vs->fidp->fsmap.path, &vs->stbuf); + vs->v9fs_errno = errno; +} +static void v9fs_stat (V9fsState *s,V9fsPDU *pdu) {int32_t fid;
@@ -1487,6 +1496,10 @@ static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) vs =qemu_malloc (sizeof (*vs)); vs->pdu = pdu; vs->offset =7 ; + vs->s = s; + vs->request.func = v9fs_stat_do_lstat; + vs->request.post_op.func = v9fs_stat_post_lstat; + vs->request.post_op.arg = vs;memset (&vs->v9stat,0 ,sizeof (vs->v9stat));
@@ -1498,8 +1511,11 @@ static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) goto out; } +/* err = v9fs_do_lstat(s, &vs->fidp->fsmap.path, &vs->stbuf); v9fs_stat_post_lstat(s, vs, err); +*/ +v9fs_qemu_submit_request (&vs->request);return ; out:
hw/9pfs/virtio-9p.h +4 -0
@@ -271,6 +271,10 @@ typedef struct V9fsStatState {V9fsStat v9stat;V9fsFidState *fidp;struct stat stbuf; +V9fsState *s; +int err; +int v9fs_errno; +V9fsRequest request; } V9fsStatState; typedef struct V9fsStatDotl {
[Qemu-devel] Re: [v1 PATCH 3/3]: Convert v9fs_stat to threaded model.
Quoted 6 lines · Arun R Bharadwaj
hw/9pfs/virtio-9p.c +1
-1-static void v9fs_stat_post_lstat (V9fsState *s,V9fsStatState *vs,int err) +static void v9fs_stat_post_lstat (void *opaque){
- if (err == -1) {
- err = -errno;
+ V9fsStatState *vs = (V9fsStatState *)opaque;
No need to cast void* in C.
Quoted 2 lines
+ if (
vs->err== -1) {
+ vs->err = -(vs->v9fs_errno);
How about the thread worker function puts the -errno into a vs->ret field:
static void v9fs_stat_do_lstat(V9fsRequest *request)
{
V9fsStatState *vs = container_of(request, V9fsStatState, request);
vs->ret = v9fs_do_lstat(vs->s, &vs->fidp->fsmap.path, &vs->stbuf);
if (vs->ret != 0) {
vs->ret = -errno;
}
}Then v9fs_stat_post_lstat() can use vs->ret directly and does not need to juggle around the two fields, vs->err and vs->v9fs_errno.
Quoted 6 lines
goto out;
}- err =
stat_to_v9stat(s, &vs->fidp->fsmap.path, &vs->stbuf, &vs->v9stat);
- if (err) {
+ vs->err =stat_to_v9stat(vs->s, &vs->fidp->fsmap.path, &vs->stbuf, &vs->v9stat);
This function can block in v9fs_do_readlink(). Needs to be done asynchronously to avoid blocking QEMU.
Quoted 14 lines
+ if (
vs->err) {
goto out;
}
vs->offset+=pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
- err =vs->offset;
+ vs->err =vs->offset;out:
- complete_pdu(s,vs->pdu, err);
+ complete_pdu(vs->s,vs->pdu,vs->err);
v9fs_stat_free(&vs->v9stat);
qemu_free(vs);
}
hw/9pfs/virtio-9p.c out: · line 1484
Quoted 3 lines
hw/9pfs/virtio-9p.c +3
-0+static void v9fs_stat_do_lstat (V9fsRequest *request) +{ + V9fsStatState *vs = container_of(request, V9fsStatState, request);
Nice. Could container_of() be used for v9fs_post_lstat() too? I'm suggesting making post op functions take the V9fsRequest* instead of a void* opaque pointer.
Quoted 2 lines
+
+ vs->err =v9fs_do_lstat(vs->s, &vs->fidp->fsmap.path, &vs->stbuf);
This is not threadsafe since rpath still uses a static buffer in qemu.git. Please ensure that rpath() is thread-safe before pushing this patch.
Quoted 18 lines
+ vs->v9fs_errno = errno;
hw/9pfs/virtio-9p.c +2
-0+} +static void
v9fs_stat(V9fsState *s, V9fsPDU *pdu){
int32_tfid;hw/9pfs/virtio-9p.c +4
-0@@ -1487,6 +1496,10 @@ static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) vs = qemu_malloc(sizeof(*vs)); vs->pdu = pdu; vs->offset = 7; + vs->s = s; + vs->request.func = v9fs_stat_do_lstat; + vs->request.post_op.func = v9fs_stat_post_lstat; + vs->request.post_op.arg = vs; memset(&vs->v9stat, 0, sizeof(vs->v9stat));
hw/9pfs/virtio-9p.c static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) · line 1517
Quoted 7 lines
hw/9pfs/virtio-9p.c +2
-0@@ -1498,8 +1511,11 @@ static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) goto out; } + /*err = v9fs_do_lstat(s, &vs->fidp->fsmap.path, &vs->stbuf); v9fs_stat_post_lstat(s, vs, err); +*/
Please remove unused code, it quickly becomes out-of-date and confuses readers.
hw/9pfs/virtio-9p.c static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) · line 1518
Quoted 1 line
hw/9pfs/virtio-9p.c +1
-0+ v9fs_qemu_submit_request(&vs->request);
What happens when another PDU is handled next that uses the same fid? The worst case is if the client sends TCLUNK and fid is freed while the worker thread and later the post op still access the memory. There needs to be some kind of guard (like a reference count) to prevent this.
Stefan
[Qemu-devel] Re: [v1 PATCH 3/3]: Convert v9fs_stat to threaded model.
Quoted 61 lines · Stefan Hajnoczi
hw/9pfs/virtio-9p.c out: · line 1463
Quoted 6 lines · Arun R Bharadwaj
hw/9pfs/virtio-9p.c +2
-3-static void v9fs_stat_post_lstat (V9fsState *s,V9fsStatState *vs,int err) +static void v9fs_stat_post_lstat (void *opaque) { -if (err ==-1 ) { - err = -errno; +V9fsStatState *vs = (V9fsStatState *)opaque;No need to cast void* in C.
hw/9pfs/virtio-9p.c out: · line 1465
Quoted 2 lines
hw/9pfs/virtio-9p.c +2
-0+if (vs->err ==-1 ) { + vs->err = -(vs->v9fs_errno);How about the thread worker function puts the -errno into a
vs->retfield:static void
v9fs_stat_do_lstat(V9fsRequest *request){ V9fsStatState *vs = container_of(request, V9fsStatState, request); vs->ret = v9fs_do_lstat(vs->s, &vs->fidp->fsmap.path, &vs->stbuf); if (vs->ret != 0) { vs->ret = -errno; } }Then
v9fs_stat_post_lstat()can usevs->retdirectly and does not need to juggle around the two fields,vs->errandvs->v9fs_errno.hw/9pfs/virtio-9p.c out: · line 1469
Quoted 6 lines
goto out; }hw/9pfs/virtio-9p.c +1
-2- err =stat_to_v9stat (s, &vs->fidp->fsmap.path, &vs->stbuf, &vs->v9stat); -if (err) { + vs->err =stat_to_v9stat (vs->s, &vs->fidp->fsmap.path, &vs->stbuf, &vs->v9stat);This function can block in
v9fs_do_readlink(). Needs to be done asynchronously to avoid blocking QEMU.Quoted 7 lines
hw/9pfs/virtio-9p.c +2
-1+if (vs->err) { goto out; } vs->offset +=pdu_marshal (vs->pdu, vs->offset,"wS" ,0 , &vs->v9stat); - err = vs->offset; + vs->err = vs->offset;hw/9pfs/virtio-9p.c out: · line 1484
Quoted 10 lines
hw/9pfs/virtio-9p.c +4
-1out: -complete_pdu (s, vs->pdu, err); +complete_pdu (vs->s, vs->pdu, vs->err);v9fs_stat_free (&vs->v9stat);qemu_free (vs); } +static void v9fs_stat_do_lstat (V9fsRequest *request) +{ +V9fsStatState *vs =container_of (request, V9fsStatState, request);Nice. Could
container_of()be used forv9fs_post_lstat()too? I'm suggesting making post op functions take the V9fsRequest* instead of a void* opaque pointer.
Quoted 6 lines
hw/9pfs/virtio-9p.c out: · line 1486
Quoted 2 lines
hw/9pfs/virtio-9p.c +2
-0+ + vs->err =v9fs_do_lstat (vs->s, &vs->fidp->fsmap.path, &vs->stbuf);This is not threadsafe since rpath still uses a static buffer in qemu.git. Please ensure that
rpath()is thread-safe before pushing this patch.
There is another patch on the internal list to make rpath thread safe.
Quoted 29 lines
Quoted 19 lines
hw/9pfs/virtio-9p.c +7
-0+ vs->v9fs_errno = errno; +} +static void v9fs_stat (V9fsState *s,V9fsPDU *pdu) {int32_t fid;@@ -1487,6 +1496,10 @@ static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) vs =qemu_malloc (sizeof (*vs)); vs->pdu = pdu; vs->offset =7 ; + vs->s = s; + vs->request.func = v9fs_stat_do_lstat; + vs->request.post_op.func = v9fs_stat_post_lstat; + vs->request.post_op.arg = vs;memset (&vs->v9stat,0 ,sizeof (vs->v9stat));hw/9pfs/virtio-9p.c static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) · line 1517
Quoted 7 lines
hw/9pfs/virtio-9p.c +2
-0@@ -1498,8 +1511,11 @@ static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) goto out; } +/* err = v9fs_do_lstat(s, &vs->fidp->fsmap.path, &vs->stbuf); v9fs_stat_post_lstat(s, vs, err); +*/ Please remove unused code, it quickly becomes out-of-date and confuses readers.
Quoted 7 lines
hw/9pfs/virtio-9p.c static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) · line 1518
Quoted 1 line
hw/9pfs/virtio-9p.c +1
-0+v9fs_qemu_submit_request (&vs->request);What happens when another PDU is handled next that uses the same fid? The worst case is if the client sends TCLUNK and fid is freed while the worker thread and later the post op still access the memory. There needs to be some kind of guard (like a reference count) to prevent this.
As per the protocol this should not happen. Client is the controls the fid, and the fid is created or destroyed per the directive of the client. It should not send clunk until the response is received on that fid based operation(if there is any).
- JV
Quoted 2 lines
Stefan
[Qemu-devel] Re: [v1 PATCH 3/3]: Convert v9fs_stat to threaded model.
Quoted 108 lines · Venkateswararao Jujjuri (JV)
Quoted 61 lines · Stefan Hajnoczi
Quoted 6 lines · Arun R Bharadwaj
hw/9pfs/virtio-9p.c +1
-1-static void v9fs_stat_post_lstat (V9fsState *s,V9fsStatState *vs,int err) +static void v9fs_stat_post_lstat (void *opaque){
- if (err == -1) {
- err = -errno;
+ V9fsStatState *vs = (V9fsStatState *)opaque;No need to cast void* in C.
Quoted 2 lines
+ if (
vs->err== -1) {
+ vs->err = -(vs->v9fs_errno);How about the thread worker function puts the -errno into a
vs->retfield:static void
v9fs_stat_do_lstat(V9fsRequest *request)
{
V9fsStatState *vs =container_of(request, V9fsStatState, request);
vs->ret=v9fs_do_lstat(vs->s, &vs->fidp->fsmap.path, &vs->stbuf); if (vs->ret!= 0) {
vs->ret= -errno;
}
}Then
v9fs_stat_post_lstat()can usevs->retdirectly and does not need to juggle around the two fields,vs->errandvs->v9fs_errno.Quoted 6 lines
goto out;
}- err =
stat_to_v9stat(s, &vs->fidp->fsmap.path, &vs->stbuf, &vs->v9stat);
- if (err) {
+ vs->err =stat_to_v9stat(vs->s, &vs->fidp->fsmap.path, &vs->stbuf, &vs->v9stat);This function can block in
v9fs_do_readlink(). Needs to be done asynchronously to avoid blocking QEMU.Quoted 14 lines
+ if (
vs->err) {
goto out;
}
vs->offset+=pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
- err =vs->offset;
+ vs->err =vs->offset;out:
- complete_pdu(s,vs->pdu, err);
+ complete_pdu(vs->s,vs->pdu,vs->err);
v9fs_stat_free(&vs->v9stat);
qemu_free(vs);
}hw/9pfs/virtio-9p.c out: · line 1484
Quoted 3 lines
hw/9pfs/virtio-9p.c +3
-0+static void v9fs_stat_do_lstat (V9fsRequest *request) +{ + V9fsStatState *vs = container_of(request, V9fsStatState, request);Nice. Could
container_of()be used forv9fs_post_lstat()too? I'm suggesting making post op functions take the V9fsRequest* instead of a void* opaque pointer.Quoted 6 lines
Quoted 2 lines
+
+ vs->err =v9fs_do_lstat(vs->s, &vs->fidp->fsmap.path, &vs->stbuf);This is not threadsafe since rpath still uses a static buffer in qemu.git. Please ensure that
rpath()is thread-safe before pushing this patch.There is another patch on the internal list to make rpath thread safe.
Quoted 29 lines
Quoted 19 lines
+ vs->v9fs_errno = errno;
hw/9pfs/virtio-9p.c +2
-0+} +static void
v9fs_stat(V9fsState *s, V9fsPDU *pdu){
int32_tfid;hw/9pfs/virtio-9p.c +4
-0@@ -1487,6 +1496,10 @@ static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) vs = qemu_malloc(sizeof(*vs)); vs->pdu = pdu; vs->offset = 7; + vs->s = s; + vs->request.func = v9fs_stat_do_lstat; + vs->request.post_op.func = v9fs_stat_post_lstat; + vs->request.post_op.arg = vs; memset(&vs->v9stat, 0, sizeof(vs->v9stat));hw/9pfs/virtio-9p.c static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) · line 1517
Quoted 7 lines
hw/9pfs/virtio-9p.c +2
-0@@ -1498,8 +1511,11 @@ static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) goto out; } + /*err = v9fs_do_lstat(s, &vs->fidp->fsmap.path, &vs->stbuf); v9fs_stat_post_lstat(s, vs, err); +*/ Please remove unused code, it quickly becomes out-of-date and confuses readers.
Quoted 7 lines
hw/9pfs/virtio-9p.c static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) · line 1518
Quoted 1 line
hw/9pfs/virtio-9p.c +1
-0+ v9fs_qemu_submit_request(&vs->request);What happens when another PDU is handled next that uses the same fid? The worst case is if the client sends TCLUNK and fid is freed while the worker thread and later the post op still access the memory. There needs to be some kind of guard (like a reference count) to prevent this.
Quoted 4 lines
As per the protocol this should not happen. Client is the controls the fid, and the fid is created or destroyed per the directive of the client. It should not send clunk until the response is received on that fid based operation(if there is any).
Unfortunately it is still possible for a guest to do it. The model for emulated hardware is that the guest is untrusted and we cannot allow things to crash.
It's really important for everyone to keep this in mind otherwise security vulnerabilities will be introduced for use cases like hosting and cloud where the guest really cannot be trusted.
An easy fix is to mark a fid busy and reject requests that mess with it before the existing request has been processed.
Stefan
[Qemu-devel] Re: [v1 PATCH 3/3]: Convert v9fs_stat to threaded model.
Quoted 110 lines · Stefan Hajnoczi
Quoted 108 lines · Venkateswararao Jujjuri (JV)
Quoted 61 lines · Stefan Hajnoczi
hw/9pfs/virtio-9p.c out: · line 1463
Quoted 6 lines · Arun R Bharadwaj
hw/9pfs/virtio-9p.c +2
-3-static void v9fs_stat_post_lstat (V9fsState *s,V9fsStatState *vs,int err) +static void v9fs_stat_post_lstat (void *opaque) { -if (err ==-1 ) { - err = -errno; +V9fsStatState *vs = (V9fsStatState *)opaque;No need to cast void* in C.
hw/9pfs/virtio-9p.c out: · line 1465
Quoted 2 lines
hw/9pfs/virtio-9p.c +2
-0+if (vs->err ==-1 ) { + vs->err = -(vs->v9fs_errno);How about the thread worker function puts the -errno into a
vs->retfield:static void
v9fs_stat_do_lstat(V9fsRequest *request){ V9fsStatState *vs = container_of(request, V9fsStatState, request); vs->ret = v9fs_do_lstat(vs->s, &vs->fidp->fsmap.path, &vs->stbuf); if (vs->ret != 0) { vs->ret = -errno; } }Then
v9fs_stat_post_lstat()can usevs->retdirectly and does not need to juggle around the two fields,vs->errandvs->v9fs_errno.hw/9pfs/virtio-9p.c out: · line 1469
Quoted 6 lines
goto out; }hw/9pfs/virtio-9p.c +1
-2- err =stat_to_v9stat (s, &vs->fidp->fsmap.path, &vs->stbuf, &vs->v9stat); -if (err) { + vs->err =stat_to_v9stat (vs->s, &vs->fidp->fsmap.path, &vs->stbuf, &vs->v9stat);This function can block in
v9fs_do_readlink(). Needs to be done asynchronously to avoid blocking QEMU.Quoted 7 lines
hw/9pfs/virtio-9p.c +2
-1+if (vs->err) { goto out; } vs->offset +=pdu_marshal (vs->pdu, vs->offset,"wS" ,0 , &vs->v9stat); - err = vs->offset; + vs->err = vs->offset;hw/9pfs/virtio-9p.c out: · line 1484
Quoted 10 lines
hw/9pfs/virtio-9p.c +4
-1out: -complete_pdu (s, vs->pdu, err); +complete_pdu (vs->s, vs->pdu, vs->err);v9fs_stat_free (&vs->v9stat);qemu_free (vs); } +static void v9fs_stat_do_lstat (V9fsRequest *request) +{ +V9fsStatState *vs =container_of (request, V9fsStatState, request);Nice. Could
container_of()be used forv9fs_post_lstat()too? I'm suggesting making post op functions take the V9fsRequest* instead of a void* opaque pointer.Quoted 6 lines
hw/9pfs/virtio-9p.c out: · line 1486
Quoted 2 lines
hw/9pfs/virtio-9p.c +2
-0+ + vs->err =v9fs_do_lstat (vs->s, &vs->fidp->fsmap.path, &vs->stbuf);This is not threadsafe since rpath still uses a static buffer in qemu.git. Please ensure that
rpath()is thread-safe before pushing this patch.There is another patch on the internal list to make rpath thread safe.
Quoted 36 lines
Quoted 19 lines
hw/9pfs/virtio-9p.c +7
-0+ vs->v9fs_errno = errno; +} +static void v9fs_stat (V9fsState *s,V9fsPDU *pdu) {int32_t fid;@@ -1487,6 +1496,10 @@ static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) vs =qemu_malloc (sizeof (*vs)); vs->pdu = pdu; vs->offset =7 ; + vs->s = s; + vs->request.func = v9fs_stat_do_lstat; + vs->request.post_op.func = v9fs_stat_post_lstat; + vs->request.post_op.arg = vs;memset (&vs->v9stat,0 ,sizeof (vs->v9stat));hw/9pfs/virtio-9p.c static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) · line 1517
Quoted 7 lines
hw/9pfs/virtio-9p.c +2
-0@@ -1498,8 +1511,11 @@ static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) goto out; } +/* err = v9fs_do_lstat(s, &vs->fidp->fsmap.path, &vs->stbuf); v9fs_stat_post_lstat(s, vs, err); +*/ Please remove unused code, it quickly becomes out-of-date and confuses readers.
hw/9pfs/virtio-9p.c static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) · line 1518
Quoted 1 line
hw/9pfs/virtio-9p.c +1
-0+v9fs_qemu_submit_request (&vs->request);What happens when another PDU is handled next that uses the same fid? The worst case is if the client sends TCLUNK and fid is freed while the worker thread and later the post op still access the memory. There needs to be some kind of guard (like a reference count) to prevent this.
Quoted 8 lines
Quoted 4 lines
As per the protocol this should not happen. Client is the controls the fid, and the fid is created or destroyed per the directive of the client. It should not send clunk until the response is received on that fid based operation(if there is any).
Unfortunately it is still possible for a guest to do it. The model for emulated hardware is that the guest is untrusted and we cannot allow things to crash.
Well, it can happen only if the guest OS is hacked...and the worst thing can happen is guest goes down. I am not sure how it is different from a bare metal system..
Quoted 9 lines
It's really important for everyone to keep this in mind otherwise security vulnerabilities will be introduced for use cases like hosting and cloud where the guest really cannot be trusted.
An easy fix is to mark a fid busy and reject requests that mess with it before the existing request has been processed.
Stefan
[Qemu-devel] Re: [v1 PATCH 3/3]: Convert v9fs_stat to threaded model.
Quoted 116 lines · Venkateswararao Jujjuri (JV)
Quoted 115 lines · Stefan Hajnoczi
Quoted 112 lines · Venkateswararao Jujjuri (JV)
Quoted 61 lines · Stefan Hajnoczi
Quoted 6 lines · Arun R Bharadwaj
hw/9pfs/virtio-9p.c +1
-1-static void v9fs_stat_post_lstat (V9fsState *s,V9fsStatState *vs,int err) +static void v9fs_stat_post_lstat (void *opaque){
- if (err == -1) {
- err = -errno;
+ V9fsStatState *vs = (V9fsStatState *)opaque;No need to cast void* in C.
Quoted 2 lines
+ if (
vs->err== -1) {
+ vs->err = -(vs->v9fs_errno);How about the thread worker function puts the -errno into a
vs->retfield:static void
v9fs_stat_do_lstat(V9fsRequest *request)
{
V9fsStatState *vs =container_of(request, V9fsStatState, request);
vs->ret=v9fs_do_lstat(vs->s, &vs->fidp->fsmap.path, &vs->stbuf); if (vs->ret!= 0) {
vs->ret= -errno;
}
}Then
v9fs_stat_post_lstat()can usevs->retdirectly and does not need to juggle around the two fields,vs->errandvs->v9fs_errno.Quoted 6 lines
goto out;
}- err =
stat_to_v9stat(s, &vs->fidp->fsmap.path, &vs->stbuf, &vs->v9stat);
- if (err) {
+ vs->err =stat_to_v9stat(vs->s, &vs->fidp->fsmap.path, &vs->stbuf, &vs->v9stat);This function can block in
v9fs_do_readlink(). Needs to be done asynchronously to avoid blocking QEMU.Quoted 14 lines
+ if (
vs->err) {
goto out;
}
vs->offset+=pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
- err =vs->offset;
+ vs->err =vs->offset;out:
- complete_pdu(s,vs->pdu, err);
+ complete_pdu(vs->s,vs->pdu,vs->err);
v9fs_stat_free(&vs->v9stat);
qemu_free(vs);
}hw/9pfs/virtio-9p.c out: · line 1484
Quoted 3 lines
hw/9pfs/virtio-9p.c +3
-0+static void v9fs_stat_do_lstat (V9fsRequest *request) +{ + V9fsStatState *vs = container_of(request, V9fsStatState, request);Nice. Could
container_of()be used forv9fs_post_lstat()too? I'm suggesting making post op functions take the V9fsRequest* instead of a void* opaque pointer.Quoted 6 lines
Quoted 2 lines
+
+ vs->err =v9fs_do_lstat(vs->s, &vs->fidp->fsmap.path, &vs->stbuf);This is not threadsafe since rpath still uses a static buffer in qemu.git. Please ensure that
rpath()is thread-safe before pushing this patch.There is another patch on the internal list to make rpath thread safe.
Quoted 29 lines
Quoted 19 lines
+ vs->v9fs_errno = errno;
hw/9pfs/virtio-9p.c +2
-0+} +static void
v9fs_stat(V9fsState *s, V9fsPDU *pdu){
int32_tfid;hw/9pfs/virtio-9p.c +4
-0@@ -1487,6 +1496,10 @@ static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) vs = qemu_malloc(sizeof(*vs)); vs->pdu = pdu; vs->offset = 7; + vs->s = s; + vs->request.func = v9fs_stat_do_lstat; + vs->request.post_op.func = v9fs_stat_post_lstat; + vs->request.post_op.arg = vs; memset(&vs->v9stat, 0, sizeof(vs->v9stat));hw/9pfs/virtio-9p.c static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) · line 1517
Quoted 7 lines
hw/9pfs/virtio-9p.c +2
-0@@ -1498,8 +1511,11 @@ static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) goto out; } + /*err = v9fs_do_lstat(s, &vs->fidp->fsmap.path, &vs->stbuf); v9fs_stat_post_lstat(s, vs, err); +*/ Please remove unused code, it quickly becomes out-of-date and confuses readers.
Quoted 7 lines
hw/9pfs/virtio-9p.c static void v9fs_stat(V9fsState *s, V9fsPDU *pdu) · line 1518
Quoted 1 line
hw/9pfs/virtio-9p.c +1
-0+ v9fs_qemu_submit_request(&vs->request);What happens when another PDU is handled next that uses the same fid? The worst case is if the client sends TCLUNK and fid is freed while the worker thread and later the post op still access the memory. There needs to be some kind of guard (like a reference count) to prevent this.
As per the protocol this should not happen. Client is the controls the fid, and the fid is created or destroyed per the directive of the client. It should not send clunk until the response is received on that fid based operation(if there is any).
Quoted 7 lines
Quoted 3 lines
Unfortunately it is still possible for a guest to do it. The model for emulated hardware is that the guest is untrusted and we cannot allow things to crash.
Well, it can happen only if the guest OS is hacked...and the worst thing can happen is guest goes down. I am not sure how it is different from a bare metal system..
No, use after free can lead to arbitrary code execution or other effects more severe than the guest going down:
http://en.wikipedia.org/wiki/Malloc#Use_after_free
For example if the same memory is handed out by malloc and used to store a function pointer, then the function pointer can be corrupted and cause a jump to an arbitrary place in memory.
Hardware emulation is like implementing system calls in an operating system. You cannot crash in the kernel and you cannot allow undefined things to happen. Every state needs to be handled, whether a reasonable process would do it or not.
Also, allowing hardware emulation to take down the guest is not an option going forward. People have been working on nested virtualization. In that scenario a virtio-9p-pci device can be passed through to a nested guest. If that guest is able to take down QEMU then it can kill its sibling nested guests and its parent guest, which it should not be able to do.
Stefan