blob: 1136ee99d4bafb1b1da7e21a6b8750c1543cc3df [file] [log] [blame]
Miklos Szeredifff56ab2001-11-16 10:12:59 +00001/*
2 FUSE: Filesystem in Userspace
Miklos Szeredi149f6072005-01-10 12:29:28 +00003 Copyright (C) 2001-2005 Miklos Szeredi <miklos@szeredi.hu>
Miklos Szeredifff56ab2001-11-16 10:12:59 +00004
Miklos Szeredi8b39a9f2002-10-25 12:41:16 +00005 This program can be distributed under the terms of the GNU LGPL.
6 See the file COPYING.LIB.
Miklos Szeredifff56ab2001-11-16 10:12:59 +00007*/
8
Miklos Szeredi178451d2005-08-15 13:19:07 +00009#include "fuse_i.h"
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000010#include "fuse_lowlevel.h"
Miklos Szeredifff56ab2001-11-16 10:12:59 +000011
12#include <stdio.h>
13#include <stdlib.h>
14#include <string.h>
Miklos Szeredie2aa2e22005-07-15 13:31:36 +000015#include <pthread.h>
Miklos Szeredia1482422005-08-14 23:00:27 +000016#include <assert.h>
Miklos Szeredifff56ab2001-11-16 10:12:59 +000017
Miklos Szeredid169f312004-09-22 08:48:26 +000018static pthread_key_t context_key;
19static pthread_mutex_t context_lock = PTHREAD_MUTEX_INITIALIZER;
20static int context_ref;
21
Miklos Szeredid169f312004-09-22 08:48:26 +000022static struct fuse_context *mt_getcontext(void)
Miklos Szeredife25def2001-12-20 15:38:05 +000023{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000024 struct fuse_context *ctx;
Miklos Szeredi9b813af2005-07-21 07:59:37 +000025
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000026 ctx = (struct fuse_context *) pthread_getspecific(context_key);
27 if (ctx == NULL) {
28 ctx = (struct fuse_context *) malloc(sizeof(struct fuse_context));
29 if (ctx == NULL) {
30 fprintf(stderr, "fuse: failed to allocate thread specific data\n");
31 return NULL;
32 }
33 pthread_setspecific(context_key, ctx);
34 }
Miklos Szeredid169f312004-09-22 08:48:26 +000035 return ctx;
Miklos Szeredife25def2001-12-20 15:38:05 +000036}
37
38static void mt_freecontext(void *data)
39{
40 free(data);
41}
42
Miklos Szeredif6e0ec62005-08-03 09:11:06 +000043static int mt_create_context_key(void)
Miklos Szeredid169f312004-09-22 08:48:26 +000044{
45 int err = 0;
46 pthread_mutex_lock(&context_lock);
47 if (!context_ref) {
48 err = pthread_key_create(&context_key, mt_freecontext);
49 if (err)
50 fprintf(stderr, "fuse: failed to create thread specific key: %s\n",
51 strerror(err));
Miklos Szeredie5183742005-02-02 11:14:04 +000052 else
Miklos Szeredif458b8c2004-12-07 16:46:42 +000053 fuse_set_getcontext_func(mt_getcontext);
Miklos Szeredid169f312004-09-22 08:48:26 +000054 }
55 if (!err)
56 context_ref ++;
57 pthread_mutex_unlock(&context_lock);
58 return err;
59}
60
Miklos Szeredif6e0ec62005-08-03 09:11:06 +000061static void mt_delete_context_key(void)
Miklos Szeredid169f312004-09-22 08:48:26 +000062{
63 pthread_mutex_lock(&context_lock);
64 context_ref--;
65 if (!context_ref) {
Miklos Szeredif458b8c2004-12-07 16:46:42 +000066 fuse_set_getcontext_func(NULL);
Miklos Szeredid169f312004-09-22 08:48:26 +000067 pthread_key_delete(context_key);
68 }
69 pthread_mutex_unlock(&context_lock);
70}
71
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000072struct procdata {
73 struct fuse *f;
Miklos Szeredi178451d2005-08-15 13:19:07 +000074 struct fuse_chan *prevch;
75 struct fuse_session *prevse;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000076 fuse_processor_t proc;
77 void *data;
78};
79
Miklos Szeredia1482422005-08-14 23:00:27 +000080static void mt_session_proc(void *data, const char *buf, size_t len,
81 struct fuse_chan *ch)
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000082{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000083 struct procdata *pd = (struct procdata *) data;
Miklos Szeredia1482422005-08-14 23:00:27 +000084 struct fuse_cmd *cmd = *(struct fuse_cmd **) buf;
85
86 (void) len;
Miklos Szeredi178451d2005-08-15 13:19:07 +000087 cmd->ch = ch;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +000088 pd->proc(pd->f, cmd, pd->data);
89}
90
Miklos Szeredi178451d2005-08-15 13:19:07 +000091static void mt_session_exit(void *data, int val)
92{
93 struct procdata *pd = (struct procdata *) data;
94 if (val)
95 fuse_session_exit(pd->prevse);
96 else
97 fuse_session_reset(pd->prevse);
98}
99
100static int mt_session_exited(void *data)
101{
102 struct procdata *pd = (struct procdata *) data;
103 return fuse_session_exited(pd->prevse);
104}
105
Miklos Szeredia1482422005-08-14 23:00:27 +0000106static int mt_chan_receive(struct fuse_chan *ch, char *buf, size_t size)
107{
108 struct fuse_cmd *cmd;
109 struct procdata *pd = (struct procdata *) fuse_chan_data(ch);
110
111 assert(size >= sizeof(cmd));
Miklos Szeredi2bb750e2005-10-03 14:54:24 +0000112
Miklos Szeredia1482422005-08-14 23:00:27 +0000113 cmd = fuse_read_cmd(pd->f);
114 if (cmd == NULL)
Miklos Szeredi178451d2005-08-15 13:19:07 +0000115 return 0;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +0000116
Miklos Szeredia1482422005-08-14 23:00:27 +0000117 *(struct fuse_cmd **) buf = cmd;
Miklos Szeredi2bb750e2005-10-03 14:54:24 +0000118
Miklos Szeredi178451d2005-08-15 13:19:07 +0000119 return sizeof(cmd);
120}
121
122static int mt_chan_send(struct fuse_chan *ch, const struct iovec iov[],
123 size_t count)
124{
125 struct procdata *pd = (struct procdata *) fuse_chan_data(ch);
126 return fuse_chan_send(pd->prevch, iov, count);
Miklos Szeredia1482422005-08-14 23:00:27 +0000127}
128
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000129int fuse_loop_mt_proc(struct fuse *f, fuse_processor_t proc, void *data)
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000130{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000131 int res;
132 struct procdata pd;
Miklos Szeredia1482422005-08-14 23:00:27 +0000133 struct fuse_session *prevse = fuse_get_session(f);
134 struct fuse_session *se;
135 struct fuse_chan *prevch = fuse_session_next_chan(prevse, NULL);
136 struct fuse_chan *ch;
137 struct fuse_session_ops sop = {
Miklos Szeredi178451d2005-08-15 13:19:07 +0000138 .exit = mt_session_exit,
139 .exited = mt_session_exited,
Miklos Szeredia1482422005-08-14 23:00:27 +0000140 .process = mt_session_proc,
141 };
142 struct fuse_chan_ops cop = {
143 .receive = mt_chan_receive,
Miklos Szeredi178451d2005-08-15 13:19:07 +0000144 .send = mt_chan_send,
Miklos Szeredia1482422005-08-14 23:00:27 +0000145 };
Miklos Szeredi43696432001-11-18 19:15:05 +0000146
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000147 pd.f = f;
Miklos Szeredi178451d2005-08-15 13:19:07 +0000148 pd.prevch = prevch;
149 pd.prevse = prevse;
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000150 pd.proc = proc;
151 pd.data = data;
152
Miklos Szeredia1482422005-08-14 23:00:27 +0000153 se = fuse_session_new(&sop, &pd);
154 if (se == NULL)
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000155 return -1;
Miklos Szeredi43696432001-11-18 19:15:05 +0000156
Miklos Szeredia1482422005-08-14 23:00:27 +0000157 ch = fuse_chan_new(&cop, fuse_chan_fd(prevch), sizeof(struct fuse_cmd *),
158 &pd);
159 if (ch == NULL) {
160 fuse_session_destroy(se);
161 return -1;
162 }
163 fuse_session_add_chan(se, ch);
164
165 if (mt_create_context_key() != 0) {
166 fuse_session_destroy(se);
167 return -1;
168 }
169
170 res = fuse_session_loop_mt(se);
Miklos Szeredi1ea9c962004-06-24 21:00:00 +0000171
Miklos Szeredid169f312004-09-22 08:48:26 +0000172 mt_delete_context_key();
Miklos Szeredia1482422005-08-14 23:00:27 +0000173 fuse_session_destroy(se);
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000174 return res;
Miklos Szeredifff56ab2001-11-16 10:12:59 +0000175}
Miklos Szeredif830a7f2001-11-16 17:46:45 +0000176
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000177int fuse_loop_mt(struct fuse *f)
Miklos Szeredif830a7f2001-11-16 17:46:45 +0000178{
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000179 int res;
180
Miklos Szeredi178451d2005-08-15 13:19:07 +0000181 if (f == NULL)
182 return -1;
183
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000184 if (mt_create_context_key() != 0)
Miklos Szeredib2cf9562004-09-16 08:42:40 +0000185 return -1;
Miklos Szeredic40748a2004-02-20 16:38:45 +0000186
Miklos Szeredia1482422005-08-14 23:00:27 +0000187 res = fuse_session_loop_mt(fuse_get_session(f));
Miklos Szeredibd10a7b2005-07-15 09:59:59 +0000188
189 mt_delete_context_key();
190 return res;
Miklos Szeredif830a7f2001-11-16 17:46:45 +0000191}
Miklos Szeredif458b8c2004-12-07 16:46:42 +0000192
193__asm__(".symver fuse_loop_mt_proc,__fuse_loop_mt@");