Commit 41e5a6ac80c600e1f8bda0a4871f0b797e097d78
Committed by
Linus Torvalds
1 parent
343f1fe6f2
Exists in
master
and in
7 other branches
[PATCH] v9fs: signal handling fixes
Multiple races can happen when v9fs is interrupted by a signal and Tflush message is sent to the server. After v9fs sends Tflush it doesn't wait until it receives Rflush, and possibly the response of the original message. This behavior may confuse v9fs what fids are allocated by the file server. This patch fixes the races and the fid allocation. Signed-off-by: Latchesar Ionkov <lucho@ionkov.net> Cc: Eric Van Hensbergen <ericvh@hera.kernel.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 4 changed files with 158 additions and 100 deletions Inline Diff
fs/9p/mux.c
1 | /* | 1 | /* |
2 | * linux/fs/9p/mux.c | 2 | * linux/fs/9p/mux.c |
3 | * | 3 | * |
4 | * Protocol Multiplexer | 4 | * Protocol Multiplexer |
5 | * | 5 | * |
6 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | 6 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> |
7 | * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> | 7 | * Copyright (C) 2004-2005 by Latchesar Ionkov <lucho@ionkov.net> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 | 10 | * it under the terms of the GNU General Public License version 2 |
11 | * as published by the Free Software Foundation. | 11 | * as published by the Free Software Foundation. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to: | 19 | * along with this program; if not, write to: |
20 | * Free Software Foundation | 20 | * Free Software Foundation |
21 | * 51 Franklin Street, Fifth Floor | 21 | * 51 Franklin Street, Fifth Floor |
22 | * Boston, MA 02111-1301 USA | 22 | * Boston, MA 02111-1301 USA |
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/config.h> | 26 | #include <linux/config.h> |
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/errno.h> | 28 | #include <linux/errno.h> |
29 | #include <linux/fs.h> | 29 | #include <linux/fs.h> |
30 | #include <linux/poll.h> | 30 | #include <linux/poll.h> |
31 | #include <linux/kthread.h> | 31 | #include <linux/kthread.h> |
32 | #include <linux/idr.h> | 32 | #include <linux/idr.h> |
33 | #include <linux/mutex.h> | 33 | #include <linux/mutex.h> |
34 | 34 | ||
35 | #include "debug.h" | 35 | #include "debug.h" |
36 | #include "v9fs.h" | 36 | #include "v9fs.h" |
37 | #include "9p.h" | 37 | #include "9p.h" |
38 | #include "conv.h" | 38 | #include "conv.h" |
39 | #include "transport.h" | 39 | #include "transport.h" |
40 | #include "mux.h" | 40 | #include "mux.h" |
41 | 41 | ||
42 | #define ERREQFLUSH 1 | 42 | #define ERREQFLUSH 1 |
43 | #define SCHED_TIMEOUT 10 | 43 | #define SCHED_TIMEOUT 10 |
44 | #define MAXPOLLWADDR 2 | 44 | #define MAXPOLLWADDR 2 |
45 | 45 | ||
46 | enum { | 46 | enum { |
47 | Rworksched = 1, /* read work scheduled or running */ | 47 | Rworksched = 1, /* read work scheduled or running */ |
48 | Rpending = 2, /* can read */ | 48 | Rpending = 2, /* can read */ |
49 | Wworksched = 4, /* write work scheduled or running */ | 49 | Wworksched = 4, /* write work scheduled or running */ |
50 | Wpending = 8, /* can write */ | 50 | Wpending = 8, /* can write */ |
51 | }; | 51 | }; |
52 | 52 | ||
53 | enum { | ||
54 | None, | ||
55 | Flushing, | ||
56 | Flushed, | ||
57 | }; | ||
58 | |||
53 | struct v9fs_mux_poll_task; | 59 | struct v9fs_mux_poll_task; |
54 | 60 | ||
55 | struct v9fs_req { | 61 | struct v9fs_req { |
62 | spinlock_t lock; | ||
56 | int tag; | 63 | int tag; |
57 | struct v9fs_fcall *tcall; | 64 | struct v9fs_fcall *tcall; |
58 | struct v9fs_fcall *rcall; | 65 | struct v9fs_fcall *rcall; |
59 | int err; | 66 | int err; |
60 | v9fs_mux_req_callback cb; | 67 | v9fs_mux_req_callback cb; |
61 | void *cba; | 68 | void *cba; |
69 | int flush; | ||
62 | struct list_head req_list; | 70 | struct list_head req_list; |
63 | }; | 71 | }; |
64 | 72 | ||
65 | struct v9fs_mux_data { | 73 | struct v9fs_mux_data { |
66 | spinlock_t lock; | 74 | spinlock_t lock; |
67 | struct list_head mux_list; | 75 | struct list_head mux_list; |
68 | struct v9fs_mux_poll_task *poll_task; | 76 | struct v9fs_mux_poll_task *poll_task; |
69 | int msize; | 77 | int msize; |
70 | unsigned char *extended; | 78 | unsigned char *extended; |
71 | struct v9fs_transport *trans; | 79 | struct v9fs_transport *trans; |
72 | struct v9fs_idpool tagpool; | 80 | struct v9fs_idpool tagpool; |
73 | int err; | 81 | int err; |
74 | wait_queue_head_t equeue; | 82 | wait_queue_head_t equeue; |
75 | struct list_head req_list; | 83 | struct list_head req_list; |
76 | struct list_head unsent_req_list; | 84 | struct list_head unsent_req_list; |
77 | struct v9fs_fcall *rcall; | 85 | struct v9fs_fcall *rcall; |
78 | int rpos; | 86 | int rpos; |
79 | char *rbuf; | 87 | char *rbuf; |
80 | int wpos; | 88 | int wpos; |
81 | int wsize; | 89 | int wsize; |
82 | char *wbuf; | 90 | char *wbuf; |
83 | wait_queue_t poll_wait[MAXPOLLWADDR]; | 91 | wait_queue_t poll_wait[MAXPOLLWADDR]; |
84 | wait_queue_head_t *poll_waddr[MAXPOLLWADDR]; | 92 | wait_queue_head_t *poll_waddr[MAXPOLLWADDR]; |
85 | poll_table pt; | 93 | poll_table pt; |
86 | struct work_struct rq; | 94 | struct work_struct rq; |
87 | struct work_struct wq; | 95 | struct work_struct wq; |
88 | unsigned long wsched; | 96 | unsigned long wsched; |
89 | }; | 97 | }; |
90 | 98 | ||
91 | struct v9fs_mux_poll_task { | 99 | struct v9fs_mux_poll_task { |
92 | struct task_struct *task; | 100 | struct task_struct *task; |
93 | struct list_head mux_list; | 101 | struct list_head mux_list; |
94 | int muxnum; | 102 | int muxnum; |
95 | }; | 103 | }; |
96 | 104 | ||
97 | struct v9fs_mux_rpc { | 105 | struct v9fs_mux_rpc { |
98 | struct v9fs_mux_data *m; | 106 | struct v9fs_mux_data *m; |
99 | struct v9fs_req *req; | ||
100 | int err; | 107 | int err; |
108 | struct v9fs_fcall *tcall; | ||
101 | struct v9fs_fcall *rcall; | 109 | struct v9fs_fcall *rcall; |
102 | wait_queue_head_t wqueue; | 110 | wait_queue_head_t wqueue; |
103 | }; | 111 | }; |
104 | 112 | ||
105 | static int v9fs_poll_proc(void *); | 113 | static int v9fs_poll_proc(void *); |
106 | static void v9fs_read_work(void *); | 114 | static void v9fs_read_work(void *); |
107 | static void v9fs_write_work(void *); | 115 | static void v9fs_write_work(void *); |
108 | static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address, | 116 | static void v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address, |
109 | poll_table * p); | 117 | poll_table * p); |
110 | static u16 v9fs_mux_get_tag(struct v9fs_mux_data *); | 118 | static u16 v9fs_mux_get_tag(struct v9fs_mux_data *); |
111 | static void v9fs_mux_put_tag(struct v9fs_mux_data *, u16); | 119 | static void v9fs_mux_put_tag(struct v9fs_mux_data *, u16); |
112 | 120 | ||
113 | static DEFINE_MUTEX(v9fs_mux_task_lock); | 121 | static DEFINE_MUTEX(v9fs_mux_task_lock); |
114 | static struct workqueue_struct *v9fs_mux_wq; | 122 | static struct workqueue_struct *v9fs_mux_wq; |
115 | 123 | ||
116 | static int v9fs_mux_num; | 124 | static int v9fs_mux_num; |
117 | static int v9fs_mux_poll_task_num; | 125 | static int v9fs_mux_poll_task_num; |
118 | static struct v9fs_mux_poll_task v9fs_mux_poll_tasks[100]; | 126 | static struct v9fs_mux_poll_task v9fs_mux_poll_tasks[100]; |
119 | 127 | ||
120 | int v9fs_mux_global_init(void) | 128 | int v9fs_mux_global_init(void) |
121 | { | 129 | { |
122 | int i; | 130 | int i; |
123 | 131 | ||
124 | for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) | 132 | for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) |
125 | v9fs_mux_poll_tasks[i].task = NULL; | 133 | v9fs_mux_poll_tasks[i].task = NULL; |
126 | 134 | ||
127 | v9fs_mux_wq = create_workqueue("v9fs"); | 135 | v9fs_mux_wq = create_workqueue("v9fs"); |
128 | if (!v9fs_mux_wq) | 136 | if (!v9fs_mux_wq) |
129 | return -ENOMEM; | 137 | return -ENOMEM; |
130 | 138 | ||
131 | return 0; | 139 | return 0; |
132 | } | 140 | } |
133 | 141 | ||
134 | void v9fs_mux_global_exit(void) | 142 | void v9fs_mux_global_exit(void) |
135 | { | 143 | { |
136 | destroy_workqueue(v9fs_mux_wq); | 144 | destroy_workqueue(v9fs_mux_wq); |
137 | } | 145 | } |
138 | 146 | ||
139 | /** | 147 | /** |
140 | * v9fs_mux_calc_poll_procs - calculates the number of polling procs | 148 | * v9fs_mux_calc_poll_procs - calculates the number of polling procs |
141 | * based on the number of mounted v9fs filesystems. | 149 | * based on the number of mounted v9fs filesystems. |
142 | * | 150 | * |
143 | * The current implementation returns sqrt of the number of mounts. | 151 | * The current implementation returns sqrt of the number of mounts. |
144 | */ | 152 | */ |
145 | static int v9fs_mux_calc_poll_procs(int muxnum) | 153 | static int v9fs_mux_calc_poll_procs(int muxnum) |
146 | { | 154 | { |
147 | int n; | 155 | int n; |
148 | 156 | ||
149 | if (v9fs_mux_poll_task_num) | 157 | if (v9fs_mux_poll_task_num) |
150 | n = muxnum / v9fs_mux_poll_task_num + | 158 | n = muxnum / v9fs_mux_poll_task_num + |
151 | (muxnum % v9fs_mux_poll_task_num ? 1 : 0); | 159 | (muxnum % v9fs_mux_poll_task_num ? 1 : 0); |
152 | else | 160 | else |
153 | n = 1; | 161 | n = 1; |
154 | 162 | ||
155 | if (n > ARRAY_SIZE(v9fs_mux_poll_tasks)) | 163 | if (n > ARRAY_SIZE(v9fs_mux_poll_tasks)) |
156 | n = ARRAY_SIZE(v9fs_mux_poll_tasks); | 164 | n = ARRAY_SIZE(v9fs_mux_poll_tasks); |
157 | 165 | ||
158 | return n; | 166 | return n; |
159 | } | 167 | } |
160 | 168 | ||
161 | static int v9fs_mux_poll_start(struct v9fs_mux_data *m) | 169 | static int v9fs_mux_poll_start(struct v9fs_mux_data *m) |
162 | { | 170 | { |
163 | int i, n; | 171 | int i, n; |
164 | struct v9fs_mux_poll_task *vpt, *vptlast; | 172 | struct v9fs_mux_poll_task *vpt, *vptlast; |
165 | struct task_struct *pproc; | 173 | struct task_struct *pproc; |
166 | 174 | ||
167 | dprintk(DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, v9fs_mux_num, | 175 | dprintk(DEBUG_MUX, "mux %p muxnum %d procnum %d\n", m, v9fs_mux_num, |
168 | v9fs_mux_poll_task_num); | 176 | v9fs_mux_poll_task_num); |
169 | mutex_lock(&v9fs_mux_task_lock); | 177 | mutex_lock(&v9fs_mux_task_lock); |
170 | 178 | ||
171 | n = v9fs_mux_calc_poll_procs(v9fs_mux_num + 1); | 179 | n = v9fs_mux_calc_poll_procs(v9fs_mux_num + 1); |
172 | if (n > v9fs_mux_poll_task_num) { | 180 | if (n > v9fs_mux_poll_task_num) { |
173 | for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) { | 181 | for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) { |
174 | if (v9fs_mux_poll_tasks[i].task == NULL) { | 182 | if (v9fs_mux_poll_tasks[i].task == NULL) { |
175 | vpt = &v9fs_mux_poll_tasks[i]; | 183 | vpt = &v9fs_mux_poll_tasks[i]; |
176 | dprintk(DEBUG_MUX, "create proc %p\n", vpt); | 184 | dprintk(DEBUG_MUX, "create proc %p\n", vpt); |
177 | pproc = kthread_create(v9fs_poll_proc, vpt, | 185 | pproc = kthread_create(v9fs_poll_proc, vpt, |
178 | "v9fs-poll"); | 186 | "v9fs-poll"); |
179 | 187 | ||
180 | if (!IS_ERR(pproc)) { | 188 | if (!IS_ERR(pproc)) { |
181 | vpt->task = pproc; | 189 | vpt->task = pproc; |
182 | INIT_LIST_HEAD(&vpt->mux_list); | 190 | INIT_LIST_HEAD(&vpt->mux_list); |
183 | vpt->muxnum = 0; | 191 | vpt->muxnum = 0; |
184 | v9fs_mux_poll_task_num++; | 192 | v9fs_mux_poll_task_num++; |
185 | wake_up_process(vpt->task); | 193 | wake_up_process(vpt->task); |
186 | } | 194 | } |
187 | break; | 195 | break; |
188 | } | 196 | } |
189 | } | 197 | } |
190 | 198 | ||
191 | if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks)) | 199 | if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks)) |
192 | dprintk(DEBUG_ERROR, "warning: no free poll slots\n"); | 200 | dprintk(DEBUG_ERROR, "warning: no free poll slots\n"); |
193 | } | 201 | } |
194 | 202 | ||
195 | n = (v9fs_mux_num + 1) / v9fs_mux_poll_task_num + | 203 | n = (v9fs_mux_num + 1) / v9fs_mux_poll_task_num + |
196 | ((v9fs_mux_num + 1) % v9fs_mux_poll_task_num ? 1 : 0); | 204 | ((v9fs_mux_num + 1) % v9fs_mux_poll_task_num ? 1 : 0); |
197 | 205 | ||
198 | vptlast = NULL; | 206 | vptlast = NULL; |
199 | for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) { | 207 | for (i = 0; i < ARRAY_SIZE(v9fs_mux_poll_tasks); i++) { |
200 | vpt = &v9fs_mux_poll_tasks[i]; | 208 | vpt = &v9fs_mux_poll_tasks[i]; |
201 | if (vpt->task != NULL) { | 209 | if (vpt->task != NULL) { |
202 | vptlast = vpt; | 210 | vptlast = vpt; |
203 | if (vpt->muxnum < n) { | 211 | if (vpt->muxnum < n) { |
204 | dprintk(DEBUG_MUX, "put in proc %d\n", i); | 212 | dprintk(DEBUG_MUX, "put in proc %d\n", i); |
205 | list_add(&m->mux_list, &vpt->mux_list); | 213 | list_add(&m->mux_list, &vpt->mux_list); |
206 | vpt->muxnum++; | 214 | vpt->muxnum++; |
207 | m->poll_task = vpt; | 215 | m->poll_task = vpt; |
208 | memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); | 216 | memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); |
209 | init_poll_funcptr(&m->pt, v9fs_pollwait); | 217 | init_poll_funcptr(&m->pt, v9fs_pollwait); |
210 | break; | 218 | break; |
211 | } | 219 | } |
212 | } | 220 | } |
213 | } | 221 | } |
214 | 222 | ||
215 | if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks)) { | 223 | if (i >= ARRAY_SIZE(v9fs_mux_poll_tasks)) { |
216 | if (vptlast == NULL) | 224 | if (vptlast == NULL) |
217 | return -ENOMEM; | 225 | return -ENOMEM; |
218 | 226 | ||
219 | dprintk(DEBUG_MUX, "put in proc %d\n", i); | 227 | dprintk(DEBUG_MUX, "put in proc %d\n", i); |
220 | list_add(&m->mux_list, &vptlast->mux_list); | 228 | list_add(&m->mux_list, &vptlast->mux_list); |
221 | vptlast->muxnum++; | 229 | vptlast->muxnum++; |
222 | m->poll_task = vptlast; | 230 | m->poll_task = vptlast; |
223 | memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); | 231 | memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); |
224 | init_poll_funcptr(&m->pt, v9fs_pollwait); | 232 | init_poll_funcptr(&m->pt, v9fs_pollwait); |
225 | } | 233 | } |
226 | 234 | ||
227 | v9fs_mux_num++; | 235 | v9fs_mux_num++; |
228 | mutex_unlock(&v9fs_mux_task_lock); | 236 | mutex_unlock(&v9fs_mux_task_lock); |
229 | 237 | ||
230 | return 0; | 238 | return 0; |
231 | } | 239 | } |
232 | 240 | ||
233 | static void v9fs_mux_poll_stop(struct v9fs_mux_data *m) | 241 | static void v9fs_mux_poll_stop(struct v9fs_mux_data *m) |
234 | { | 242 | { |
235 | int i; | 243 | int i; |
236 | struct v9fs_mux_poll_task *vpt; | 244 | struct v9fs_mux_poll_task *vpt; |
237 | 245 | ||
238 | mutex_lock(&v9fs_mux_task_lock); | 246 | mutex_lock(&v9fs_mux_task_lock); |
239 | vpt = m->poll_task; | 247 | vpt = m->poll_task; |
240 | list_del(&m->mux_list); | 248 | list_del(&m->mux_list); |
241 | for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { | 249 | for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { |
242 | if (m->poll_waddr[i] != NULL) { | 250 | if (m->poll_waddr[i] != NULL) { |
243 | remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]); | 251 | remove_wait_queue(m->poll_waddr[i], &m->poll_wait[i]); |
244 | m->poll_waddr[i] = NULL; | 252 | m->poll_waddr[i] = NULL; |
245 | } | 253 | } |
246 | } | 254 | } |
247 | vpt->muxnum--; | 255 | vpt->muxnum--; |
248 | if (!vpt->muxnum) { | 256 | if (!vpt->muxnum) { |
249 | dprintk(DEBUG_MUX, "destroy proc %p\n", vpt); | 257 | dprintk(DEBUG_MUX, "destroy proc %p\n", vpt); |
250 | send_sig(SIGKILL, vpt->task, 1); | 258 | send_sig(SIGKILL, vpt->task, 1); |
251 | vpt->task = NULL; | 259 | vpt->task = NULL; |
252 | v9fs_mux_poll_task_num--; | 260 | v9fs_mux_poll_task_num--; |
253 | } | 261 | } |
254 | v9fs_mux_num--; | 262 | v9fs_mux_num--; |
255 | mutex_unlock(&v9fs_mux_task_lock); | 263 | mutex_unlock(&v9fs_mux_task_lock); |
256 | } | 264 | } |
257 | 265 | ||
258 | /** | 266 | /** |
259 | * v9fs_mux_init - allocate and initialize the per-session mux data | 267 | * v9fs_mux_init - allocate and initialize the per-session mux data |
260 | * Creates the polling task if this is the first session. | 268 | * Creates the polling task if this is the first session. |
261 | * | 269 | * |
262 | * @trans - transport structure | 270 | * @trans - transport structure |
263 | * @msize - maximum message size | 271 | * @msize - maximum message size |
264 | * @extended - pointer to the extended flag | 272 | * @extended - pointer to the extended flag |
265 | */ | 273 | */ |
266 | struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, | 274 | struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, |
267 | unsigned char *extended) | 275 | unsigned char *extended) |
268 | { | 276 | { |
269 | int i, n; | 277 | int i, n; |
270 | struct v9fs_mux_data *m, *mtmp; | 278 | struct v9fs_mux_data *m, *mtmp; |
271 | 279 | ||
272 | dprintk(DEBUG_MUX, "transport %p msize %d\n", trans, msize); | 280 | dprintk(DEBUG_MUX, "transport %p msize %d\n", trans, msize); |
273 | m = kmalloc(sizeof(struct v9fs_mux_data), GFP_KERNEL); | 281 | m = kmalloc(sizeof(struct v9fs_mux_data), GFP_KERNEL); |
274 | if (!m) | 282 | if (!m) |
275 | return ERR_PTR(-ENOMEM); | 283 | return ERR_PTR(-ENOMEM); |
276 | 284 | ||
277 | spin_lock_init(&m->lock); | 285 | spin_lock_init(&m->lock); |
278 | INIT_LIST_HEAD(&m->mux_list); | 286 | INIT_LIST_HEAD(&m->mux_list); |
279 | m->msize = msize; | 287 | m->msize = msize; |
280 | m->extended = extended; | 288 | m->extended = extended; |
281 | m->trans = trans; | 289 | m->trans = trans; |
282 | idr_init(&m->tagpool.pool); | 290 | idr_init(&m->tagpool.pool); |
283 | init_MUTEX(&m->tagpool.lock); | 291 | init_MUTEX(&m->tagpool.lock); |
284 | m->err = 0; | 292 | m->err = 0; |
285 | init_waitqueue_head(&m->equeue); | 293 | init_waitqueue_head(&m->equeue); |
286 | INIT_LIST_HEAD(&m->req_list); | 294 | INIT_LIST_HEAD(&m->req_list); |
287 | INIT_LIST_HEAD(&m->unsent_req_list); | 295 | INIT_LIST_HEAD(&m->unsent_req_list); |
288 | m->rcall = NULL; | 296 | m->rcall = NULL; |
289 | m->rpos = 0; | 297 | m->rpos = 0; |
290 | m->rbuf = NULL; | 298 | m->rbuf = NULL; |
291 | m->wpos = m->wsize = 0; | 299 | m->wpos = m->wsize = 0; |
292 | m->wbuf = NULL; | 300 | m->wbuf = NULL; |
293 | INIT_WORK(&m->rq, v9fs_read_work, m); | 301 | INIT_WORK(&m->rq, v9fs_read_work, m); |
294 | INIT_WORK(&m->wq, v9fs_write_work, m); | 302 | INIT_WORK(&m->wq, v9fs_write_work, m); |
295 | m->wsched = 0; | 303 | m->wsched = 0; |
296 | memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); | 304 | memset(&m->poll_waddr, 0, sizeof(m->poll_waddr)); |
297 | m->poll_task = NULL; | 305 | m->poll_task = NULL; |
298 | n = v9fs_mux_poll_start(m); | 306 | n = v9fs_mux_poll_start(m); |
299 | if (n) | 307 | if (n) |
300 | return ERR_PTR(n); | 308 | return ERR_PTR(n); |
301 | 309 | ||
302 | n = trans->poll(trans, &m->pt); | 310 | n = trans->poll(trans, &m->pt); |
303 | if (n & POLLIN) { | 311 | if (n & POLLIN) { |
304 | dprintk(DEBUG_MUX, "mux %p can read\n", m); | 312 | dprintk(DEBUG_MUX, "mux %p can read\n", m); |
305 | set_bit(Rpending, &m->wsched); | 313 | set_bit(Rpending, &m->wsched); |
306 | } | 314 | } |
307 | 315 | ||
308 | if (n & POLLOUT) { | 316 | if (n & POLLOUT) { |
309 | dprintk(DEBUG_MUX, "mux %p can write\n", m); | 317 | dprintk(DEBUG_MUX, "mux %p can write\n", m); |
310 | set_bit(Wpending, &m->wsched); | 318 | set_bit(Wpending, &m->wsched); |
311 | } | 319 | } |
312 | 320 | ||
313 | for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { | 321 | for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) { |
314 | if (IS_ERR(m->poll_waddr[i])) { | 322 | if (IS_ERR(m->poll_waddr[i])) { |
315 | v9fs_mux_poll_stop(m); | 323 | v9fs_mux_poll_stop(m); |
316 | mtmp = (void *)m->poll_waddr; /* the error code */ | 324 | mtmp = (void *)m->poll_waddr; /* the error code */ |
317 | kfree(m); | 325 | kfree(m); |
318 | m = mtmp; | 326 | m = mtmp; |
319 | break; | 327 | break; |
320 | } | 328 | } |
321 | } | 329 | } |
322 | 330 | ||
323 | return m; | 331 | return m; |
324 | } | 332 | } |
325 | 333 | ||
326 | /** | 334 | /** |
327 | * v9fs_mux_destroy - cancels all pending requests and frees mux resources | 335 | * v9fs_mux_destroy - cancels all pending requests and frees mux resources |
328 | */ | 336 | */ |
329 | void v9fs_mux_destroy(struct v9fs_mux_data *m) | 337 | void v9fs_mux_destroy(struct v9fs_mux_data *m) |
330 | { | 338 | { |
331 | dprintk(DEBUG_MUX, "mux %p prev %p next %p\n", m, | 339 | dprintk(DEBUG_MUX, "mux %p prev %p next %p\n", m, |
332 | m->mux_list.prev, m->mux_list.next); | 340 | m->mux_list.prev, m->mux_list.next); |
333 | v9fs_mux_cancel(m, -ECONNRESET); | 341 | v9fs_mux_cancel(m, -ECONNRESET); |
334 | 342 | ||
335 | if (!list_empty(&m->req_list)) { | 343 | if (!list_empty(&m->req_list)) { |
336 | /* wait until all processes waiting on this session exit */ | 344 | /* wait until all processes waiting on this session exit */ |
337 | dprintk(DEBUG_MUX, "mux %p waiting for empty request queue\n", | 345 | dprintk(DEBUG_MUX, "mux %p waiting for empty request queue\n", |
338 | m); | 346 | m); |
339 | wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000); | 347 | wait_event_timeout(m->equeue, (list_empty(&m->req_list)), 5000); |
340 | dprintk(DEBUG_MUX, "mux %p request queue empty: %d\n", m, | 348 | dprintk(DEBUG_MUX, "mux %p request queue empty: %d\n", m, |
341 | list_empty(&m->req_list)); | 349 | list_empty(&m->req_list)); |
342 | } | 350 | } |
343 | 351 | ||
344 | v9fs_mux_poll_stop(m); | 352 | v9fs_mux_poll_stop(m); |
345 | m->trans = NULL; | 353 | m->trans = NULL; |
346 | 354 | ||
347 | kfree(m); | 355 | kfree(m); |
348 | } | 356 | } |
349 | 357 | ||
350 | /** | 358 | /** |
351 | * v9fs_pollwait - called by files poll operation to add v9fs-poll task | 359 | * v9fs_pollwait - called by files poll operation to add v9fs-poll task |
352 | * to files wait queue | 360 | * to files wait queue |
353 | */ | 361 | */ |
354 | static void | 362 | static void |
355 | v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address, | 363 | v9fs_pollwait(struct file *filp, wait_queue_head_t * wait_address, |
356 | poll_table * p) | 364 | poll_table * p) |
357 | { | 365 | { |
358 | int i; | 366 | int i; |
359 | struct v9fs_mux_data *m; | 367 | struct v9fs_mux_data *m; |
360 | 368 | ||
361 | m = container_of(p, struct v9fs_mux_data, pt); | 369 | m = container_of(p, struct v9fs_mux_data, pt); |
362 | for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) | 370 | for(i = 0; i < ARRAY_SIZE(m->poll_waddr); i++) |
363 | if (m->poll_waddr[i] == NULL) | 371 | if (m->poll_waddr[i] == NULL) |
364 | break; | 372 | break; |
365 | 373 | ||
366 | if (i >= ARRAY_SIZE(m->poll_waddr)) { | 374 | if (i >= ARRAY_SIZE(m->poll_waddr)) { |
367 | dprintk(DEBUG_ERROR, "not enough wait_address slots\n"); | 375 | dprintk(DEBUG_ERROR, "not enough wait_address slots\n"); |
368 | return; | 376 | return; |
369 | } | 377 | } |
370 | 378 | ||
371 | m->poll_waddr[i] = wait_address; | 379 | m->poll_waddr[i] = wait_address; |
372 | 380 | ||
373 | if (!wait_address) { | 381 | if (!wait_address) { |
374 | dprintk(DEBUG_ERROR, "no wait_address\n"); | 382 | dprintk(DEBUG_ERROR, "no wait_address\n"); |
375 | m->poll_waddr[i] = ERR_PTR(-EIO); | 383 | m->poll_waddr[i] = ERR_PTR(-EIO); |
376 | return; | 384 | return; |
377 | } | 385 | } |
378 | 386 | ||
379 | init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task); | 387 | init_waitqueue_entry(&m->poll_wait[i], m->poll_task->task); |
380 | add_wait_queue(wait_address, &m->poll_wait[i]); | 388 | add_wait_queue(wait_address, &m->poll_wait[i]); |
381 | } | 389 | } |
382 | 390 | ||
383 | /** | 391 | /** |
384 | * v9fs_poll_mux - polls a mux and schedules read or write works if necessary | 392 | * v9fs_poll_mux - polls a mux and schedules read or write works if necessary |
385 | */ | 393 | */ |
386 | static void v9fs_poll_mux(struct v9fs_mux_data *m) | 394 | static void v9fs_poll_mux(struct v9fs_mux_data *m) |
387 | { | 395 | { |
388 | int n; | 396 | int n; |
389 | 397 | ||
390 | if (m->err < 0) | 398 | if (m->err < 0) |
391 | return; | 399 | return; |
392 | 400 | ||
393 | n = m->trans->poll(m->trans, NULL); | 401 | n = m->trans->poll(m->trans, NULL); |
394 | if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { | 402 | if (n < 0 || n & (POLLERR | POLLHUP | POLLNVAL)) { |
395 | dprintk(DEBUG_MUX, "error mux %p err %d\n", m, n); | 403 | dprintk(DEBUG_MUX, "error mux %p err %d\n", m, n); |
396 | if (n >= 0) | 404 | if (n >= 0) |
397 | n = -ECONNRESET; | 405 | n = -ECONNRESET; |
398 | v9fs_mux_cancel(m, n); | 406 | v9fs_mux_cancel(m, n); |
399 | } | 407 | } |
400 | 408 | ||
401 | if (n & POLLIN) { | 409 | if (n & POLLIN) { |
402 | set_bit(Rpending, &m->wsched); | 410 | set_bit(Rpending, &m->wsched); |
403 | dprintk(DEBUG_MUX, "mux %p can read\n", m); | 411 | dprintk(DEBUG_MUX, "mux %p can read\n", m); |
404 | if (!test_and_set_bit(Rworksched, &m->wsched)) { | 412 | if (!test_and_set_bit(Rworksched, &m->wsched)) { |
405 | dprintk(DEBUG_MUX, "schedule read work mux %p\n", m); | 413 | dprintk(DEBUG_MUX, "schedule read work mux %p\n", m); |
406 | queue_work(v9fs_mux_wq, &m->rq); | 414 | queue_work(v9fs_mux_wq, &m->rq); |
407 | } | 415 | } |
408 | } | 416 | } |
409 | 417 | ||
410 | if (n & POLLOUT) { | 418 | if (n & POLLOUT) { |
411 | set_bit(Wpending, &m->wsched); | 419 | set_bit(Wpending, &m->wsched); |
412 | dprintk(DEBUG_MUX, "mux %p can write\n", m); | 420 | dprintk(DEBUG_MUX, "mux %p can write\n", m); |
413 | if ((m->wsize || !list_empty(&m->unsent_req_list)) | 421 | if ((m->wsize || !list_empty(&m->unsent_req_list)) |
414 | && !test_and_set_bit(Wworksched, &m->wsched)) { | 422 | && !test_and_set_bit(Wworksched, &m->wsched)) { |
415 | dprintk(DEBUG_MUX, "schedule write work mux %p\n", m); | 423 | dprintk(DEBUG_MUX, "schedule write work mux %p\n", m); |
416 | queue_work(v9fs_mux_wq, &m->wq); | 424 | queue_work(v9fs_mux_wq, &m->wq); |
417 | } | 425 | } |
418 | } | 426 | } |
419 | } | 427 | } |
420 | 428 | ||
421 | /** | 429 | /** |
422 | * v9fs_poll_proc - polls all v9fs transports for new events and queues | 430 | * v9fs_poll_proc - polls all v9fs transports for new events and queues |
423 | * the appropriate work to the work queue | 431 | * the appropriate work to the work queue |
424 | */ | 432 | */ |
425 | static int v9fs_poll_proc(void *a) | 433 | static int v9fs_poll_proc(void *a) |
426 | { | 434 | { |
427 | struct v9fs_mux_data *m, *mtmp; | 435 | struct v9fs_mux_data *m, *mtmp; |
428 | struct v9fs_mux_poll_task *vpt; | 436 | struct v9fs_mux_poll_task *vpt; |
429 | 437 | ||
430 | vpt = a; | 438 | vpt = a; |
431 | dprintk(DEBUG_MUX, "start %p %p\n", current, vpt); | 439 | dprintk(DEBUG_MUX, "start %p %p\n", current, vpt); |
432 | allow_signal(SIGKILL); | 440 | allow_signal(SIGKILL); |
433 | while (!kthread_should_stop()) { | 441 | while (!kthread_should_stop()) { |
434 | set_current_state(TASK_INTERRUPTIBLE); | 442 | set_current_state(TASK_INTERRUPTIBLE); |
435 | if (signal_pending(current)) | 443 | if (signal_pending(current)) |
436 | break; | 444 | break; |
437 | 445 | ||
438 | list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) { | 446 | list_for_each_entry_safe(m, mtmp, &vpt->mux_list, mux_list) { |
439 | v9fs_poll_mux(m); | 447 | v9fs_poll_mux(m); |
440 | } | 448 | } |
441 | 449 | ||
442 | dprintk(DEBUG_MUX, "sleeping...\n"); | 450 | dprintk(DEBUG_MUX, "sleeping...\n"); |
443 | schedule_timeout(SCHED_TIMEOUT * HZ); | 451 | schedule_timeout(SCHED_TIMEOUT * HZ); |
444 | } | 452 | } |
445 | 453 | ||
446 | __set_current_state(TASK_RUNNING); | 454 | __set_current_state(TASK_RUNNING); |
447 | dprintk(DEBUG_MUX, "finish\n"); | 455 | dprintk(DEBUG_MUX, "finish\n"); |
448 | return 0; | 456 | return 0; |
449 | } | 457 | } |
450 | 458 | ||
451 | /** | 459 | /** |
452 | * v9fs_write_work - called when a transport can send some data | 460 | * v9fs_write_work - called when a transport can send some data |
453 | */ | 461 | */ |
454 | static void v9fs_write_work(void *a) | 462 | static void v9fs_write_work(void *a) |
455 | { | 463 | { |
456 | int n, err; | 464 | int n, err; |
457 | struct v9fs_mux_data *m; | 465 | struct v9fs_mux_data *m; |
458 | struct v9fs_req *req; | 466 | struct v9fs_req *req; |
459 | 467 | ||
460 | m = a; | 468 | m = a; |
461 | 469 | ||
462 | if (m->err < 0) { | 470 | if (m->err < 0) { |
463 | clear_bit(Wworksched, &m->wsched); | 471 | clear_bit(Wworksched, &m->wsched); |
464 | return; | 472 | return; |
465 | } | 473 | } |
466 | 474 | ||
467 | if (!m->wsize) { | 475 | if (!m->wsize) { |
468 | if (list_empty(&m->unsent_req_list)) { | 476 | if (list_empty(&m->unsent_req_list)) { |
469 | clear_bit(Wworksched, &m->wsched); | 477 | clear_bit(Wworksched, &m->wsched); |
470 | return; | 478 | return; |
471 | } | 479 | } |
472 | 480 | ||
473 | spin_lock(&m->lock); | 481 | spin_lock(&m->lock); |
474 | again: | 482 | again: |
475 | req = list_entry(m->unsent_req_list.next, struct v9fs_req, | 483 | req = list_entry(m->unsent_req_list.next, struct v9fs_req, |
476 | req_list); | 484 | req_list); |
477 | list_move_tail(&req->req_list, &m->req_list); | 485 | list_move_tail(&req->req_list, &m->req_list); |
478 | if (req->err == ERREQFLUSH) | 486 | if (req->err == ERREQFLUSH) |
479 | goto again; | 487 | goto again; |
480 | 488 | ||
481 | m->wbuf = req->tcall->sdata; | 489 | m->wbuf = req->tcall->sdata; |
482 | m->wsize = req->tcall->size; | 490 | m->wsize = req->tcall->size; |
483 | m->wpos = 0; | 491 | m->wpos = 0; |
484 | dump_data(m->wbuf, m->wsize); | 492 | dump_data(m->wbuf, m->wsize); |
485 | spin_unlock(&m->lock); | 493 | spin_unlock(&m->lock); |
486 | } | 494 | } |
487 | 495 | ||
488 | dprintk(DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos, m->wsize); | 496 | dprintk(DEBUG_MUX, "mux %p pos %d size %d\n", m, m->wpos, m->wsize); |
489 | clear_bit(Wpending, &m->wsched); | 497 | clear_bit(Wpending, &m->wsched); |
490 | err = m->trans->write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos); | 498 | err = m->trans->write(m->trans, m->wbuf + m->wpos, m->wsize - m->wpos); |
491 | dprintk(DEBUG_MUX, "mux %p sent %d bytes\n", m, err); | 499 | dprintk(DEBUG_MUX, "mux %p sent %d bytes\n", m, err); |
492 | if (err == -EAGAIN) { | 500 | if (err == -EAGAIN) { |
493 | clear_bit(Wworksched, &m->wsched); | 501 | clear_bit(Wworksched, &m->wsched); |
494 | return; | 502 | return; |
495 | } | 503 | } |
496 | 504 | ||
497 | if (err <= 0) | 505 | if (err <= 0) |
498 | goto error; | 506 | goto error; |
499 | 507 | ||
500 | m->wpos += err; | 508 | m->wpos += err; |
501 | if (m->wpos == m->wsize) | 509 | if (m->wpos == m->wsize) |
502 | m->wpos = m->wsize = 0; | 510 | m->wpos = m->wsize = 0; |
503 | 511 | ||
504 | if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) { | 512 | if (m->wsize == 0 && !list_empty(&m->unsent_req_list)) { |
505 | if (test_and_clear_bit(Wpending, &m->wsched)) | 513 | if (test_and_clear_bit(Wpending, &m->wsched)) |
506 | n = POLLOUT; | 514 | n = POLLOUT; |
507 | else | 515 | else |
508 | n = m->trans->poll(m->trans, NULL); | 516 | n = m->trans->poll(m->trans, NULL); |
509 | 517 | ||
510 | if (n & POLLOUT) { | 518 | if (n & POLLOUT) { |
511 | dprintk(DEBUG_MUX, "schedule write work mux %p\n", m); | 519 | dprintk(DEBUG_MUX, "schedule write work mux %p\n", m); |
512 | queue_work(v9fs_mux_wq, &m->wq); | 520 | queue_work(v9fs_mux_wq, &m->wq); |
513 | } else | 521 | } else |
514 | clear_bit(Wworksched, &m->wsched); | 522 | clear_bit(Wworksched, &m->wsched); |
515 | } else | 523 | } else |
516 | clear_bit(Wworksched, &m->wsched); | 524 | clear_bit(Wworksched, &m->wsched); |
517 | 525 | ||
518 | return; | 526 | return; |
519 | 527 | ||
520 | error: | 528 | error: |
521 | v9fs_mux_cancel(m, err); | 529 | v9fs_mux_cancel(m, err); |
522 | clear_bit(Wworksched, &m->wsched); | 530 | clear_bit(Wworksched, &m->wsched); |
523 | } | 531 | } |
524 | 532 | ||
525 | static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) | 533 | static void process_request(struct v9fs_mux_data *m, struct v9fs_req *req) |
526 | { | 534 | { |
527 | int ecode, tag; | 535 | int ecode; |
528 | struct v9fs_str *ename; | 536 | struct v9fs_str *ename; |
529 | 537 | ||
530 | tag = req->tag; | ||
531 | if (!req->err && req->rcall->id == RERROR) { | 538 | if (!req->err && req->rcall->id == RERROR) { |
532 | ecode = req->rcall->params.rerror.errno; | 539 | ecode = req->rcall->params.rerror.errno; |
533 | ename = &req->rcall->params.rerror.error; | 540 | ename = &req->rcall->params.rerror.error; |
534 | 541 | ||
535 | dprintk(DEBUG_MUX, "Rerror %.*s\n", ename->len, ename->str); | 542 | dprintk(DEBUG_MUX, "Rerror %.*s\n", ename->len, ename->str); |
536 | 543 | ||
537 | if (*m->extended) | 544 | if (*m->extended) |
538 | req->err = -ecode; | 545 | req->err = -ecode; |
539 | 546 | ||
540 | if (!req->err) { | 547 | if (!req->err) { |
541 | req->err = v9fs_errstr2errno(ename->str, ename->len); | 548 | req->err = v9fs_errstr2errno(ename->str, ename->len); |
542 | 549 | ||
543 | if (!req->err) { /* string match failed */ | 550 | if (!req->err) { /* string match failed */ |
544 | PRINT_FCALL_ERROR("unknown error", req->rcall); | 551 | PRINT_FCALL_ERROR("unknown error", req->rcall); |
545 | } | 552 | } |
546 | 553 | ||
547 | if (!req->err) | 554 | if (!req->err) |
548 | req->err = -ESERVERFAULT; | 555 | req->err = -ESERVERFAULT; |
549 | } | 556 | } |
550 | } else if (req->tcall && req->rcall->id != req->tcall->id + 1) { | 557 | } else if (req->tcall && req->rcall->id != req->tcall->id + 1) { |
551 | dprintk(DEBUG_ERROR, "fcall mismatch: expected %d, got %d\n", | 558 | dprintk(DEBUG_ERROR, "fcall mismatch: expected %d, got %d\n", |
552 | req->tcall->id + 1, req->rcall->id); | 559 | req->tcall->id + 1, req->rcall->id); |
553 | if (!req->err) | 560 | if (!req->err) |
554 | req->err = -EIO; | 561 | req->err = -EIO; |
555 | } | 562 | } |
556 | |||
557 | if (req->err == ERREQFLUSH) | ||
558 | return; | ||
559 | |||
560 | if (req->cb) { | ||
561 | dprintk(DEBUG_MUX, "calling callback tcall %p rcall %p\n", | ||
562 | req->tcall, req->rcall); | ||
563 | |||
564 | (*req->cb) (req->cba, req->tcall, req->rcall, req->err); | ||
565 | req->cb = NULL; | ||
566 | } else | ||
567 | kfree(req->rcall); | ||
568 | |||
569 | v9fs_mux_put_tag(m, tag); | ||
570 | |||
571 | wake_up(&m->equeue); | ||
572 | kfree(req); | ||
573 | } | 563 | } |
574 | 564 | ||
575 | /** | 565 | /** |
576 | * v9fs_read_work - called when there is some data to be read from a transport | 566 | * v9fs_read_work - called when there is some data to be read from a transport |
577 | */ | 567 | */ |
578 | static void v9fs_read_work(void *a) | 568 | static void v9fs_read_work(void *a) |
579 | { | 569 | { |
580 | int n, err; | 570 | int n, err; |
581 | struct v9fs_mux_data *m; | 571 | struct v9fs_mux_data *m; |
582 | struct v9fs_req *req, *rptr, *rreq; | 572 | struct v9fs_req *req, *rptr, *rreq; |
583 | struct v9fs_fcall *rcall; | 573 | struct v9fs_fcall *rcall; |
584 | char *rbuf; | 574 | char *rbuf; |
585 | 575 | ||
586 | m = a; | 576 | m = a; |
587 | 577 | ||
588 | if (m->err < 0) | 578 | if (m->err < 0) |
589 | return; | 579 | return; |
590 | 580 | ||
591 | rcall = NULL; | 581 | rcall = NULL; |
592 | dprintk(DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); | 582 | dprintk(DEBUG_MUX, "start mux %p pos %d\n", m, m->rpos); |
593 | 583 | ||
594 | if (!m->rcall) { | 584 | if (!m->rcall) { |
595 | m->rcall = | 585 | m->rcall = |
596 | kmalloc(sizeof(struct v9fs_fcall) + m->msize, GFP_KERNEL); | 586 | kmalloc(sizeof(struct v9fs_fcall) + m->msize, GFP_KERNEL); |
597 | if (!m->rcall) { | 587 | if (!m->rcall) { |
598 | err = -ENOMEM; | 588 | err = -ENOMEM; |
599 | goto error; | 589 | goto error; |
600 | } | 590 | } |
601 | 591 | ||
602 | m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall); | 592 | m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall); |
603 | m->rpos = 0; | 593 | m->rpos = 0; |
604 | } | 594 | } |
605 | 595 | ||
606 | clear_bit(Rpending, &m->wsched); | 596 | clear_bit(Rpending, &m->wsched); |
607 | err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos); | 597 | err = m->trans->read(m->trans, m->rbuf + m->rpos, m->msize - m->rpos); |
608 | dprintk(DEBUG_MUX, "mux %p got %d bytes\n", m, err); | 598 | dprintk(DEBUG_MUX, "mux %p got %d bytes\n", m, err); |
609 | if (err == -EAGAIN) { | 599 | if (err == -EAGAIN) { |
610 | clear_bit(Rworksched, &m->wsched); | 600 | clear_bit(Rworksched, &m->wsched); |
611 | return; | 601 | return; |
612 | } | 602 | } |
613 | 603 | ||
614 | if (err <= 0) | 604 | if (err <= 0) |
615 | goto error; | 605 | goto error; |
616 | 606 | ||
617 | m->rpos += err; | 607 | m->rpos += err; |
618 | while (m->rpos > 4) { | 608 | while (m->rpos > 4) { |
619 | n = le32_to_cpu(*(__le32 *) m->rbuf); | 609 | n = le32_to_cpu(*(__le32 *) m->rbuf); |
620 | if (n >= m->msize) { | 610 | if (n >= m->msize) { |
621 | dprintk(DEBUG_ERROR, | 611 | dprintk(DEBUG_ERROR, |
622 | "requested packet size too big: %d\n", n); | 612 | "requested packet size too big: %d\n", n); |
623 | err = -EIO; | 613 | err = -EIO; |
624 | goto error; | 614 | goto error; |
625 | } | 615 | } |
626 | 616 | ||
627 | if (m->rpos < n) | 617 | if (m->rpos < n) |
628 | break; | 618 | break; |
629 | 619 | ||
630 | dump_data(m->rbuf, n); | 620 | dump_data(m->rbuf, n); |
631 | err = | 621 | err = |
632 | v9fs_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended); | 622 | v9fs_deserialize_fcall(m->rbuf, n, m->rcall, *m->extended); |
633 | if (err < 0) { | 623 | if (err < 0) { |
634 | goto error; | 624 | goto error; |
635 | } | 625 | } |
636 | 626 | ||
637 | if ((v9fs_debug_level&DEBUG_FCALL) == DEBUG_FCALL) { | 627 | if ((v9fs_debug_level&DEBUG_FCALL) == DEBUG_FCALL) { |
638 | char buf[150]; | 628 | char buf[150]; |
639 | 629 | ||
640 | v9fs_printfcall(buf, sizeof(buf), m->rcall, | 630 | v9fs_printfcall(buf, sizeof(buf), m->rcall, |
641 | *m->extended); | 631 | *m->extended); |
642 | printk(KERN_NOTICE ">>> %p %s\n", m, buf); | 632 | printk(KERN_NOTICE ">>> %p %s\n", m, buf); |
643 | } | 633 | } |
644 | 634 | ||
645 | rcall = m->rcall; | 635 | rcall = m->rcall; |
646 | rbuf = m->rbuf; | 636 | rbuf = m->rbuf; |
647 | if (m->rpos > n) { | 637 | if (m->rpos > n) { |
648 | m->rcall = kmalloc(sizeof(struct v9fs_fcall) + m->msize, | 638 | m->rcall = kmalloc(sizeof(struct v9fs_fcall) + m->msize, |
649 | GFP_KERNEL); | 639 | GFP_KERNEL); |
650 | if (!m->rcall) { | 640 | if (!m->rcall) { |
651 | err = -ENOMEM; | 641 | err = -ENOMEM; |
652 | goto error; | 642 | goto error; |
653 | } | 643 | } |
654 | 644 | ||
655 | m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall); | 645 | m->rbuf = (char *)m->rcall + sizeof(struct v9fs_fcall); |
656 | memmove(m->rbuf, rbuf + n, m->rpos - n); | 646 | memmove(m->rbuf, rbuf + n, m->rpos - n); |
657 | m->rpos -= n; | 647 | m->rpos -= n; |
658 | } else { | 648 | } else { |
659 | m->rcall = NULL; | 649 | m->rcall = NULL; |
660 | m->rbuf = NULL; | 650 | m->rbuf = NULL; |
661 | m->rpos = 0; | 651 | m->rpos = 0; |
662 | } | 652 | } |
663 | 653 | ||
664 | dprintk(DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, rcall->id, | 654 | dprintk(DEBUG_MUX, "mux %p fcall id %d tag %d\n", m, rcall->id, |
665 | rcall->tag); | 655 | rcall->tag); |
666 | 656 | ||
667 | req = NULL; | 657 | req = NULL; |
668 | spin_lock(&m->lock); | 658 | spin_lock(&m->lock); |
669 | list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { | 659 | list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { |
670 | if (rreq->tag == rcall->tag) { | 660 | if (rreq->tag == rcall->tag) { |
671 | req = rreq; | 661 | req = rreq; |
672 | req->rcall = rcall; | 662 | if (req->flush != Flushing) |
673 | list_del(&req->req_list); | 663 | list_del(&req->req_list); |
674 | spin_unlock(&m->lock); | ||
675 | process_request(m, req); | ||
676 | break; | 664 | break; |
677 | } | 665 | } |
678 | |||
679 | } | 666 | } |
667 | spin_unlock(&m->lock); | ||
680 | 668 | ||
681 | if (!req) { | 669 | if (req) { |
682 | spin_unlock(&m->lock); | 670 | req->rcall = rcall; |
671 | process_request(m, req); | ||
672 | |||
673 | if (req->flush != Flushing) { | ||
674 | if (req->cb) | ||
675 | (*req->cb) (req, req->cba); | ||
676 | else | ||
677 | kfree(req->rcall); | ||
678 | |||
679 | wake_up(&m->equeue); | ||
680 | } | ||
681 | } else { | ||
683 | if (err >= 0 && rcall->id != RFLUSH) | 682 | if (err >= 0 && rcall->id != RFLUSH) |
684 | dprintk(DEBUG_ERROR, | 683 | dprintk(DEBUG_ERROR, |
685 | "unexpected response mux %p id %d tag %d\n", | 684 | "unexpected response mux %p id %d tag %d\n", |
686 | m, rcall->id, rcall->tag); | 685 | m, rcall->id, rcall->tag); |
687 | kfree(rcall); | 686 | kfree(rcall); |
688 | } | 687 | } |
689 | } | 688 | } |
690 | 689 | ||
691 | if (!list_empty(&m->req_list)) { | 690 | if (!list_empty(&m->req_list)) { |
692 | if (test_and_clear_bit(Rpending, &m->wsched)) | 691 | if (test_and_clear_bit(Rpending, &m->wsched)) |
693 | n = POLLIN; | 692 | n = POLLIN; |
694 | else | 693 | else |
695 | n = m->trans->poll(m->trans, NULL); | 694 | n = m->trans->poll(m->trans, NULL); |
696 | 695 | ||
697 | if (n & POLLIN) { | 696 | if (n & POLLIN) { |
698 | dprintk(DEBUG_MUX, "schedule read work mux %p\n", m); | 697 | dprintk(DEBUG_MUX, "schedule read work mux %p\n", m); |
699 | queue_work(v9fs_mux_wq, &m->rq); | 698 | queue_work(v9fs_mux_wq, &m->rq); |
700 | } else | 699 | } else |
701 | clear_bit(Rworksched, &m->wsched); | 700 | clear_bit(Rworksched, &m->wsched); |
702 | } else | 701 | } else |
703 | clear_bit(Rworksched, &m->wsched); | 702 | clear_bit(Rworksched, &m->wsched); |
704 | 703 | ||
705 | return; | 704 | return; |
706 | 705 | ||
707 | error: | 706 | error: |
708 | v9fs_mux_cancel(m, err); | 707 | v9fs_mux_cancel(m, err); |
709 | clear_bit(Rworksched, &m->wsched); | 708 | clear_bit(Rworksched, &m->wsched); |
710 | } | 709 | } |
711 | 710 | ||
712 | /** | 711 | /** |
713 | * v9fs_send_request - send 9P request | 712 | * v9fs_send_request - send 9P request |
714 | * The function can sleep until the request is scheduled for sending. | 713 | * The function can sleep until the request is scheduled for sending. |
715 | * The function can be interrupted. Return from the function is not | 714 | * The function can be interrupted. Return from the function is not |
716 | * a guarantee that the request is sent succesfully. Can return errors | 715 | * a guarantee that the request is sent succesfully. Can return errors |
717 | * that can be retrieved by PTR_ERR macros. | 716 | * that can be retrieved by PTR_ERR macros. |
718 | * | 717 | * |
719 | * @m: mux data | 718 | * @m: mux data |
720 | * @tc: request to be sent | 719 | * @tc: request to be sent |
721 | * @cb: callback function to call when response is received | 720 | * @cb: callback function to call when response is received |
722 | * @cba: parameter to pass to the callback function | 721 | * @cba: parameter to pass to the callback function |
723 | */ | 722 | */ |
724 | static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m, | 723 | static struct v9fs_req *v9fs_send_request(struct v9fs_mux_data *m, |
725 | struct v9fs_fcall *tc, | 724 | struct v9fs_fcall *tc, |
726 | v9fs_mux_req_callback cb, void *cba) | 725 | v9fs_mux_req_callback cb, void *cba) |
727 | { | 726 | { |
728 | int n; | 727 | int n; |
729 | struct v9fs_req *req; | 728 | struct v9fs_req *req; |
730 | 729 | ||
731 | dprintk(DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current, | 730 | dprintk(DEBUG_MUX, "mux %p task %p tcall %p id %d\n", m, current, |
732 | tc, tc->id); | 731 | tc, tc->id); |
733 | if (m->err < 0) | 732 | if (m->err < 0) |
734 | return ERR_PTR(m->err); | 733 | return ERR_PTR(m->err); |
735 | 734 | ||
736 | req = kmalloc(sizeof(struct v9fs_req), GFP_KERNEL); | 735 | req = kmalloc(sizeof(struct v9fs_req), GFP_KERNEL); |
737 | if (!req) | 736 | if (!req) |
738 | return ERR_PTR(-ENOMEM); | 737 | return ERR_PTR(-ENOMEM); |
739 | 738 | ||
740 | if (tc->id == TVERSION) | 739 | if (tc->id == TVERSION) |
741 | n = V9FS_NOTAG; | 740 | n = V9FS_NOTAG; |
742 | else | 741 | else |
743 | n = v9fs_mux_get_tag(m); | 742 | n = v9fs_mux_get_tag(m); |
744 | 743 | ||
745 | if (n < 0) | 744 | if (n < 0) |
746 | return ERR_PTR(-ENOMEM); | 745 | return ERR_PTR(-ENOMEM); |
747 | 746 | ||
748 | v9fs_set_tag(tc, n); | 747 | v9fs_set_tag(tc, n); |
749 | |||
750 | if ((v9fs_debug_level&DEBUG_FCALL) == DEBUG_FCALL) { | 748 | if ((v9fs_debug_level&DEBUG_FCALL) == DEBUG_FCALL) { |
751 | char buf[150]; | 749 | char buf[150]; |
752 | 750 | ||
753 | v9fs_printfcall(buf, sizeof(buf), tc, *m->extended); | 751 | v9fs_printfcall(buf, sizeof(buf), tc, *m->extended); |
754 | printk(KERN_NOTICE "<<< %p %s\n", m, buf); | 752 | printk(KERN_NOTICE "<<< %p %s\n", m, buf); |
755 | } | 753 | } |
756 | 754 | ||
755 | spin_lock_init(&req->lock); | ||
757 | req->tag = n; | 756 | req->tag = n; |
758 | req->tcall = tc; | 757 | req->tcall = tc; |
759 | req->rcall = NULL; | 758 | req->rcall = NULL; |
760 | req->err = 0; | 759 | req->err = 0; |
761 | req->cb = cb; | 760 | req->cb = cb; |
762 | req->cba = cba; | 761 | req->cba = cba; |
762 | req->flush = None; | ||
763 | 763 | ||
764 | spin_lock(&m->lock); | 764 | spin_lock(&m->lock); |
765 | list_add_tail(&req->req_list, &m->unsent_req_list); | 765 | list_add_tail(&req->req_list, &m->unsent_req_list); |
766 | spin_unlock(&m->lock); | 766 | spin_unlock(&m->lock); |
767 | 767 | ||
768 | if (test_and_clear_bit(Wpending, &m->wsched)) | 768 | if (test_and_clear_bit(Wpending, &m->wsched)) |
769 | n = POLLOUT; | 769 | n = POLLOUT; |
770 | else | 770 | else |
771 | n = m->trans->poll(m->trans, NULL); | 771 | n = m->trans->poll(m->trans, NULL); |
772 | 772 | ||
773 | if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched)) | 773 | if (n & POLLOUT && !test_and_set_bit(Wworksched, &m->wsched)) |
774 | queue_work(v9fs_mux_wq, &m->wq); | 774 | queue_work(v9fs_mux_wq, &m->wq); |
775 | 775 | ||
776 | return req; | 776 | return req; |
777 | } | 777 | } |
778 | 778 | ||
779 | static void v9fs_mux_flush_cb(void *a, struct v9fs_fcall *tc, | 779 | static void v9fs_mux_free_request(struct v9fs_mux_data *m, struct v9fs_req *req) |
780 | struct v9fs_fcall *rc, int err) | ||
781 | { | 780 | { |
781 | v9fs_mux_put_tag(m, req->tag); | ||
782 | kfree(req); | ||
783 | } | ||
784 | |||
785 | static void v9fs_mux_flush_cb(struct v9fs_req *freq, void *a) | ||
786 | { | ||
782 | v9fs_mux_req_callback cb; | 787 | v9fs_mux_req_callback cb; |
783 | int tag; | 788 | int tag; |
784 | struct v9fs_mux_data *m; | 789 | struct v9fs_mux_data *m; |
785 | struct v9fs_req *req, *rptr; | 790 | struct v9fs_req *req, *rreq, *rptr; |
786 | 791 | ||
787 | m = a; | 792 | m = a; |
788 | dprintk(DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m, tc, | 793 | dprintk(DEBUG_MUX, "mux %p tc %p rc %p err %d oldtag %d\n", m, |
789 | rc, err, tc->params.tflush.oldtag); | 794 | freq->tcall, freq->rcall, freq->err, |
795 | freq->tcall->params.tflush.oldtag); | ||
790 | 796 | ||
791 | spin_lock(&m->lock); | 797 | spin_lock(&m->lock); |
792 | cb = NULL; | 798 | cb = NULL; |
793 | tag = tc->params.tflush.oldtag; | 799 | tag = freq->tcall->params.tflush.oldtag; |
794 | list_for_each_entry_safe(req, rptr, &m->req_list, req_list) { | 800 | req = NULL; |
795 | if (req->tag == tag) { | 801 | list_for_each_entry_safe(rreq, rptr, &m->req_list, req_list) { |
802 | if (rreq->tag == tag) { | ||
803 | req = rreq; | ||
796 | list_del(&req->req_list); | 804 | list_del(&req->req_list); |
797 | if (req->cb) { | ||
798 | cb = req->cb; | ||
799 | req->cb = NULL; | ||
800 | spin_unlock(&m->lock); | ||
801 | (*cb) (req->cba, req->tcall, req->rcall, | ||
802 | req->err); | ||
803 | } | ||
804 | kfree(req); | ||
805 | wake_up(&m->equeue); | ||
806 | break; | 805 | break; |
807 | } | 806 | } |
808 | } | 807 | } |
808 | spin_unlock(&m->lock); | ||
809 | 809 | ||
810 | if (!cb) | 810 | if (req) { |
811 | spin_unlock(&m->lock); | 811 | spin_lock(&req->lock); |
812 | req->flush = Flushed; | ||
813 | spin_unlock(&req->lock); | ||
812 | 814 | ||
813 | v9fs_mux_put_tag(m, tag); | 815 | if (req->cb) |
814 | kfree(tc); | 816 | (*req->cb) (req, req->cba); |
815 | kfree(rc); | 817 | else |
818 | kfree(req->rcall); | ||
819 | |||
820 | wake_up(&m->equeue); | ||
821 | } | ||
822 | |||
823 | kfree(freq->tcall); | ||
824 | kfree(freq->rcall); | ||
825 | v9fs_mux_free_request(m, freq); | ||
816 | } | 826 | } |
817 | 827 | ||
818 | static void | 828 | static int |
819 | v9fs_mux_flush_request(struct v9fs_mux_data *m, struct v9fs_req *req) | 829 | v9fs_mux_flush_request(struct v9fs_mux_data *m, struct v9fs_req *req) |
820 | { | 830 | { |
821 | struct v9fs_fcall *fc; | 831 | struct v9fs_fcall *fc; |
832 | struct v9fs_req *rreq, *rptr; | ||
822 | 833 | ||
823 | dprintk(DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag); | 834 | dprintk(DEBUG_MUX, "mux %p req %p tag %d\n", m, req, req->tag); |
824 | 835 | ||
836 | /* if a response was received for a request, do nothing */ | ||
837 | spin_lock(&req->lock); | ||
838 | if (req->rcall || req->err) { | ||
839 | spin_unlock(&req->lock); | ||
840 | dprintk(DEBUG_MUX, "mux %p req %p response already received\n", m, req); | ||
841 | return 0; | ||
842 | } | ||
843 | |||
844 | req->flush = Flushing; | ||
845 | spin_unlock(&req->lock); | ||
846 | |||
847 | spin_lock(&m->lock); | ||
848 | /* if the request is not sent yet, just remove it from the list */ | ||
849 | list_for_each_entry_safe(rreq, rptr, &m->unsent_req_list, req_list) { | ||
850 | if (rreq->tag == req->tag) { | ||
851 | dprintk(DEBUG_MUX, "mux %p req %p request is not sent yet\n", m, req); | ||
852 | list_del(&rreq->req_list); | ||
853 | req->flush = Flushed; | ||
854 | spin_unlock(&m->lock); | ||
855 | if (req->cb) | ||
856 | (*req->cb) (req, req->cba); | ||
857 | return 0; | ||
858 | } | ||
859 | } | ||
860 | spin_unlock(&m->lock); | ||
861 | |||
862 | clear_thread_flag(TIF_SIGPENDING); | ||
825 | fc = v9fs_create_tflush(req->tag); | 863 | fc = v9fs_create_tflush(req->tag); |
826 | v9fs_send_request(m, fc, v9fs_mux_flush_cb, m); | 864 | v9fs_send_request(m, fc, v9fs_mux_flush_cb, m); |
865 | return 1; | ||
827 | } | 866 | } |
828 | 867 | ||
829 | static void | 868 | static void |
830 | v9fs_mux_rpc_cb(void *a, struct v9fs_fcall *tc, struct v9fs_fcall *rc, int err) | 869 | v9fs_mux_rpc_cb(struct v9fs_req *req, void *a) |
831 | { | 870 | { |
832 | struct v9fs_mux_rpc *r; | 871 | struct v9fs_mux_rpc *r; |
833 | 872 | ||
834 | if (err == ERREQFLUSH) { | 873 | dprintk(DEBUG_MUX, "req %p r %p\n", req, a); |
835 | kfree(rc); | ||
836 | dprintk(DEBUG_MUX, "err req flush\n"); | ||
837 | return; | ||
838 | } | ||
839 | |||
840 | r = a; | 874 | r = a; |
841 | dprintk(DEBUG_MUX, "mux %p req %p tc %p rc %p err %d\n", r->m, r->req, | 875 | r->rcall = req->rcall; |
842 | tc, rc, err); | 876 | r->err = req->err; |
843 | r->rcall = rc; | 877 | |
844 | r->err = err; | 878 | if (req->flush!=None && !req->err) |
879 | r->err = -ERESTARTSYS; | ||
880 | |||
845 | wake_up(&r->wqueue); | 881 | wake_up(&r->wqueue); |
846 | } | 882 | } |
847 | 883 | ||
848 | /** | 884 | /** |
849 | * v9fs_mux_rpc - sends 9P request and waits until a response is available. | 885 | * v9fs_mux_rpc - sends 9P request and waits until a response is available. |
850 | * The function can be interrupted. | 886 | * The function can be interrupted. |
851 | * @m: mux data | 887 | * @m: mux data |
852 | * @tc: request to be sent | 888 | * @tc: request to be sent |
853 | * @rc: pointer where a pointer to the response is stored | 889 | * @rc: pointer where a pointer to the response is stored |
854 | */ | 890 | */ |
855 | int | 891 | int |
856 | v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc, | 892 | v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc, |
857 | struct v9fs_fcall **rc) | 893 | struct v9fs_fcall **rc) |
858 | { | 894 | { |
859 | int err; | 895 | int err, sigpending; |
860 | unsigned long flags; | 896 | unsigned long flags; |
861 | struct v9fs_req *req; | 897 | struct v9fs_req *req; |
862 | struct v9fs_mux_rpc r; | 898 | struct v9fs_mux_rpc r; |
863 | 899 | ||
864 | r.err = 0; | 900 | r.err = 0; |
901 | r.tcall = tc; | ||
865 | r.rcall = NULL; | 902 | r.rcall = NULL; |
866 | r.m = m; | 903 | r.m = m; |
867 | init_waitqueue_head(&r.wqueue); | 904 | init_waitqueue_head(&r.wqueue); |
868 | 905 | ||
869 | if (rc) | 906 | if (rc) |
870 | *rc = NULL; | 907 | *rc = NULL; |
871 | 908 | ||
909 | sigpending = 0; | ||
910 | if (signal_pending(current)) { | ||
911 | sigpending = 1; | ||
912 | clear_thread_flag(TIF_SIGPENDING); | ||
913 | } | ||
914 | |||
872 | req = v9fs_send_request(m, tc, v9fs_mux_rpc_cb, &r); | 915 | req = v9fs_send_request(m, tc, v9fs_mux_rpc_cb, &r); |
873 | if (IS_ERR(req)) { | 916 | if (IS_ERR(req)) { |
874 | err = PTR_ERR(req); | 917 | err = PTR_ERR(req); |
875 | dprintk(DEBUG_MUX, "error %d\n", err); | 918 | dprintk(DEBUG_MUX, "error %d\n", err); |
876 | return PTR_ERR(req); | 919 | return err; |
877 | } | 920 | } |
878 | 921 | ||
879 | r.req = req; | ||
880 | dprintk(DEBUG_MUX, "mux %p tc %p tag %d rpc %p req %p\n", m, tc, | ||
881 | req->tag, &r, req); | ||
882 | err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0); | 922 | err = wait_event_interruptible(r.wqueue, r.rcall != NULL || r.err < 0); |
883 | if (r.err < 0) | 923 | if (r.err < 0) |
884 | err = r.err; | 924 | err = r.err; |
885 | 925 | ||
886 | if (err == -ERESTARTSYS && m->trans->status == Connected && m->err == 0) { | 926 | if (err == -ERESTARTSYS && m->trans->status == Connected && m->err == 0) { |
887 | spin_lock(&m->lock); | 927 | if (v9fs_mux_flush_request(m, req)) { |
888 | req->tcall = NULL; | 928 | /* wait until we get response of the flush message */ |
889 | req->err = ERREQFLUSH; | 929 | do { |
890 | spin_unlock(&m->lock); | 930 | clear_thread_flag(TIF_SIGPENDING); |
931 | err = wait_event_interruptible(r.wqueue, | ||
932 | r.rcall || r.err); | ||
933 | } while (!r.rcall && !r.err && err==-ERESTARTSYS && | ||
934 | m->trans->status==Connected && !m->err); | ||
935 | } | ||
936 | sigpending = 1; | ||
937 | } | ||
891 | 938 | ||
892 | clear_thread_flag(TIF_SIGPENDING); | 939 | if (sigpending) { |
893 | v9fs_mux_flush_request(m, req); | ||
894 | spin_lock_irqsave(¤t->sighand->siglock, flags); | 940 | spin_lock_irqsave(¤t->sighand->siglock, flags); |
895 | recalc_sigpending(); | 941 | recalc_sigpending(); |
896 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); | 942 | spin_unlock_irqrestore(¤t->sighand->siglock, flags); |
897 | } | 943 | } |
898 | 944 | ||
899 | if (!err) { | 945 | if (rc) |
900 | if (r.rcall) | 946 | *rc = r.rcall; |
901 | dprintk(DEBUG_MUX, "got response id %d tag %d\n", | 947 | else |
902 | r.rcall->id, r.rcall->tag); | ||
903 | |||
904 | if (rc) | ||
905 | *rc = r.rcall; | ||
906 | else | ||
907 | kfree(r.rcall); | ||
908 | } else { | ||
909 | kfree(r.rcall); | 948 | kfree(r.rcall); |
910 | dprintk(DEBUG_MUX, "got error %d\n", err); | ||
911 | if (err > 0) | ||
912 | err = -EIO; | ||
913 | } | ||
914 | 949 | ||
950 | v9fs_mux_free_request(m, req); | ||
951 | if (err > 0) | ||
952 | err = -EIO; | ||
953 | |||
915 | return err; | 954 | return err; |
916 | } | 955 | } |
917 | 956 | ||
918 | #if 0 | 957 | #if 0 |
919 | /** | 958 | /** |
920 | * v9fs_mux_rpcnb - sends 9P request without waiting for response. | 959 | * v9fs_mux_rpcnb - sends 9P request without waiting for response. |
921 | * @m: mux data | 960 | * @m: mux data |
922 | * @tc: request to be sent | 961 | * @tc: request to be sent |
923 | * @cb: callback function to be called when response arrives | 962 | * @cb: callback function to be called when response arrives |
924 | * @cba: value to pass to the callback function | 963 | * @cba: value to pass to the callback function |
925 | */ | 964 | */ |
926 | int v9fs_mux_rpcnb(struct v9fs_mux_data *m, struct v9fs_fcall *tc, | 965 | int v9fs_mux_rpcnb(struct v9fs_mux_data *m, struct v9fs_fcall *tc, |
927 | v9fs_mux_req_callback cb, void *a) | 966 | v9fs_mux_req_callback cb, void *a) |
928 | { | 967 | { |
929 | int err; | 968 | int err; |
930 | struct v9fs_req *req; | 969 | struct v9fs_req *req; |
931 | 970 | ||
932 | req = v9fs_send_request(m, tc, cb, a); | 971 | req = v9fs_send_request(m, tc, cb, a); |
933 | if (IS_ERR(req)) { | 972 | if (IS_ERR(req)) { |
934 | err = PTR_ERR(req); | 973 | err = PTR_ERR(req); |
935 | dprintk(DEBUG_MUX, "error %d\n", err); | 974 | dprintk(DEBUG_MUX, "error %d\n", err); |
936 | return PTR_ERR(req); | 975 | return PTR_ERR(req); |
937 | } | 976 | } |
938 | 977 | ||
939 | dprintk(DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag); | 978 | dprintk(DEBUG_MUX, "mux %p tc %p tag %d\n", m, tc, req->tag); |
940 | return 0; | 979 | return 0; |
941 | } | 980 | } |
942 | #endif /* 0 */ | 981 | #endif /* 0 */ |
fs/9p/mux.h
1 | /* | 1 | /* |
2 | * linux/fs/9p/mux.h | 2 | * linux/fs/9p/mux.h |
3 | * | 3 | * |
4 | * Multiplexer Definitions | 4 | * Multiplexer Definitions |
5 | * | 5 | * |
6 | * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net> | 6 | * Copyright (C) 2005 by Latchesar Ionkov <lucho@ionkov.net> |
7 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | 7 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 | 10 | * it under the terms of the GNU General Public License version 2 |
11 | * as published by the Free Software Foundation. | 11 | * as published by the Free Software Foundation. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to: | 19 | * along with this program; if not, write to: |
20 | * Free Software Foundation | 20 | * Free Software Foundation |
21 | * 51 Franklin Street, Fifth Floor | 21 | * 51 Franklin Street, Fifth Floor |
22 | * Boston, MA 02111-1301 USA | 22 | * Boston, MA 02111-1301 USA |
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | struct v9fs_mux_data; | 26 | struct v9fs_mux_data; |
27 | struct v9fs_req; | ||
27 | 28 | ||
28 | /** | 29 | /** |
29 | * v9fs_mux_req_callback - callback function that is called when the | 30 | * v9fs_mux_req_callback - callback function that is called when the |
30 | * response of a request is received. The callback is called from | 31 | * response of a request is received. The callback is called from |
31 | * a workqueue and shouldn't block. | 32 | * a workqueue and shouldn't block. |
32 | * | 33 | * |
33 | * @a - the pointer that was specified when the request was send to be | 34 | * @a - the pointer that was specified when the request was send to be |
34 | * passed to the callback | 35 | * passed to the callback |
35 | * @tc - request call | 36 | * @tc - request call |
36 | * @rc - response call | 37 | * @rc - response call |
37 | * @err - error code (non-zero if error occured) | 38 | * @err - error code (non-zero if error occured) |
38 | */ | 39 | */ |
39 | typedef void (*v9fs_mux_req_callback)(void *a, struct v9fs_fcall *tc, | 40 | typedef void (*v9fs_mux_req_callback)(struct v9fs_req *req, void *a); |
40 | struct v9fs_fcall *rc, int err); | ||
41 | 41 | ||
42 | int v9fs_mux_global_init(void); | 42 | int v9fs_mux_global_init(void); |
43 | void v9fs_mux_global_exit(void); | 43 | void v9fs_mux_global_exit(void); |
44 | 44 | ||
45 | struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, | 45 | struct v9fs_mux_data *v9fs_mux_init(struct v9fs_transport *trans, int msize, |
46 | unsigned char *extended); | 46 | unsigned char *extended); |
47 | void v9fs_mux_destroy(struct v9fs_mux_data *); | 47 | void v9fs_mux_destroy(struct v9fs_mux_data *); |
48 | 48 | ||
49 | int v9fs_mux_send(struct v9fs_mux_data *m, struct v9fs_fcall *tc); | 49 | int v9fs_mux_send(struct v9fs_mux_data *m, struct v9fs_fcall *tc); |
50 | struct v9fs_fcall *v9fs_mux_recv(struct v9fs_mux_data *m); | 50 | struct v9fs_fcall *v9fs_mux_recv(struct v9fs_mux_data *m); |
51 | int v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc, struct v9fs_fcall **rc); | 51 | int v9fs_mux_rpc(struct v9fs_mux_data *m, struct v9fs_fcall *tc, struct v9fs_fcall **rc); |
52 | 52 | ||
53 | void v9fs_mux_flush(struct v9fs_mux_data *m, int sendflush); | 53 | void v9fs_mux_flush(struct v9fs_mux_data *m, int sendflush); |
54 | void v9fs_mux_cancel(struct v9fs_mux_data *m, int err); | 54 | void v9fs_mux_cancel(struct v9fs_mux_data *m, int err); |
55 | int v9fs_errstr2errno(char *errstr, int len); | 55 | int v9fs_errstr2errno(char *errstr, int len); |
fs/9p/vfs_file.c
1 | /* | 1 | /* |
2 | * linux/fs/9p/vfs_file.c | 2 | * linux/fs/9p/vfs_file.c |
3 | * | 3 | * |
4 | * This file contians vfs file ops for 9P2000. | 4 | * This file contians vfs file ops for 9P2000. |
5 | * | 5 | * |
6 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | 6 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> |
7 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | 7 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 | 10 | * it under the terms of the GNU General Public License version 2 |
11 | * as published by the Free Software Foundation. | 11 | * as published by the Free Software Foundation. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to: | 19 | * along with this program; if not, write to: |
20 | * Free Software Foundation | 20 | * Free Software Foundation |
21 | * 51 Franklin Street, Fifth Floor | 21 | * 51 Franklin Street, Fifth Floor |
22 | * Boston, MA 02111-1301 USA | 22 | * Boston, MA 02111-1301 USA |
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/errno.h> | 27 | #include <linux/errno.h> |
28 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
29 | #include <linux/file.h> | 29 | #include <linux/file.h> |
30 | #include <linux/stat.h> | 30 | #include <linux/stat.h> |
31 | #include <linux/string.h> | 31 | #include <linux/string.h> |
32 | #include <linux/smp_lock.h> | 32 | #include <linux/smp_lock.h> |
33 | #include <linux/inet.h> | 33 | #include <linux/inet.h> |
34 | #include <linux/version.h> | 34 | #include <linux/version.h> |
35 | #include <linux/list.h> | 35 | #include <linux/list.h> |
36 | #include <asm/uaccess.h> | 36 | #include <asm/uaccess.h> |
37 | #include <linux/idr.h> | 37 | #include <linux/idr.h> |
38 | 38 | ||
39 | #include "debug.h" | 39 | #include "debug.h" |
40 | #include "v9fs.h" | 40 | #include "v9fs.h" |
41 | #include "9p.h" | 41 | #include "9p.h" |
42 | #include "v9fs_vfs.h" | 42 | #include "v9fs_vfs.h" |
43 | #include "fid.h" | 43 | #include "fid.h" |
44 | 44 | ||
45 | /** | 45 | /** |
46 | * v9fs_file_open - open a file (or directory) | 46 | * v9fs_file_open - open a file (or directory) |
47 | * @inode: inode to be opened | 47 | * @inode: inode to be opened |
48 | * @file: file being opened | 48 | * @file: file being opened |
49 | * | 49 | * |
50 | */ | 50 | */ |
51 | 51 | ||
52 | int v9fs_file_open(struct inode *inode, struct file *file) | 52 | int v9fs_file_open(struct inode *inode, struct file *file) |
53 | { | 53 | { |
54 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 54 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); |
55 | struct v9fs_fid *vfid; | 55 | struct v9fs_fid *vfid; |
56 | struct v9fs_fcall *fcall = NULL; | 56 | struct v9fs_fcall *fcall = NULL; |
57 | int omode; | 57 | int omode; |
58 | int fid = V9FS_NOFID; | 58 | int fid = V9FS_NOFID; |
59 | int err; | 59 | int err; |
60 | 60 | ||
61 | dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file); | 61 | dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file); |
62 | 62 | ||
63 | vfid = v9fs_fid_lookup(file->f_dentry); | 63 | vfid = v9fs_fid_lookup(file->f_dentry); |
64 | if (!vfid) { | 64 | if (!vfid) { |
65 | dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); | 65 | dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); |
66 | return -EBADF; | 66 | return -EBADF; |
67 | } | 67 | } |
68 | 68 | ||
69 | fid = v9fs_get_idpool(&v9ses->fidpool); | 69 | fid = v9fs_get_idpool(&v9ses->fidpool); |
70 | if (fid < 0) { | 70 | if (fid < 0) { |
71 | eprintk(KERN_WARNING, "newfid fails!\n"); | 71 | eprintk(KERN_WARNING, "newfid fails!\n"); |
72 | return -ENOSPC; | 72 | return -ENOSPC; |
73 | } | 73 | } |
74 | 74 | ||
75 | err = v9fs_t_walk(v9ses, vfid->fid, fid, NULL, NULL); | 75 | err = v9fs_t_walk(v9ses, vfid->fid, fid, NULL, &fcall); |
76 | if (err < 0) { | 76 | if (err < 0) { |
77 | dprintk(DEBUG_ERROR, "rewalk didn't work\n"); | 77 | dprintk(DEBUG_ERROR, "rewalk didn't work\n"); |
78 | goto put_fid; | 78 | if (fcall && fcall->id == RWALK) |
79 | goto clunk_fid; | ||
80 | else { | ||
81 | v9fs_put_idpool(fid, &v9ses->fidpool); | ||
82 | goto free_fcall; | ||
83 | } | ||
79 | } | 84 | } |
85 | kfree(fcall); | ||
80 | 86 | ||
81 | /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ | 87 | /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ |
82 | /* translate open mode appropriately */ | 88 | /* translate open mode appropriately */ |
83 | omode = v9fs_uflags2omode(file->f_flags); | 89 | omode = v9fs_uflags2omode(file->f_flags); |
84 | err = v9fs_t_open(v9ses, fid, omode, &fcall); | 90 | err = v9fs_t_open(v9ses, fid, omode, &fcall); |
85 | if (err < 0) { | 91 | if (err < 0) { |
86 | PRINT_FCALL_ERROR("open failed", fcall); | 92 | PRINT_FCALL_ERROR("open failed", fcall); |
87 | goto clunk_fid; | 93 | goto clunk_fid; |
88 | } | 94 | } |
89 | 95 | ||
90 | vfid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); | 96 | vfid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); |
91 | if (vfid == NULL) { | 97 | if (vfid == NULL) { |
92 | dprintk(DEBUG_ERROR, "out of memory\n"); | 98 | dprintk(DEBUG_ERROR, "out of memory\n"); |
93 | err = -ENOMEM; | 99 | err = -ENOMEM; |
94 | goto clunk_fid; | 100 | goto clunk_fid; |
95 | } | 101 | } |
96 | 102 | ||
97 | file->private_data = vfid; | 103 | file->private_data = vfid; |
98 | vfid->fid = fid; | 104 | vfid->fid = fid; |
99 | vfid->fidopen = 1; | 105 | vfid->fidopen = 1; |
100 | vfid->fidclunked = 0; | 106 | vfid->fidclunked = 0; |
101 | vfid->iounit = fcall->params.ropen.iounit; | 107 | vfid->iounit = fcall->params.ropen.iounit; |
102 | vfid->rdir_pos = 0; | 108 | vfid->rdir_pos = 0; |
103 | vfid->rdir_fcall = NULL; | 109 | vfid->rdir_fcall = NULL; |
104 | vfid->filp = file; | 110 | vfid->filp = file; |
105 | kfree(fcall); | 111 | kfree(fcall); |
106 | 112 | ||
107 | return 0; | 113 | return 0; |
108 | 114 | ||
109 | clunk_fid: | 115 | clunk_fid: |
110 | v9fs_t_clunk(v9ses, fid); | 116 | v9fs_t_clunk(v9ses, fid); |
111 | 117 | ||
112 | put_fid: | 118 | free_fcall: |
113 | v9fs_put_idpool(fid, &v9ses->fidpool); | ||
114 | kfree(fcall); | 119 | kfree(fcall); |
115 | 120 | ||
116 | return err; | 121 | return err; |
117 | } | 122 | } |
118 | 123 | ||
119 | /** | 124 | /** |
120 | * v9fs_file_lock - lock a file (or directory) | 125 | * v9fs_file_lock - lock a file (or directory) |
121 | * @inode: inode to be opened | 126 | * @inode: inode to be opened |
122 | * @file: file being opened | 127 | * @file: file being opened |
123 | * | 128 | * |
124 | * XXX - this looks like a local only lock, we should extend into 9P | 129 | * XXX - this looks like a local only lock, we should extend into 9P |
125 | * by using open exclusive | 130 | * by using open exclusive |
126 | */ | 131 | */ |
127 | 132 | ||
128 | static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) | 133 | static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) |
129 | { | 134 | { |
130 | int res = 0; | 135 | int res = 0; |
131 | struct inode *inode = filp->f_dentry->d_inode; | 136 | struct inode *inode = filp->f_dentry->d_inode; |
132 | 137 | ||
133 | dprintk(DEBUG_VFS, "filp: %p lock: %p\n", filp, fl); | 138 | dprintk(DEBUG_VFS, "filp: %p lock: %p\n", filp, fl); |
134 | 139 | ||
135 | /* No mandatory locks */ | 140 | /* No mandatory locks */ |
136 | if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) | 141 | if ((inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) |
137 | return -ENOLCK; | 142 | return -ENOLCK; |
138 | 143 | ||
139 | if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { | 144 | if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { |
140 | filemap_write_and_wait(inode->i_mapping); | 145 | filemap_write_and_wait(inode->i_mapping); |
141 | invalidate_inode_pages(&inode->i_data); | 146 | invalidate_inode_pages(&inode->i_data); |
142 | } | 147 | } |
143 | 148 | ||
144 | return res; | 149 | return res; |
145 | } | 150 | } |
146 | 151 | ||
147 | /** | 152 | /** |
148 | * v9fs_file_read - read from a file | 153 | * v9fs_file_read - read from a file |
149 | * @filep: file pointer to read | 154 | * @filep: file pointer to read |
150 | * @data: data buffer to read data into | 155 | * @data: data buffer to read data into |
151 | * @count: size of buffer | 156 | * @count: size of buffer |
152 | * @offset: offset at which to read data | 157 | * @offset: offset at which to read data |
153 | * | 158 | * |
154 | */ | 159 | */ |
155 | static ssize_t | 160 | static ssize_t |
156 | v9fs_file_read(struct file *filp, char __user * data, size_t count, | 161 | v9fs_file_read(struct file *filp, char __user * data, size_t count, |
157 | loff_t * offset) | 162 | loff_t * offset) |
158 | { | 163 | { |
159 | struct inode *inode = filp->f_dentry->d_inode; | 164 | struct inode *inode = filp->f_dentry->d_inode; |
160 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 165 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); |
161 | struct v9fs_fid *v9f = filp->private_data; | 166 | struct v9fs_fid *v9f = filp->private_data; |
162 | struct v9fs_fcall *fcall = NULL; | 167 | struct v9fs_fcall *fcall = NULL; |
163 | int fid = v9f->fid; | 168 | int fid = v9f->fid; |
164 | int rsize = 0; | 169 | int rsize = 0; |
165 | int result = 0; | 170 | int result = 0; |
166 | int total = 0; | 171 | int total = 0; |
167 | int n; | 172 | int n; |
168 | 173 | ||
169 | dprintk(DEBUG_VFS, "\n"); | 174 | dprintk(DEBUG_VFS, "\n"); |
170 | 175 | ||
171 | rsize = v9ses->maxdata - V9FS_IOHDRSZ; | 176 | rsize = v9ses->maxdata - V9FS_IOHDRSZ; |
172 | if (v9f->iounit != 0 && rsize > v9f->iounit) | 177 | if (v9f->iounit != 0 && rsize > v9f->iounit) |
173 | rsize = v9f->iounit; | 178 | rsize = v9f->iounit; |
174 | 179 | ||
175 | do { | 180 | do { |
176 | if (count < rsize) | 181 | if (count < rsize) |
177 | rsize = count; | 182 | rsize = count; |
178 | 183 | ||
179 | result = v9fs_t_read(v9ses, fid, *offset, rsize, &fcall); | 184 | result = v9fs_t_read(v9ses, fid, *offset, rsize, &fcall); |
180 | 185 | ||
181 | if (result < 0) { | 186 | if (result < 0) { |
182 | printk(KERN_ERR "9P2000: v9fs_t_read returned %d\n", | 187 | printk(KERN_ERR "9P2000: v9fs_t_read returned %d\n", |
183 | result); | 188 | result); |
184 | 189 | ||
185 | kfree(fcall); | 190 | kfree(fcall); |
186 | return total; | 191 | return total; |
187 | } else | 192 | } else |
188 | *offset += result; | 193 | *offset += result; |
189 | 194 | ||
190 | n = copy_to_user(data, fcall->params.rread.data, result); | 195 | n = copy_to_user(data, fcall->params.rread.data, result); |
191 | if (n) { | 196 | if (n) { |
192 | dprintk(DEBUG_ERROR, "Problem copying to user %d\n", n); | 197 | dprintk(DEBUG_ERROR, "Problem copying to user %d\n", n); |
193 | kfree(fcall); | 198 | kfree(fcall); |
194 | return -EFAULT; | 199 | return -EFAULT; |
195 | } | 200 | } |
196 | 201 | ||
197 | count -= result; | 202 | count -= result; |
198 | data += result; | 203 | data += result; |
199 | total += result; | 204 | total += result; |
200 | 205 | ||
201 | kfree(fcall); | 206 | kfree(fcall); |
202 | 207 | ||
203 | if (result < rsize) | 208 | if (result < rsize) |
204 | break; | 209 | break; |
205 | } while (count); | 210 | } while (count); |
206 | 211 | ||
207 | return total; | 212 | return total; |
208 | } | 213 | } |
209 | 214 | ||
210 | /** | 215 | /** |
211 | * v9fs_file_write - write to a file | 216 | * v9fs_file_write - write to a file |
212 | * @filep: file pointer to write | 217 | * @filep: file pointer to write |
213 | * @data: data buffer to write data from | 218 | * @data: data buffer to write data from |
214 | * @count: size of buffer | 219 | * @count: size of buffer |
215 | * @offset: offset at which to write data | 220 | * @offset: offset at which to write data |
216 | * | 221 | * |
217 | */ | 222 | */ |
218 | 223 | ||
219 | static ssize_t | 224 | static ssize_t |
220 | v9fs_file_write(struct file *filp, const char __user * data, | 225 | v9fs_file_write(struct file *filp, const char __user * data, |
221 | size_t count, loff_t * offset) | 226 | size_t count, loff_t * offset) |
222 | { | 227 | { |
223 | struct inode *inode = filp->f_dentry->d_inode; | 228 | struct inode *inode = filp->f_dentry->d_inode; |
224 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 229 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); |
225 | struct v9fs_fid *v9fid = filp->private_data; | 230 | struct v9fs_fid *v9fid = filp->private_data; |
226 | struct v9fs_fcall *fcall; | 231 | struct v9fs_fcall *fcall; |
227 | int fid = v9fid->fid; | 232 | int fid = v9fid->fid; |
228 | int result = -EIO; | 233 | int result = -EIO; |
229 | int rsize = 0; | 234 | int rsize = 0; |
230 | int total = 0; | 235 | int total = 0; |
231 | 236 | ||
232 | dprintk(DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count, | 237 | dprintk(DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count, |
233 | (int)*offset); | 238 | (int)*offset); |
234 | rsize = v9ses->maxdata - V9FS_IOHDRSZ; | 239 | rsize = v9ses->maxdata - V9FS_IOHDRSZ; |
235 | if (v9fid->iounit != 0 && rsize > v9fid->iounit) | 240 | if (v9fid->iounit != 0 && rsize > v9fid->iounit) |
236 | rsize = v9fid->iounit; | 241 | rsize = v9fid->iounit; |
237 | 242 | ||
238 | do { | 243 | do { |
239 | if (count < rsize) | 244 | if (count < rsize) |
240 | rsize = count; | 245 | rsize = count; |
241 | 246 | ||
242 | result = v9fs_t_write(v9ses, fid, *offset, rsize, data, &fcall); | 247 | result = v9fs_t_write(v9ses, fid, *offset, rsize, data, &fcall); |
243 | if (result < 0) { | 248 | if (result < 0) { |
244 | PRINT_FCALL_ERROR("error while writing", fcall); | 249 | PRINT_FCALL_ERROR("error while writing", fcall); |
245 | kfree(fcall); | 250 | kfree(fcall); |
246 | return result; | 251 | return result; |
247 | } else | 252 | } else |
248 | *offset += result; | 253 | *offset += result; |
249 | 254 | ||
250 | kfree(fcall); | 255 | kfree(fcall); |
251 | fcall = NULL; | 256 | fcall = NULL; |
252 | 257 | ||
253 | if (result != rsize) { | 258 | if (result != rsize) { |
254 | eprintk(KERN_ERR, | 259 | eprintk(KERN_ERR, |
255 | "short write: v9fs_t_write returned %d\n", | 260 | "short write: v9fs_t_write returned %d\n", |
256 | result); | 261 | result); |
257 | break; | 262 | break; |
258 | } | 263 | } |
259 | 264 | ||
260 | count -= result; | 265 | count -= result; |
261 | data += result; | 266 | data += result; |
262 | total += result; | 267 | total += result; |
263 | } while (count); | 268 | } while (count); |
264 | 269 | ||
265 | invalidate_inode_pages2(inode->i_mapping); | 270 | invalidate_inode_pages2(inode->i_mapping); |
266 | return total; | 271 | return total; |
267 | } | 272 | } |
268 | 273 | ||
269 | const struct file_operations v9fs_file_operations = { | 274 | const struct file_operations v9fs_file_operations = { |
270 | .llseek = generic_file_llseek, | 275 | .llseek = generic_file_llseek, |
271 | .read = v9fs_file_read, | 276 | .read = v9fs_file_read, |
272 | .write = v9fs_file_write, | 277 | .write = v9fs_file_write, |
273 | .open = v9fs_file_open, | 278 | .open = v9fs_file_open, |
274 | .release = v9fs_dir_release, | 279 | .release = v9fs_dir_release, |
275 | .lock = v9fs_file_lock, | 280 | .lock = v9fs_file_lock, |
276 | .mmap = generic_file_mmap, | 281 | .mmap = generic_file_mmap, |
277 | }; | 282 | }; |
fs/9p/vfs_inode.c
1 | /* | 1 | /* |
2 | * linux/fs/9p/vfs_inode.c | 2 | * linux/fs/9p/vfs_inode.c |
3 | * | 3 | * |
4 | * This file contains vfs inode ops for the 9P2000 protocol. | 4 | * This file contains vfs inode ops for the 9P2000 protocol. |
5 | * | 5 | * |
6 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> | 6 | * Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com> |
7 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> | 7 | * Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov> |
8 | * | 8 | * |
9 | * This program is free software; you can redistribute it and/or modify | 9 | * This program is free software; you can redistribute it and/or modify |
10 | * it under the terms of the GNU General Public License version 2 | 10 | * it under the terms of the GNU General Public License version 2 |
11 | * as published by the Free Software Foundation. | 11 | * as published by the Free Software Foundation. |
12 | * | 12 | * |
13 | * This program is distributed in the hope that it will be useful, | 13 | * This program is distributed in the hope that it will be useful, |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
16 | * GNU General Public License for more details. | 16 | * GNU General Public License for more details. |
17 | * | 17 | * |
18 | * You should have received a copy of the GNU General Public License | 18 | * You should have received a copy of the GNU General Public License |
19 | * along with this program; if not, write to: | 19 | * along with this program; if not, write to: |
20 | * Free Software Foundation | 20 | * Free Software Foundation |
21 | * 51 Franklin Street, Fifth Floor | 21 | * 51 Franklin Street, Fifth Floor |
22 | * Boston, MA 02111-1301 USA | 22 | * Boston, MA 02111-1301 USA |
23 | * | 23 | * |
24 | */ | 24 | */ |
25 | 25 | ||
26 | #include <linux/module.h> | 26 | #include <linux/module.h> |
27 | #include <linux/errno.h> | 27 | #include <linux/errno.h> |
28 | #include <linux/fs.h> | 28 | #include <linux/fs.h> |
29 | #include <linux/file.h> | 29 | #include <linux/file.h> |
30 | #include <linux/pagemap.h> | 30 | #include <linux/pagemap.h> |
31 | #include <linux/stat.h> | 31 | #include <linux/stat.h> |
32 | #include <linux/string.h> | 32 | #include <linux/string.h> |
33 | #include <linux/smp_lock.h> | 33 | #include <linux/smp_lock.h> |
34 | #include <linux/inet.h> | 34 | #include <linux/inet.h> |
35 | #include <linux/namei.h> | 35 | #include <linux/namei.h> |
36 | #include <linux/idr.h> | 36 | #include <linux/idr.h> |
37 | 37 | ||
38 | #include "debug.h" | 38 | #include "debug.h" |
39 | #include "v9fs.h" | 39 | #include "v9fs.h" |
40 | #include "9p.h" | 40 | #include "9p.h" |
41 | #include "v9fs_vfs.h" | 41 | #include "v9fs_vfs.h" |
42 | #include "fid.h" | 42 | #include "fid.h" |
43 | 43 | ||
44 | static struct inode_operations v9fs_dir_inode_operations; | 44 | static struct inode_operations v9fs_dir_inode_operations; |
45 | static struct inode_operations v9fs_dir_inode_operations_ext; | 45 | static struct inode_operations v9fs_dir_inode_operations_ext; |
46 | static struct inode_operations v9fs_file_inode_operations; | 46 | static struct inode_operations v9fs_file_inode_operations; |
47 | static struct inode_operations v9fs_symlink_inode_operations; | 47 | static struct inode_operations v9fs_symlink_inode_operations; |
48 | 48 | ||
49 | /** | 49 | /** |
50 | * unixmode2p9mode - convert unix mode bits to plan 9 | 50 | * unixmode2p9mode - convert unix mode bits to plan 9 |
51 | * @v9ses: v9fs session information | 51 | * @v9ses: v9fs session information |
52 | * @mode: mode to convert | 52 | * @mode: mode to convert |
53 | * | 53 | * |
54 | */ | 54 | */ |
55 | 55 | ||
56 | static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) | 56 | static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) |
57 | { | 57 | { |
58 | int res; | 58 | int res; |
59 | res = mode & 0777; | 59 | res = mode & 0777; |
60 | if (S_ISDIR(mode)) | 60 | if (S_ISDIR(mode)) |
61 | res |= V9FS_DMDIR; | 61 | res |= V9FS_DMDIR; |
62 | if (v9ses->extended) { | 62 | if (v9ses->extended) { |
63 | if (S_ISLNK(mode)) | 63 | if (S_ISLNK(mode)) |
64 | res |= V9FS_DMSYMLINK; | 64 | res |= V9FS_DMSYMLINK; |
65 | if (v9ses->nodev == 0) { | 65 | if (v9ses->nodev == 0) { |
66 | if (S_ISSOCK(mode)) | 66 | if (S_ISSOCK(mode)) |
67 | res |= V9FS_DMSOCKET; | 67 | res |= V9FS_DMSOCKET; |
68 | if (S_ISFIFO(mode)) | 68 | if (S_ISFIFO(mode)) |
69 | res |= V9FS_DMNAMEDPIPE; | 69 | res |= V9FS_DMNAMEDPIPE; |
70 | if (S_ISBLK(mode)) | 70 | if (S_ISBLK(mode)) |
71 | res |= V9FS_DMDEVICE; | 71 | res |= V9FS_DMDEVICE; |
72 | if (S_ISCHR(mode)) | 72 | if (S_ISCHR(mode)) |
73 | res |= V9FS_DMDEVICE; | 73 | res |= V9FS_DMDEVICE; |
74 | } | 74 | } |
75 | 75 | ||
76 | if ((mode & S_ISUID) == S_ISUID) | 76 | if ((mode & S_ISUID) == S_ISUID) |
77 | res |= V9FS_DMSETUID; | 77 | res |= V9FS_DMSETUID; |
78 | if ((mode & S_ISGID) == S_ISGID) | 78 | if ((mode & S_ISGID) == S_ISGID) |
79 | res |= V9FS_DMSETGID; | 79 | res |= V9FS_DMSETGID; |
80 | if ((mode & V9FS_DMLINK)) | 80 | if ((mode & V9FS_DMLINK)) |
81 | res |= V9FS_DMLINK; | 81 | res |= V9FS_DMLINK; |
82 | } | 82 | } |
83 | 83 | ||
84 | return res; | 84 | return res; |
85 | } | 85 | } |
86 | 86 | ||
87 | /** | 87 | /** |
88 | * p9mode2unixmode- convert plan9 mode bits to unix mode bits | 88 | * p9mode2unixmode- convert plan9 mode bits to unix mode bits |
89 | * @v9ses: v9fs session information | 89 | * @v9ses: v9fs session information |
90 | * @mode: mode to convert | 90 | * @mode: mode to convert |
91 | * | 91 | * |
92 | */ | 92 | */ |
93 | 93 | ||
94 | static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) | 94 | static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) |
95 | { | 95 | { |
96 | int res; | 96 | int res; |
97 | 97 | ||
98 | res = mode & 0777; | 98 | res = mode & 0777; |
99 | 99 | ||
100 | if ((mode & V9FS_DMDIR) == V9FS_DMDIR) | 100 | if ((mode & V9FS_DMDIR) == V9FS_DMDIR) |
101 | res |= S_IFDIR; | 101 | res |= S_IFDIR; |
102 | else if ((mode & V9FS_DMSYMLINK) && (v9ses->extended)) | 102 | else if ((mode & V9FS_DMSYMLINK) && (v9ses->extended)) |
103 | res |= S_IFLNK; | 103 | res |= S_IFLNK; |
104 | else if ((mode & V9FS_DMSOCKET) && (v9ses->extended) | 104 | else if ((mode & V9FS_DMSOCKET) && (v9ses->extended) |
105 | && (v9ses->nodev == 0)) | 105 | && (v9ses->nodev == 0)) |
106 | res |= S_IFSOCK; | 106 | res |= S_IFSOCK; |
107 | else if ((mode & V9FS_DMNAMEDPIPE) && (v9ses->extended) | 107 | else if ((mode & V9FS_DMNAMEDPIPE) && (v9ses->extended) |
108 | && (v9ses->nodev == 0)) | 108 | && (v9ses->nodev == 0)) |
109 | res |= S_IFIFO; | 109 | res |= S_IFIFO; |
110 | else if ((mode & V9FS_DMDEVICE) && (v9ses->extended) | 110 | else if ((mode & V9FS_DMDEVICE) && (v9ses->extended) |
111 | && (v9ses->nodev == 0)) | 111 | && (v9ses->nodev == 0)) |
112 | res |= S_IFBLK; | 112 | res |= S_IFBLK; |
113 | else | 113 | else |
114 | res |= S_IFREG; | 114 | res |= S_IFREG; |
115 | 115 | ||
116 | if (v9ses->extended) { | 116 | if (v9ses->extended) { |
117 | if ((mode & V9FS_DMSETUID) == V9FS_DMSETUID) | 117 | if ((mode & V9FS_DMSETUID) == V9FS_DMSETUID) |
118 | res |= S_ISUID; | 118 | res |= S_ISUID; |
119 | 119 | ||
120 | if ((mode & V9FS_DMSETGID) == V9FS_DMSETGID) | 120 | if ((mode & V9FS_DMSETGID) == V9FS_DMSETGID) |
121 | res |= S_ISGID; | 121 | res |= S_ISGID; |
122 | } | 122 | } |
123 | 123 | ||
124 | return res; | 124 | return res; |
125 | } | 125 | } |
126 | 126 | ||
127 | int v9fs_uflags2omode(int uflags) | 127 | int v9fs_uflags2omode(int uflags) |
128 | { | 128 | { |
129 | int ret; | 129 | int ret; |
130 | 130 | ||
131 | ret = 0; | 131 | ret = 0; |
132 | switch (uflags&3) { | 132 | switch (uflags&3) { |
133 | default: | 133 | default: |
134 | case O_RDONLY: | 134 | case O_RDONLY: |
135 | ret = V9FS_OREAD; | 135 | ret = V9FS_OREAD; |
136 | break; | 136 | break; |
137 | 137 | ||
138 | case O_WRONLY: | 138 | case O_WRONLY: |
139 | ret = V9FS_OWRITE; | 139 | ret = V9FS_OWRITE; |
140 | break; | 140 | break; |
141 | 141 | ||
142 | case O_RDWR: | 142 | case O_RDWR: |
143 | ret = V9FS_ORDWR; | 143 | ret = V9FS_ORDWR; |
144 | break; | 144 | break; |
145 | } | 145 | } |
146 | 146 | ||
147 | if (uflags & O_EXCL) | 147 | if (uflags & O_EXCL) |
148 | ret |= V9FS_OEXCL; | 148 | ret |= V9FS_OEXCL; |
149 | 149 | ||
150 | if (uflags & O_TRUNC) | 150 | if (uflags & O_TRUNC) |
151 | ret |= V9FS_OTRUNC; | 151 | ret |= V9FS_OTRUNC; |
152 | 152 | ||
153 | if (uflags & O_APPEND) | 153 | if (uflags & O_APPEND) |
154 | ret |= V9FS_OAPPEND; | 154 | ret |= V9FS_OAPPEND; |
155 | 155 | ||
156 | return ret; | 156 | return ret; |
157 | } | 157 | } |
158 | 158 | ||
159 | /** | 159 | /** |
160 | * v9fs_blank_wstat - helper function to setup a 9P stat structure | 160 | * v9fs_blank_wstat - helper function to setup a 9P stat structure |
161 | * @v9ses: 9P session info (for determining extended mode) | 161 | * @v9ses: 9P session info (for determining extended mode) |
162 | * @wstat: structure to initialize | 162 | * @wstat: structure to initialize |
163 | * | 163 | * |
164 | */ | 164 | */ |
165 | 165 | ||
166 | static void | 166 | static void |
167 | v9fs_blank_wstat(struct v9fs_wstat *wstat) | 167 | v9fs_blank_wstat(struct v9fs_wstat *wstat) |
168 | { | 168 | { |
169 | wstat->type = ~0; | 169 | wstat->type = ~0; |
170 | wstat->dev = ~0; | 170 | wstat->dev = ~0; |
171 | wstat->qid.type = ~0; | 171 | wstat->qid.type = ~0; |
172 | wstat->qid.version = ~0; | 172 | wstat->qid.version = ~0; |
173 | *((long long *)&wstat->qid.path) = ~0; | 173 | *((long long *)&wstat->qid.path) = ~0; |
174 | wstat->mode = ~0; | 174 | wstat->mode = ~0; |
175 | wstat->atime = ~0; | 175 | wstat->atime = ~0; |
176 | wstat->mtime = ~0; | 176 | wstat->mtime = ~0; |
177 | wstat->length = ~0; | 177 | wstat->length = ~0; |
178 | wstat->name = NULL; | 178 | wstat->name = NULL; |
179 | wstat->uid = NULL; | 179 | wstat->uid = NULL; |
180 | wstat->gid = NULL; | 180 | wstat->gid = NULL; |
181 | wstat->muid = NULL; | 181 | wstat->muid = NULL; |
182 | wstat->n_uid = ~0; | 182 | wstat->n_uid = ~0; |
183 | wstat->n_gid = ~0; | 183 | wstat->n_gid = ~0; |
184 | wstat->n_muid = ~0; | 184 | wstat->n_muid = ~0; |
185 | wstat->extension = NULL; | 185 | wstat->extension = NULL; |
186 | } | 186 | } |
187 | 187 | ||
188 | /** | 188 | /** |
189 | * v9fs_get_inode - helper function to setup an inode | 189 | * v9fs_get_inode - helper function to setup an inode |
190 | * @sb: superblock | 190 | * @sb: superblock |
191 | * @mode: mode to setup inode with | 191 | * @mode: mode to setup inode with |
192 | * | 192 | * |
193 | */ | 193 | */ |
194 | 194 | ||
195 | struct inode *v9fs_get_inode(struct super_block *sb, int mode) | 195 | struct inode *v9fs_get_inode(struct super_block *sb, int mode) |
196 | { | 196 | { |
197 | struct inode *inode; | 197 | struct inode *inode; |
198 | struct v9fs_session_info *v9ses = sb->s_fs_info; | 198 | struct v9fs_session_info *v9ses = sb->s_fs_info; |
199 | 199 | ||
200 | dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); | 200 | dprintk(DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); |
201 | 201 | ||
202 | inode = new_inode(sb); | 202 | inode = new_inode(sb); |
203 | if (inode) { | 203 | if (inode) { |
204 | inode->i_mode = mode; | 204 | inode->i_mode = mode; |
205 | inode->i_uid = current->fsuid; | 205 | inode->i_uid = current->fsuid; |
206 | inode->i_gid = current->fsgid; | 206 | inode->i_gid = current->fsgid; |
207 | inode->i_blksize = sb->s_blocksize; | 207 | inode->i_blksize = sb->s_blocksize; |
208 | inode->i_blocks = 0; | 208 | inode->i_blocks = 0; |
209 | inode->i_rdev = 0; | 209 | inode->i_rdev = 0; |
210 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 210 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
211 | inode->i_mapping->a_ops = &v9fs_addr_operations; | 211 | inode->i_mapping->a_ops = &v9fs_addr_operations; |
212 | 212 | ||
213 | switch (mode & S_IFMT) { | 213 | switch (mode & S_IFMT) { |
214 | case S_IFIFO: | 214 | case S_IFIFO: |
215 | case S_IFBLK: | 215 | case S_IFBLK: |
216 | case S_IFCHR: | 216 | case S_IFCHR: |
217 | case S_IFSOCK: | 217 | case S_IFSOCK: |
218 | if(!v9ses->extended) { | 218 | if(!v9ses->extended) { |
219 | dprintk(DEBUG_ERROR, "special files without extended mode\n"); | 219 | dprintk(DEBUG_ERROR, "special files without extended mode\n"); |
220 | return ERR_PTR(-EINVAL); | 220 | return ERR_PTR(-EINVAL); |
221 | } | 221 | } |
222 | init_special_inode(inode, inode->i_mode, | 222 | init_special_inode(inode, inode->i_mode, |
223 | inode->i_rdev); | 223 | inode->i_rdev); |
224 | break; | 224 | break; |
225 | case S_IFREG: | 225 | case S_IFREG: |
226 | inode->i_op = &v9fs_file_inode_operations; | 226 | inode->i_op = &v9fs_file_inode_operations; |
227 | inode->i_fop = &v9fs_file_operations; | 227 | inode->i_fop = &v9fs_file_operations; |
228 | break; | 228 | break; |
229 | case S_IFLNK: | 229 | case S_IFLNK: |
230 | if(!v9ses->extended) { | 230 | if(!v9ses->extended) { |
231 | dprintk(DEBUG_ERROR, "extended modes used w/o 9P2000.u\n"); | 231 | dprintk(DEBUG_ERROR, "extended modes used w/o 9P2000.u\n"); |
232 | return ERR_PTR(-EINVAL); | 232 | return ERR_PTR(-EINVAL); |
233 | } | 233 | } |
234 | inode->i_op = &v9fs_symlink_inode_operations; | 234 | inode->i_op = &v9fs_symlink_inode_operations; |
235 | break; | 235 | break; |
236 | case S_IFDIR: | 236 | case S_IFDIR: |
237 | inode->i_nlink++; | 237 | inode->i_nlink++; |
238 | if(v9ses->extended) | 238 | if(v9ses->extended) |
239 | inode->i_op = &v9fs_dir_inode_operations_ext; | 239 | inode->i_op = &v9fs_dir_inode_operations_ext; |
240 | else | 240 | else |
241 | inode->i_op = &v9fs_dir_inode_operations; | 241 | inode->i_op = &v9fs_dir_inode_operations; |
242 | inode->i_fop = &v9fs_dir_operations; | 242 | inode->i_fop = &v9fs_dir_operations; |
243 | break; | 243 | break; |
244 | default: | 244 | default: |
245 | dprintk(DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n", | 245 | dprintk(DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n", |
246 | mode, mode & S_IFMT); | 246 | mode, mode & S_IFMT); |
247 | return ERR_PTR(-EINVAL); | 247 | return ERR_PTR(-EINVAL); |
248 | } | 248 | } |
249 | } else { | 249 | } else { |
250 | eprintk(KERN_WARNING, "Problem allocating inode\n"); | 250 | eprintk(KERN_WARNING, "Problem allocating inode\n"); |
251 | return ERR_PTR(-ENOMEM); | 251 | return ERR_PTR(-ENOMEM); |
252 | } | 252 | } |
253 | return inode; | 253 | return inode; |
254 | } | 254 | } |
255 | 255 | ||
256 | static int | 256 | static int |
257 | v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name, u32 perm, | 257 | v9fs_create(struct v9fs_session_info *v9ses, u32 pfid, char *name, u32 perm, |
258 | u8 mode, char *extension, u32 *fidp, struct v9fs_qid *qid, u32 *iounit) | 258 | u8 mode, char *extension, u32 *fidp, struct v9fs_qid *qid, u32 *iounit) |
259 | { | 259 | { |
260 | u32 fid; | 260 | u32 fid; |
261 | int err; | 261 | int err; |
262 | struct v9fs_fcall *fcall; | 262 | struct v9fs_fcall *fcall; |
263 | 263 | ||
264 | fid = v9fs_get_idpool(&v9ses->fidpool); | 264 | fid = v9fs_get_idpool(&v9ses->fidpool); |
265 | if (fid < 0) { | 265 | if (fid < 0) { |
266 | eprintk(KERN_WARNING, "no free fids available\n"); | 266 | eprintk(KERN_WARNING, "no free fids available\n"); |
267 | return -ENOSPC; | 267 | return -ENOSPC; |
268 | } | 268 | } |
269 | 269 | ||
270 | err = v9fs_t_walk(v9ses, pfid, fid, NULL, &fcall); | 270 | err = v9fs_t_walk(v9ses, pfid, fid, NULL, &fcall); |
271 | if (err < 0) { | 271 | if (err < 0) { |
272 | PRINT_FCALL_ERROR("clone error", fcall); | 272 | PRINT_FCALL_ERROR("clone error", fcall); |
273 | goto put_fid; | 273 | if (fcall && fcall->id == RWALK) |
274 | goto clunk_fid; | ||
275 | else | ||
276 | goto put_fid; | ||
274 | } | 277 | } |
275 | kfree(fcall); | 278 | kfree(fcall); |
276 | 279 | ||
277 | err = v9fs_t_create(v9ses, fid, name, perm, mode, extension, &fcall); | 280 | err = v9fs_t_create(v9ses, fid, name, perm, mode, extension, &fcall); |
278 | if (err < 0) { | 281 | if (err < 0) { |
279 | PRINT_FCALL_ERROR("create fails", fcall); | 282 | PRINT_FCALL_ERROR("create fails", fcall); |
280 | goto clunk_fid; | 283 | goto clunk_fid; |
281 | } | 284 | } |
282 | 285 | ||
283 | if (iounit) | 286 | if (iounit) |
284 | *iounit = fcall->params.rcreate.iounit; | 287 | *iounit = fcall->params.rcreate.iounit; |
285 | 288 | ||
286 | if (qid) | 289 | if (qid) |
287 | *qid = fcall->params.rcreate.qid; | 290 | *qid = fcall->params.rcreate.qid; |
288 | 291 | ||
289 | if (fidp) | 292 | if (fidp) |
290 | *fidp = fid; | 293 | *fidp = fid; |
291 | 294 | ||
292 | kfree(fcall); | 295 | kfree(fcall); |
293 | return 0; | 296 | return 0; |
294 | 297 | ||
295 | clunk_fid: | 298 | clunk_fid: |
296 | v9fs_t_clunk(v9ses, fid); | 299 | v9fs_t_clunk(v9ses, fid); |
297 | fid = V9FS_NOFID; | 300 | fid = V9FS_NOFID; |
298 | 301 | ||
299 | put_fid: | 302 | put_fid: |
300 | if (fid >= 0) | 303 | if (fid >= 0) |
301 | v9fs_put_idpool(fid, &v9ses->fidpool); | 304 | v9fs_put_idpool(fid, &v9ses->fidpool); |
302 | 305 | ||
303 | kfree(fcall); | 306 | kfree(fcall); |
304 | return err; | 307 | return err; |
305 | } | 308 | } |
306 | 309 | ||
307 | static struct v9fs_fid* | 310 | static struct v9fs_fid* |
308 | v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry) | 311 | v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry) |
309 | { | 312 | { |
310 | int err; | 313 | int err; |
311 | u32 nfid; | 314 | u32 nfid; |
312 | struct v9fs_fid *ret; | 315 | struct v9fs_fid *ret; |
313 | struct v9fs_fcall *fcall; | 316 | struct v9fs_fcall *fcall; |
314 | 317 | ||
315 | nfid = v9fs_get_idpool(&v9ses->fidpool); | 318 | nfid = v9fs_get_idpool(&v9ses->fidpool); |
316 | if (nfid < 0) { | 319 | if (nfid < 0) { |
317 | eprintk(KERN_WARNING, "no free fids available\n"); | 320 | eprintk(KERN_WARNING, "no free fids available\n"); |
318 | return ERR_PTR(-ENOSPC); | 321 | return ERR_PTR(-ENOSPC); |
319 | } | 322 | } |
320 | 323 | ||
321 | err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name, | 324 | err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name, |
322 | &fcall); | 325 | &fcall); |
323 | 326 | ||
324 | if (err < 0) { | 327 | if (err < 0) { |
328 | if (fcall && fcall->id == RWALK) | ||
329 | goto clunk_fid; | ||
330 | |||
325 | PRINT_FCALL_ERROR("walk error", fcall); | 331 | PRINT_FCALL_ERROR("walk error", fcall); |
326 | v9fs_put_idpool(nfid, &v9ses->fidpool); | 332 | v9fs_put_idpool(nfid, &v9ses->fidpool); |
327 | goto error; | 333 | goto error; |
328 | } | 334 | } |
329 | 335 | ||
330 | kfree(fcall); | 336 | kfree(fcall); |
331 | fcall = NULL; | 337 | fcall = NULL; |
332 | ret = v9fs_fid_create(v9ses, nfid); | 338 | ret = v9fs_fid_create(v9ses, nfid); |
333 | if (!ret) { | 339 | if (!ret) { |
334 | err = -ENOMEM; | 340 | err = -ENOMEM; |
335 | goto clunk_fid; | 341 | goto clunk_fid; |
336 | } | 342 | } |
337 | 343 | ||
338 | err = v9fs_fid_insert(ret, dentry); | 344 | err = v9fs_fid_insert(ret, dentry); |
339 | if (err < 0) { | 345 | if (err < 0) { |
340 | v9fs_fid_destroy(ret); | 346 | v9fs_fid_destroy(ret); |
341 | goto clunk_fid; | 347 | goto clunk_fid; |
342 | } | 348 | } |
343 | 349 | ||
344 | return ret; | 350 | return ret; |
345 | 351 | ||
346 | clunk_fid: | 352 | clunk_fid: |
347 | v9fs_t_clunk(v9ses, nfid); | 353 | v9fs_t_clunk(v9ses, nfid); |
348 | 354 | ||
349 | error: | 355 | error: |
350 | kfree(fcall); | 356 | kfree(fcall); |
351 | return ERR_PTR(err); | 357 | return ERR_PTR(err); |
352 | } | 358 | } |
353 | 359 | ||
354 | static struct inode * | 360 | static struct inode * |
355 | v9fs_inode_from_fid(struct v9fs_session_info *v9ses, u32 fid, | 361 | v9fs_inode_from_fid(struct v9fs_session_info *v9ses, u32 fid, |
356 | struct super_block *sb) | 362 | struct super_block *sb) |
357 | { | 363 | { |
358 | int err, umode; | 364 | int err, umode; |
359 | struct inode *ret; | 365 | struct inode *ret; |
360 | struct v9fs_fcall *fcall; | 366 | struct v9fs_fcall *fcall; |
361 | 367 | ||
362 | ret = NULL; | 368 | ret = NULL; |
363 | err = v9fs_t_stat(v9ses, fid, &fcall); | 369 | err = v9fs_t_stat(v9ses, fid, &fcall); |
364 | if (err) { | 370 | if (err) { |
365 | PRINT_FCALL_ERROR("stat error", fcall); | 371 | PRINT_FCALL_ERROR("stat error", fcall); |
366 | goto error; | 372 | goto error; |
367 | } | 373 | } |
368 | 374 | ||
369 | umode = p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode); | 375 | umode = p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode); |
370 | ret = v9fs_get_inode(sb, umode); | 376 | ret = v9fs_get_inode(sb, umode); |
371 | if (IS_ERR(ret)) { | 377 | if (IS_ERR(ret)) { |
372 | err = PTR_ERR(ret); | 378 | err = PTR_ERR(ret); |
373 | ret = NULL; | 379 | ret = NULL; |
374 | goto error; | 380 | goto error; |
375 | } | 381 | } |
376 | 382 | ||
377 | v9fs_stat2inode(&fcall->params.rstat.stat, ret, sb); | 383 | v9fs_stat2inode(&fcall->params.rstat.stat, ret, sb); |
378 | kfree(fcall); | 384 | kfree(fcall); |
379 | return ret; | 385 | return ret; |
380 | 386 | ||
381 | error: | 387 | error: |
382 | kfree(fcall); | 388 | kfree(fcall); |
383 | if (ret) | 389 | if (ret) |
384 | iput(ret); | 390 | iput(ret); |
385 | 391 | ||
386 | return ERR_PTR(err); | 392 | return ERR_PTR(err); |
387 | } | 393 | } |
388 | 394 | ||
389 | /** | 395 | /** |
390 | * v9fs_remove - helper function to remove files and directories | 396 | * v9fs_remove - helper function to remove files and directories |
391 | * @dir: directory inode that is being deleted | 397 | * @dir: directory inode that is being deleted |
392 | * @file: dentry that is being deleted | 398 | * @file: dentry that is being deleted |
393 | * @rmdir: removing a directory | 399 | * @rmdir: removing a directory |
394 | * | 400 | * |
395 | */ | 401 | */ |
396 | 402 | ||
397 | static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) | 403 | static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir) |
398 | { | 404 | { |
399 | struct v9fs_fcall *fcall = NULL; | 405 | struct v9fs_fcall *fcall = NULL; |
400 | struct super_block *sb = NULL; | 406 | struct super_block *sb = NULL; |
401 | struct v9fs_session_info *v9ses = NULL; | 407 | struct v9fs_session_info *v9ses = NULL; |
402 | struct v9fs_fid *v9fid = NULL; | 408 | struct v9fs_fid *v9fid = NULL; |
403 | struct inode *file_inode = NULL; | 409 | struct inode *file_inode = NULL; |
404 | int fid = -1; | 410 | int fid = -1; |
405 | int result = 0; | 411 | int result = 0; |
406 | 412 | ||
407 | dprintk(DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, | 413 | dprintk(DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file, |
408 | rmdir); | 414 | rmdir); |
409 | 415 | ||
410 | file_inode = file->d_inode; | 416 | file_inode = file->d_inode; |
411 | sb = file_inode->i_sb; | 417 | sb = file_inode->i_sb; |
412 | v9ses = v9fs_inode2v9ses(file_inode); | 418 | v9ses = v9fs_inode2v9ses(file_inode); |
413 | v9fid = v9fs_fid_lookup(file); | 419 | v9fid = v9fs_fid_lookup(file); |
414 | 420 | ||
415 | if (!v9fid) { | 421 | if (!v9fid) { |
416 | dprintk(DEBUG_ERROR, | 422 | dprintk(DEBUG_ERROR, |
417 | "no v9fs_fid\n"); | 423 | "no v9fs_fid\n"); |
418 | return -EBADF; | 424 | return -EBADF; |
419 | } | 425 | } |
420 | 426 | ||
421 | fid = v9fid->fid; | 427 | fid = v9fid->fid; |
422 | if (fid < 0) { | 428 | if (fid < 0) { |
423 | dprintk(DEBUG_ERROR, "inode #%lu, no fid!\n", | 429 | dprintk(DEBUG_ERROR, "inode #%lu, no fid!\n", |
424 | file_inode->i_ino); | 430 | file_inode->i_ino); |
425 | return -EBADF; | 431 | return -EBADF; |
426 | } | 432 | } |
427 | 433 | ||
428 | result = v9fs_t_remove(v9ses, fid, &fcall); | 434 | result = v9fs_t_remove(v9ses, fid, &fcall); |
429 | if (result < 0) { | 435 | if (result < 0) { |
430 | PRINT_FCALL_ERROR("remove fails", fcall); | 436 | PRINT_FCALL_ERROR("remove fails", fcall); |
431 | } else { | 437 | } else { |
432 | v9fs_put_idpool(fid, &v9ses->fidpool); | 438 | v9fs_put_idpool(fid, &v9ses->fidpool); |
433 | v9fs_fid_destroy(v9fid); | 439 | v9fs_fid_destroy(v9fid); |
434 | } | 440 | } |
435 | 441 | ||
436 | kfree(fcall); | 442 | kfree(fcall); |
437 | return result; | 443 | return result; |
438 | } | 444 | } |
439 | 445 | ||
440 | static int | 446 | static int |
441 | v9fs_open_created(struct inode *inode, struct file *file) | 447 | v9fs_open_created(struct inode *inode, struct file *file) |
442 | { | 448 | { |
443 | return 0; | 449 | return 0; |
444 | } | 450 | } |
445 | 451 | ||
446 | /** | 452 | /** |
447 | * v9fs_vfs_create - VFS hook to create files | 453 | * v9fs_vfs_create - VFS hook to create files |
448 | * @inode: directory inode that is being deleted | 454 | * @inode: directory inode that is being deleted |
449 | * @dentry: dentry that is being deleted | 455 | * @dentry: dentry that is being deleted |
450 | * @mode: create permissions | 456 | * @mode: create permissions |
451 | * @nd: path information | 457 | * @nd: path information |
452 | * | 458 | * |
453 | */ | 459 | */ |
454 | 460 | ||
455 | static int | 461 | static int |
456 | v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, | 462 | v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode, |
457 | struct nameidata *nd) | 463 | struct nameidata *nd) |
458 | { | 464 | { |
459 | int err; | 465 | int err; |
460 | u32 fid, perm, iounit; | 466 | u32 fid, perm, iounit; |
461 | int flags; | 467 | int flags; |
462 | struct v9fs_session_info *v9ses; | 468 | struct v9fs_session_info *v9ses; |
463 | struct v9fs_fid *dfid, *vfid, *ffid; | 469 | struct v9fs_fid *dfid, *vfid, *ffid; |
464 | struct inode *inode; | 470 | struct inode *inode; |
465 | struct v9fs_qid qid; | 471 | struct v9fs_qid qid; |
466 | struct file *filp; | 472 | struct file *filp; |
467 | 473 | ||
468 | inode = NULL; | 474 | inode = NULL; |
469 | vfid = NULL; | 475 | vfid = NULL; |
470 | v9ses = v9fs_inode2v9ses(dir); | 476 | v9ses = v9fs_inode2v9ses(dir); |
471 | dfid = v9fs_fid_lookup(dentry->d_parent); | 477 | dfid = v9fs_fid_lookup(dentry->d_parent); |
472 | perm = unixmode2p9mode(v9ses, mode); | 478 | perm = unixmode2p9mode(v9ses, mode); |
473 | 479 | ||
474 | if (nd && nd->flags & LOOKUP_OPEN) | 480 | if (nd && nd->flags & LOOKUP_OPEN) |
475 | flags = nd->intent.open.flags - 1; | 481 | flags = nd->intent.open.flags - 1; |
476 | else | 482 | else |
477 | flags = O_RDWR; | 483 | flags = O_RDWR; |
478 | 484 | ||
479 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, | 485 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, |
480 | perm, v9fs_uflags2omode(flags), NULL, &fid, &qid, &iounit); | 486 | perm, v9fs_uflags2omode(flags), NULL, &fid, &qid, &iounit); |
481 | 487 | ||
482 | if (err) | 488 | if (err) |
483 | goto error; | 489 | goto error; |
484 | 490 | ||
485 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); | 491 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); |
486 | if (IS_ERR(vfid)) { | 492 | if (IS_ERR(vfid)) { |
487 | err = PTR_ERR(vfid); | 493 | err = PTR_ERR(vfid); |
488 | vfid = NULL; | 494 | vfid = NULL; |
489 | goto error; | 495 | goto error; |
490 | } | 496 | } |
491 | 497 | ||
492 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); | 498 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); |
493 | if (IS_ERR(inode)) { | 499 | if (IS_ERR(inode)) { |
494 | err = PTR_ERR(inode); | 500 | err = PTR_ERR(inode); |
495 | inode = NULL; | 501 | inode = NULL; |
496 | goto error; | 502 | goto error; |
497 | } | 503 | } |
498 | 504 | ||
499 | dentry->d_op = &v9fs_dentry_operations; | 505 | dentry->d_op = &v9fs_dentry_operations; |
500 | d_instantiate(dentry, inode); | 506 | d_instantiate(dentry, inode); |
501 | 507 | ||
502 | if (nd && nd->flags & LOOKUP_OPEN) { | 508 | if (nd && nd->flags & LOOKUP_OPEN) { |
503 | ffid = v9fs_fid_create(v9ses, fid); | 509 | ffid = v9fs_fid_create(v9ses, fid); |
504 | if (!ffid) | 510 | if (!ffid) |
505 | return -ENOMEM; | 511 | return -ENOMEM; |
506 | 512 | ||
507 | filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); | 513 | filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created); |
508 | if (IS_ERR(filp)) { | 514 | if (IS_ERR(filp)) { |
509 | v9fs_fid_destroy(ffid); | 515 | v9fs_fid_destroy(ffid); |
510 | return PTR_ERR(filp); | 516 | return PTR_ERR(filp); |
511 | } | 517 | } |
512 | 518 | ||
513 | ffid->rdir_pos = 0; | 519 | ffid->rdir_pos = 0; |
514 | ffid->rdir_fcall = NULL; | 520 | ffid->rdir_fcall = NULL; |
515 | ffid->fidopen = 1; | 521 | ffid->fidopen = 1; |
516 | ffid->iounit = iounit; | 522 | ffid->iounit = iounit; |
517 | ffid->filp = filp; | 523 | ffid->filp = filp; |
518 | filp->private_data = ffid; | 524 | filp->private_data = ffid; |
519 | } | 525 | } |
520 | 526 | ||
521 | return 0; | 527 | return 0; |
522 | 528 | ||
523 | error: | 529 | error: |
524 | if (vfid) | 530 | if (vfid) |
525 | v9fs_fid_destroy(vfid); | 531 | v9fs_fid_destroy(vfid); |
526 | 532 | ||
527 | if (inode) | 533 | if (inode) |
528 | iput(inode); | 534 | iput(inode); |
529 | 535 | ||
530 | return err; | 536 | return err; |
531 | } | 537 | } |
532 | 538 | ||
533 | /** | 539 | /** |
534 | * v9fs_vfs_mkdir - VFS mkdir hook to create a directory | 540 | * v9fs_vfs_mkdir - VFS mkdir hook to create a directory |
535 | * @inode: inode that is being unlinked | 541 | * @inode: inode that is being unlinked |
536 | * @dentry: dentry that is being unlinked | 542 | * @dentry: dentry that is being unlinked |
537 | * @mode: mode for new directory | 543 | * @mode: mode for new directory |
538 | * | 544 | * |
539 | */ | 545 | */ |
540 | 546 | ||
541 | static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | 547 | static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) |
542 | { | 548 | { |
543 | int err; | 549 | int err; |
544 | u32 fid, perm; | 550 | u32 fid, perm; |
545 | struct v9fs_session_info *v9ses; | 551 | struct v9fs_session_info *v9ses; |
546 | struct v9fs_fid *dfid, *vfid; | 552 | struct v9fs_fid *dfid, *vfid; |
547 | struct inode *inode; | 553 | struct inode *inode; |
548 | 554 | ||
549 | inode = NULL; | 555 | inode = NULL; |
550 | vfid = NULL; | 556 | vfid = NULL; |
551 | v9ses = v9fs_inode2v9ses(dir); | 557 | v9ses = v9fs_inode2v9ses(dir); |
552 | dfid = v9fs_fid_lookup(dentry->d_parent); | 558 | dfid = v9fs_fid_lookup(dentry->d_parent); |
553 | perm = unixmode2p9mode(v9ses, mode | S_IFDIR); | 559 | perm = unixmode2p9mode(v9ses, mode | S_IFDIR); |
554 | 560 | ||
555 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, | 561 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, |
556 | perm, V9FS_OREAD, NULL, &fid, NULL, NULL); | 562 | perm, V9FS_OREAD, NULL, &fid, NULL, NULL); |
557 | 563 | ||
558 | if (err) { | 564 | if (err) { |
559 | dprintk(DEBUG_ERROR, "create error %d\n", err); | 565 | dprintk(DEBUG_ERROR, "create error %d\n", err); |
560 | goto error; | 566 | goto error; |
561 | } | 567 | } |
562 | 568 | ||
563 | err = v9fs_t_clunk(v9ses, fid); | 569 | err = v9fs_t_clunk(v9ses, fid); |
564 | if (err) { | 570 | if (err) { |
565 | dprintk(DEBUG_ERROR, "clunk error %d\n", err); | 571 | dprintk(DEBUG_ERROR, "clunk error %d\n", err); |
566 | goto error; | 572 | goto error; |
567 | } | 573 | } |
568 | 574 | ||
569 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); | 575 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); |
570 | if (IS_ERR(vfid)) { | 576 | if (IS_ERR(vfid)) { |
571 | err = PTR_ERR(vfid); | 577 | err = PTR_ERR(vfid); |
572 | vfid = NULL; | 578 | vfid = NULL; |
573 | goto error; | 579 | goto error; |
574 | } | 580 | } |
575 | 581 | ||
576 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); | 582 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); |
577 | if (IS_ERR(inode)) { | 583 | if (IS_ERR(inode)) { |
578 | err = PTR_ERR(inode); | 584 | err = PTR_ERR(inode); |
579 | inode = NULL; | 585 | inode = NULL; |
580 | goto error; | 586 | goto error; |
581 | } | 587 | } |
582 | 588 | ||
583 | dentry->d_op = &v9fs_dentry_operations; | 589 | dentry->d_op = &v9fs_dentry_operations; |
584 | d_instantiate(dentry, inode); | 590 | d_instantiate(dentry, inode); |
585 | return 0; | 591 | return 0; |
586 | 592 | ||
587 | error: | 593 | error: |
588 | if (vfid) | 594 | if (vfid) |
589 | v9fs_fid_destroy(vfid); | 595 | v9fs_fid_destroy(vfid); |
590 | 596 | ||
591 | return err; | 597 | return err; |
592 | } | 598 | } |
593 | 599 | ||
594 | /** | 600 | /** |
595 | * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode | 601 | * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode |
596 | * @dir: inode that is being walked from | 602 | * @dir: inode that is being walked from |
597 | * @dentry: dentry that is being walked to? | 603 | * @dentry: dentry that is being walked to? |
598 | * @nameidata: path data | 604 | * @nameidata: path data |
599 | * | 605 | * |
600 | */ | 606 | */ |
601 | 607 | ||
602 | static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | 608 | static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, |
603 | struct nameidata *nameidata) | 609 | struct nameidata *nameidata) |
604 | { | 610 | { |
605 | struct super_block *sb; | 611 | struct super_block *sb; |
606 | struct v9fs_session_info *v9ses; | 612 | struct v9fs_session_info *v9ses; |
607 | struct v9fs_fid *dirfid; | 613 | struct v9fs_fid *dirfid; |
608 | struct v9fs_fid *fid; | 614 | struct v9fs_fid *fid; |
609 | struct inode *inode; | 615 | struct inode *inode; |
610 | struct v9fs_fcall *fcall = NULL; | 616 | struct v9fs_fcall *fcall = NULL; |
611 | int dirfidnum = -1; | 617 | int dirfidnum = -1; |
612 | int newfid = -1; | 618 | int newfid = -1; |
613 | int result = 0; | 619 | int result = 0; |
614 | 620 | ||
615 | dprintk(DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", | 621 | dprintk(DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n", |
616 | dir, dentry->d_name.name, dentry, nameidata); | 622 | dir, dentry->d_name.name, dentry, nameidata); |
617 | 623 | ||
618 | sb = dir->i_sb; | 624 | sb = dir->i_sb; |
619 | v9ses = v9fs_inode2v9ses(dir); | 625 | v9ses = v9fs_inode2v9ses(dir); |
620 | dentry->d_op = &v9fs_dentry_operations; | 626 | dentry->d_op = &v9fs_dentry_operations; |
621 | dirfid = v9fs_fid_lookup(dentry->d_parent); | 627 | dirfid = v9fs_fid_lookup(dentry->d_parent); |
622 | 628 | ||
623 | if (!dirfid) { | 629 | if (!dirfid) { |
624 | dprintk(DEBUG_ERROR, "no dirfid\n"); | 630 | dprintk(DEBUG_ERROR, "no dirfid\n"); |
625 | return ERR_PTR(-EINVAL); | 631 | return ERR_PTR(-EINVAL); |
626 | } | 632 | } |
627 | 633 | ||
628 | dirfidnum = dirfid->fid; | 634 | dirfidnum = dirfid->fid; |
629 | 635 | ||
630 | if (dirfidnum < 0) { | 636 | if (dirfidnum < 0) { |
631 | dprintk(DEBUG_ERROR, "no dirfid for inode %p, #%lu\n", | 637 | dprintk(DEBUG_ERROR, "no dirfid for inode %p, #%lu\n", |
632 | dir, dir->i_ino); | 638 | dir, dir->i_ino); |
633 | return ERR_PTR(-EBADF); | 639 | return ERR_PTR(-EBADF); |
634 | } | 640 | } |
635 | 641 | ||
636 | newfid = v9fs_get_idpool(&v9ses->fidpool); | 642 | newfid = v9fs_get_idpool(&v9ses->fidpool); |
637 | if (newfid < 0) { | 643 | if (newfid < 0) { |
638 | eprintk(KERN_WARNING, "newfid fails!\n"); | 644 | eprintk(KERN_WARNING, "newfid fails!\n"); |
639 | return ERR_PTR(-ENOSPC); | 645 | return ERR_PTR(-ENOSPC); |
640 | } | 646 | } |
641 | 647 | ||
642 | result = v9fs_t_walk(v9ses, dirfidnum, newfid, | 648 | result = v9fs_t_walk(v9ses, dirfidnum, newfid, |
643 | (char *)dentry->d_name.name, NULL); | 649 | (char *)dentry->d_name.name, &fcall); |
650 | |||
644 | if (result < 0) { | 651 | if (result < 0) { |
645 | v9fs_put_idpool(newfid, &v9ses->fidpool); | 652 | if (fcall && fcall->id == RWALK) |
653 | v9fs_t_clunk(v9ses, newfid); | ||
654 | else | ||
655 | v9fs_put_idpool(newfid, &v9ses->fidpool); | ||
656 | |||
646 | if (result == -ENOENT) { | 657 | if (result == -ENOENT) { |
647 | d_add(dentry, NULL); | 658 | d_add(dentry, NULL); |
648 | dprintk(DEBUG_VFS, | 659 | dprintk(DEBUG_VFS, |
649 | "Return negative dentry %p count %d\n", | 660 | "Return negative dentry %p count %d\n", |
650 | dentry, atomic_read(&dentry->d_count)); | 661 | dentry, atomic_read(&dentry->d_count)); |
662 | kfree(fcall); | ||
651 | return NULL; | 663 | return NULL; |
652 | } | 664 | } |
653 | dprintk(DEBUG_ERROR, "walk error:%d\n", result); | 665 | dprintk(DEBUG_ERROR, "walk error:%d\n", result); |
654 | goto FreeFcall; | 666 | goto FreeFcall; |
655 | } | 667 | } |
668 | kfree(fcall); | ||
656 | 669 | ||
657 | result = v9fs_t_stat(v9ses, newfid, &fcall); | 670 | result = v9fs_t_stat(v9ses, newfid, &fcall); |
658 | if (result < 0) { | 671 | if (result < 0) { |
659 | dprintk(DEBUG_ERROR, "stat error\n"); | 672 | dprintk(DEBUG_ERROR, "stat error\n"); |
660 | goto FreeFcall; | 673 | goto FreeFcall; |
661 | } | 674 | } |
662 | 675 | ||
663 | inode = v9fs_get_inode(sb, p9mode2unixmode(v9ses, | 676 | inode = v9fs_get_inode(sb, p9mode2unixmode(v9ses, |
664 | fcall->params.rstat.stat.mode)); | 677 | fcall->params.rstat.stat.mode)); |
665 | 678 | ||
666 | if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) { | 679 | if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) { |
667 | eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n", | 680 | eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n", |
668 | PTR_ERR(inode)); | 681 | PTR_ERR(inode)); |
669 | 682 | ||
670 | result = -ENOSPC; | 683 | result = -ENOSPC; |
671 | goto FreeFcall; | 684 | goto FreeFcall; |
672 | } | 685 | } |
673 | 686 | ||
674 | inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid); | 687 | inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid); |
675 | 688 | ||
676 | fid = v9fs_fid_create(v9ses, newfid); | 689 | fid = v9fs_fid_create(v9ses, newfid); |
677 | if (fid == NULL) { | 690 | if (fid == NULL) { |
678 | dprintk(DEBUG_ERROR, "couldn't insert\n"); | 691 | dprintk(DEBUG_ERROR, "couldn't insert\n"); |
679 | result = -ENOMEM; | 692 | result = -ENOMEM; |
680 | goto FreeFcall; | 693 | goto FreeFcall; |
681 | } | 694 | } |
682 | 695 | ||
683 | result = v9fs_fid_insert(fid, dentry); | 696 | result = v9fs_fid_insert(fid, dentry); |
684 | if (result < 0) | 697 | if (result < 0) |
685 | goto FreeFcall; | 698 | goto FreeFcall; |
686 | 699 | ||
687 | fid->qid = fcall->params.rstat.stat.qid; | 700 | fid->qid = fcall->params.rstat.stat.qid; |
688 | v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb); | 701 | v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb); |
689 | 702 | ||
690 | d_add(dentry, inode); | 703 | d_add(dentry, inode); |
691 | kfree(fcall); | 704 | kfree(fcall); |
692 | 705 | ||
693 | return NULL; | 706 | return NULL; |
694 | 707 | ||
695 | FreeFcall: | 708 | FreeFcall: |
696 | kfree(fcall); | 709 | kfree(fcall); |
697 | return ERR_PTR(result); | 710 | return ERR_PTR(result); |
698 | } | 711 | } |
699 | 712 | ||
700 | /** | 713 | /** |
701 | * v9fs_vfs_unlink - VFS unlink hook to delete an inode | 714 | * v9fs_vfs_unlink - VFS unlink hook to delete an inode |
702 | * @i: inode that is being unlinked | 715 | * @i: inode that is being unlinked |
703 | * @d: dentry that is being unlinked | 716 | * @d: dentry that is being unlinked |
704 | * | 717 | * |
705 | */ | 718 | */ |
706 | 719 | ||
707 | static int v9fs_vfs_unlink(struct inode *i, struct dentry *d) | 720 | static int v9fs_vfs_unlink(struct inode *i, struct dentry *d) |
708 | { | 721 | { |
709 | return v9fs_remove(i, d, 0); | 722 | return v9fs_remove(i, d, 0); |
710 | } | 723 | } |
711 | 724 | ||
712 | /** | 725 | /** |
713 | * v9fs_vfs_rmdir - VFS unlink hook to delete a directory | 726 | * v9fs_vfs_rmdir - VFS unlink hook to delete a directory |
714 | * @i: inode that is being unlinked | 727 | * @i: inode that is being unlinked |
715 | * @d: dentry that is being unlinked | 728 | * @d: dentry that is being unlinked |
716 | * | 729 | * |
717 | */ | 730 | */ |
718 | 731 | ||
719 | static int v9fs_vfs_rmdir(struct inode *i, struct dentry *d) | 732 | static int v9fs_vfs_rmdir(struct inode *i, struct dentry *d) |
720 | { | 733 | { |
721 | return v9fs_remove(i, d, 1); | 734 | return v9fs_remove(i, d, 1); |
722 | } | 735 | } |
723 | 736 | ||
724 | /** | 737 | /** |
725 | * v9fs_vfs_rename - VFS hook to rename an inode | 738 | * v9fs_vfs_rename - VFS hook to rename an inode |
726 | * @old_dir: old dir inode | 739 | * @old_dir: old dir inode |
727 | * @old_dentry: old dentry | 740 | * @old_dentry: old dentry |
728 | * @new_dir: new dir inode | 741 | * @new_dir: new dir inode |
729 | * @new_dentry: new dentry | 742 | * @new_dentry: new dentry |
730 | * | 743 | * |
731 | */ | 744 | */ |
732 | 745 | ||
733 | static int | 746 | static int |
734 | v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, | 747 | v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry, |
735 | struct inode *new_dir, struct dentry *new_dentry) | 748 | struct inode *new_dir, struct dentry *new_dentry) |
736 | { | 749 | { |
737 | struct inode *old_inode = old_dentry->d_inode; | 750 | struct inode *old_inode = old_dentry->d_inode; |
738 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode); | 751 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(old_inode); |
739 | struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); | 752 | struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); |
740 | struct v9fs_fid *olddirfid = | 753 | struct v9fs_fid *olddirfid = |
741 | v9fs_fid_lookup(old_dentry->d_parent); | 754 | v9fs_fid_lookup(old_dentry->d_parent); |
742 | struct v9fs_fid *newdirfid = | 755 | struct v9fs_fid *newdirfid = |
743 | v9fs_fid_lookup(new_dentry->d_parent); | 756 | v9fs_fid_lookup(new_dentry->d_parent); |
744 | struct v9fs_wstat wstat; | 757 | struct v9fs_wstat wstat; |
745 | struct v9fs_fcall *fcall = NULL; | 758 | struct v9fs_fcall *fcall = NULL; |
746 | int fid = -1; | 759 | int fid = -1; |
747 | int olddirfidnum = -1; | 760 | int olddirfidnum = -1; |
748 | int newdirfidnum = -1; | 761 | int newdirfidnum = -1; |
749 | int retval = 0; | 762 | int retval = 0; |
750 | 763 | ||
751 | dprintk(DEBUG_VFS, "\n"); | 764 | dprintk(DEBUG_VFS, "\n"); |
752 | 765 | ||
753 | if ((!oldfid) || (!olddirfid) || (!newdirfid)) { | 766 | if ((!oldfid) || (!olddirfid) || (!newdirfid)) { |
754 | dprintk(DEBUG_ERROR, "problem with arguments\n"); | 767 | dprintk(DEBUG_ERROR, "problem with arguments\n"); |
755 | return -EBADF; | 768 | return -EBADF; |
756 | } | 769 | } |
757 | 770 | ||
758 | /* 9P can only handle file rename in the same directory */ | 771 | /* 9P can only handle file rename in the same directory */ |
759 | if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) { | 772 | if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) { |
760 | dprintk(DEBUG_ERROR, "old dir and new dir are different\n"); | 773 | dprintk(DEBUG_ERROR, "old dir and new dir are different\n"); |
761 | retval = -EPERM; | 774 | retval = -EPERM; |
762 | goto FreeFcallnBail; | 775 | goto FreeFcallnBail; |
763 | } | 776 | } |
764 | 777 | ||
765 | fid = oldfid->fid; | 778 | fid = oldfid->fid; |
766 | olddirfidnum = olddirfid->fid; | 779 | olddirfidnum = olddirfid->fid; |
767 | newdirfidnum = newdirfid->fid; | 780 | newdirfidnum = newdirfid->fid; |
768 | 781 | ||
769 | if (fid < 0) { | 782 | if (fid < 0) { |
770 | dprintk(DEBUG_ERROR, "no fid for old file #%lu\n", | 783 | dprintk(DEBUG_ERROR, "no fid for old file #%lu\n", |
771 | old_inode->i_ino); | 784 | old_inode->i_ino); |
772 | retval = -EBADF; | 785 | retval = -EBADF; |
773 | goto FreeFcallnBail; | 786 | goto FreeFcallnBail; |
774 | } | 787 | } |
775 | 788 | ||
776 | v9fs_blank_wstat(&wstat); | 789 | v9fs_blank_wstat(&wstat); |
777 | wstat.muid = v9ses->name; | 790 | wstat.muid = v9ses->name; |
778 | wstat.name = (char *) new_dentry->d_name.name; | 791 | wstat.name = (char *) new_dentry->d_name.name; |
779 | 792 | ||
780 | retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall); | 793 | retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall); |
781 | 794 | ||
782 | FreeFcallnBail: | 795 | FreeFcallnBail: |
783 | if (retval < 0) | 796 | if (retval < 0) |
784 | PRINT_FCALL_ERROR("wstat error", fcall); | 797 | PRINT_FCALL_ERROR("wstat error", fcall); |
785 | 798 | ||
786 | kfree(fcall); | 799 | kfree(fcall); |
787 | return retval; | 800 | return retval; |
788 | } | 801 | } |
789 | 802 | ||
790 | /** | 803 | /** |
791 | * v9fs_vfs_getattr - retrieve file metadata | 804 | * v9fs_vfs_getattr - retrieve file metadata |
792 | * @mnt - mount information | 805 | * @mnt - mount information |
793 | * @dentry - file to get attributes on | 806 | * @dentry - file to get attributes on |
794 | * @stat - metadata structure to populate | 807 | * @stat - metadata structure to populate |
795 | * | 808 | * |
796 | */ | 809 | */ |
797 | 810 | ||
798 | static int | 811 | static int |
799 | v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | 812 | v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, |
800 | struct kstat *stat) | 813 | struct kstat *stat) |
801 | { | 814 | { |
802 | struct v9fs_fcall *fcall = NULL; | 815 | struct v9fs_fcall *fcall = NULL; |
803 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 816 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); |
804 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); | 817 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); |
805 | int err = -EPERM; | 818 | int err = -EPERM; |
806 | 819 | ||
807 | dprintk(DEBUG_VFS, "dentry: %p\n", dentry); | 820 | dprintk(DEBUG_VFS, "dentry: %p\n", dentry); |
808 | if (!fid) { | 821 | if (!fid) { |
809 | dprintk(DEBUG_ERROR, | 822 | dprintk(DEBUG_ERROR, |
810 | "couldn't find fid associated with dentry\n"); | 823 | "couldn't find fid associated with dentry\n"); |
811 | return -EBADF; | 824 | return -EBADF; |
812 | } | 825 | } |
813 | 826 | ||
814 | err = v9fs_t_stat(v9ses, fid->fid, &fcall); | 827 | err = v9fs_t_stat(v9ses, fid->fid, &fcall); |
815 | 828 | ||
816 | if (err < 0) | 829 | if (err < 0) |
817 | dprintk(DEBUG_ERROR, "stat error\n"); | 830 | dprintk(DEBUG_ERROR, "stat error\n"); |
818 | else { | 831 | else { |
819 | v9fs_stat2inode(&fcall->params.rstat.stat, dentry->d_inode, | 832 | v9fs_stat2inode(&fcall->params.rstat.stat, dentry->d_inode, |
820 | dentry->d_inode->i_sb); | 833 | dentry->d_inode->i_sb); |
821 | generic_fillattr(dentry->d_inode, stat); | 834 | generic_fillattr(dentry->d_inode, stat); |
822 | } | 835 | } |
823 | 836 | ||
824 | kfree(fcall); | 837 | kfree(fcall); |
825 | return err; | 838 | return err; |
826 | } | 839 | } |
827 | 840 | ||
828 | /** | 841 | /** |
829 | * v9fs_vfs_setattr - set file metadata | 842 | * v9fs_vfs_setattr - set file metadata |
830 | * @dentry: file whose metadata to set | 843 | * @dentry: file whose metadata to set |
831 | * @iattr: metadata assignment structure | 844 | * @iattr: metadata assignment structure |
832 | * | 845 | * |
833 | */ | 846 | */ |
834 | 847 | ||
835 | static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) | 848 | static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr) |
836 | { | 849 | { |
837 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 850 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); |
838 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); | 851 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); |
839 | struct v9fs_fcall *fcall = NULL; | 852 | struct v9fs_fcall *fcall = NULL; |
840 | struct v9fs_wstat wstat; | 853 | struct v9fs_wstat wstat; |
841 | int res = -EPERM; | 854 | int res = -EPERM; |
842 | 855 | ||
843 | dprintk(DEBUG_VFS, "\n"); | 856 | dprintk(DEBUG_VFS, "\n"); |
844 | 857 | ||
845 | if (!fid) { | 858 | if (!fid) { |
846 | dprintk(DEBUG_ERROR, | 859 | dprintk(DEBUG_ERROR, |
847 | "Couldn't find fid associated with dentry\n"); | 860 | "Couldn't find fid associated with dentry\n"); |
848 | return -EBADF; | 861 | return -EBADF; |
849 | } | 862 | } |
850 | 863 | ||
851 | v9fs_blank_wstat(&wstat); | 864 | v9fs_blank_wstat(&wstat); |
852 | if (iattr->ia_valid & ATTR_MODE) | 865 | if (iattr->ia_valid & ATTR_MODE) |
853 | wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode); | 866 | wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode); |
854 | 867 | ||
855 | if (iattr->ia_valid & ATTR_MTIME) | 868 | if (iattr->ia_valid & ATTR_MTIME) |
856 | wstat.mtime = iattr->ia_mtime.tv_sec; | 869 | wstat.mtime = iattr->ia_mtime.tv_sec; |
857 | 870 | ||
858 | if (iattr->ia_valid & ATTR_ATIME) | 871 | if (iattr->ia_valid & ATTR_ATIME) |
859 | wstat.atime = iattr->ia_atime.tv_sec; | 872 | wstat.atime = iattr->ia_atime.tv_sec; |
860 | 873 | ||
861 | if (iattr->ia_valid & ATTR_SIZE) | 874 | if (iattr->ia_valid & ATTR_SIZE) |
862 | wstat.length = iattr->ia_size; | 875 | wstat.length = iattr->ia_size; |
863 | 876 | ||
864 | if (v9ses->extended) { | 877 | if (v9ses->extended) { |
865 | if (iattr->ia_valid & ATTR_UID) | 878 | if (iattr->ia_valid & ATTR_UID) |
866 | wstat.n_uid = iattr->ia_uid; | 879 | wstat.n_uid = iattr->ia_uid; |
867 | 880 | ||
868 | if (iattr->ia_valid & ATTR_GID) | 881 | if (iattr->ia_valid & ATTR_GID) |
869 | wstat.n_gid = iattr->ia_gid; | 882 | wstat.n_gid = iattr->ia_gid; |
870 | } | 883 | } |
871 | 884 | ||
872 | res = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall); | 885 | res = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall); |
873 | 886 | ||
874 | if (res < 0) | 887 | if (res < 0) |
875 | PRINT_FCALL_ERROR("wstat error", fcall); | 888 | PRINT_FCALL_ERROR("wstat error", fcall); |
876 | 889 | ||
877 | kfree(fcall); | 890 | kfree(fcall); |
878 | if (res >= 0) | 891 | if (res >= 0) |
879 | res = inode_setattr(dentry->d_inode, iattr); | 892 | res = inode_setattr(dentry->d_inode, iattr); |
880 | 893 | ||
881 | return res; | 894 | return res; |
882 | } | 895 | } |
883 | 896 | ||
884 | /** | 897 | /** |
885 | * v9fs_stat2inode - populate an inode structure with mistat info | 898 | * v9fs_stat2inode - populate an inode structure with mistat info |
886 | * @stat: Plan 9 metadata (mistat) structure | 899 | * @stat: Plan 9 metadata (mistat) structure |
887 | * @inode: inode to populate | 900 | * @inode: inode to populate |
888 | * @sb: superblock of filesystem | 901 | * @sb: superblock of filesystem |
889 | * | 902 | * |
890 | */ | 903 | */ |
891 | 904 | ||
892 | void | 905 | void |
893 | v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode, | 906 | v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode, |
894 | struct super_block *sb) | 907 | struct super_block *sb) |
895 | { | 908 | { |
896 | int n; | 909 | int n; |
897 | char ext[32]; | 910 | char ext[32]; |
898 | struct v9fs_session_info *v9ses = sb->s_fs_info; | 911 | struct v9fs_session_info *v9ses = sb->s_fs_info; |
899 | 912 | ||
900 | inode->i_nlink = 1; | 913 | inode->i_nlink = 1; |
901 | 914 | ||
902 | inode->i_atime.tv_sec = stat->atime; | 915 | inode->i_atime.tv_sec = stat->atime; |
903 | inode->i_mtime.tv_sec = stat->mtime; | 916 | inode->i_mtime.tv_sec = stat->mtime; |
904 | inode->i_ctime.tv_sec = stat->mtime; | 917 | inode->i_ctime.tv_sec = stat->mtime; |
905 | 918 | ||
906 | inode->i_uid = v9ses->uid; | 919 | inode->i_uid = v9ses->uid; |
907 | inode->i_gid = v9ses->gid; | 920 | inode->i_gid = v9ses->gid; |
908 | 921 | ||
909 | if (v9ses->extended) { | 922 | if (v9ses->extended) { |
910 | inode->i_uid = stat->n_uid; | 923 | inode->i_uid = stat->n_uid; |
911 | inode->i_gid = stat->n_gid; | 924 | inode->i_gid = stat->n_gid; |
912 | } | 925 | } |
913 | 926 | ||
914 | inode->i_mode = p9mode2unixmode(v9ses, stat->mode); | 927 | inode->i_mode = p9mode2unixmode(v9ses, stat->mode); |
915 | if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { | 928 | if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { |
916 | char type = 0; | 929 | char type = 0; |
917 | int major = -1; | 930 | int major = -1; |
918 | int minor = -1; | 931 | int minor = -1; |
919 | 932 | ||
920 | n = stat->extension.len; | 933 | n = stat->extension.len; |
921 | if (n > sizeof(ext)-1) | 934 | if (n > sizeof(ext)-1) |
922 | n = sizeof(ext)-1; | 935 | n = sizeof(ext)-1; |
923 | memmove(ext, stat->extension.str, n); | 936 | memmove(ext, stat->extension.str, n); |
924 | ext[n] = 0; | 937 | ext[n] = 0; |
925 | sscanf(ext, "%c %u %u", &type, &major, &minor); | 938 | sscanf(ext, "%c %u %u", &type, &major, &minor); |
926 | switch (type) { | 939 | switch (type) { |
927 | case 'c': | 940 | case 'c': |
928 | inode->i_mode &= ~S_IFBLK; | 941 | inode->i_mode &= ~S_IFBLK; |
929 | inode->i_mode |= S_IFCHR; | 942 | inode->i_mode |= S_IFCHR; |
930 | break; | 943 | break; |
931 | case 'b': | 944 | case 'b': |
932 | break; | 945 | break; |
933 | default: | 946 | default: |
934 | dprintk(DEBUG_ERROR, "Unknown special type %c (%.*s)\n", | 947 | dprintk(DEBUG_ERROR, "Unknown special type %c (%.*s)\n", |
935 | type, stat->extension.len, stat->extension.str); | 948 | type, stat->extension.len, stat->extension.str); |
936 | }; | 949 | }; |
937 | inode->i_rdev = MKDEV(major, minor); | 950 | inode->i_rdev = MKDEV(major, minor); |
938 | } else | 951 | } else |
939 | inode->i_rdev = 0; | 952 | inode->i_rdev = 0; |
940 | 953 | ||
941 | inode->i_size = stat->length; | 954 | inode->i_size = stat->length; |
942 | 955 | ||
943 | inode->i_blksize = sb->s_blocksize; | 956 | inode->i_blksize = sb->s_blocksize; |
944 | inode->i_blocks = | 957 | inode->i_blocks = |
945 | (inode->i_size + inode->i_blksize - 1) >> sb->s_blocksize_bits; | 958 | (inode->i_size + inode->i_blksize - 1) >> sb->s_blocksize_bits; |
946 | } | 959 | } |
947 | 960 | ||
948 | /** | 961 | /** |
949 | * v9fs_qid2ino - convert qid into inode number | 962 | * v9fs_qid2ino - convert qid into inode number |
950 | * @qid: qid to hash | 963 | * @qid: qid to hash |
951 | * | 964 | * |
952 | * BUG: potential for inode number collisions? | 965 | * BUG: potential for inode number collisions? |
953 | */ | 966 | */ |
954 | 967 | ||
955 | ino_t v9fs_qid2ino(struct v9fs_qid *qid) | 968 | ino_t v9fs_qid2ino(struct v9fs_qid *qid) |
956 | { | 969 | { |
957 | u64 path = qid->path + 2; | 970 | u64 path = qid->path + 2; |
958 | ino_t i = 0; | 971 | ino_t i = 0; |
959 | 972 | ||
960 | if (sizeof(ino_t) == sizeof(path)) | 973 | if (sizeof(ino_t) == sizeof(path)) |
961 | memcpy(&i, &path, sizeof(ino_t)); | 974 | memcpy(&i, &path, sizeof(ino_t)); |
962 | else | 975 | else |
963 | i = (ino_t) (path ^ (path >> 32)); | 976 | i = (ino_t) (path ^ (path >> 32)); |
964 | 977 | ||
965 | return i; | 978 | return i; |
966 | } | 979 | } |
967 | 980 | ||
968 | /** | 981 | /** |
969 | * v9fs_readlink - read a symlink's location (internal version) | 982 | * v9fs_readlink - read a symlink's location (internal version) |
970 | * @dentry: dentry for symlink | 983 | * @dentry: dentry for symlink |
971 | * @buffer: buffer to load symlink location into | 984 | * @buffer: buffer to load symlink location into |
972 | * @buflen: length of buffer | 985 | * @buflen: length of buffer |
973 | * | 986 | * |
974 | */ | 987 | */ |
975 | 988 | ||
976 | static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) | 989 | static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen) |
977 | { | 990 | { |
978 | int retval = -EPERM; | 991 | int retval = -EPERM; |
979 | 992 | ||
980 | struct v9fs_fcall *fcall = NULL; | 993 | struct v9fs_fcall *fcall = NULL; |
981 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); | 994 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); |
982 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); | 995 | struct v9fs_fid *fid = v9fs_fid_lookup(dentry); |
983 | 996 | ||
984 | if (!fid) { | 997 | if (!fid) { |
985 | dprintk(DEBUG_ERROR, "could not resolve fid from dentry\n"); | 998 | dprintk(DEBUG_ERROR, "could not resolve fid from dentry\n"); |
986 | retval = -EBADF; | 999 | retval = -EBADF; |
987 | goto FreeFcall; | 1000 | goto FreeFcall; |
988 | } | 1001 | } |
989 | 1002 | ||
990 | if (!v9ses->extended) { | 1003 | if (!v9ses->extended) { |
991 | retval = -EBADF; | 1004 | retval = -EBADF; |
992 | dprintk(DEBUG_ERROR, "not extended\n"); | 1005 | dprintk(DEBUG_ERROR, "not extended\n"); |
993 | goto FreeFcall; | 1006 | goto FreeFcall; |
994 | } | 1007 | } |
995 | 1008 | ||
996 | dprintk(DEBUG_VFS, " %s\n", dentry->d_name.name); | 1009 | dprintk(DEBUG_VFS, " %s\n", dentry->d_name.name); |
997 | retval = v9fs_t_stat(v9ses, fid->fid, &fcall); | 1010 | retval = v9fs_t_stat(v9ses, fid->fid, &fcall); |
998 | 1011 | ||
999 | if (retval < 0) { | 1012 | if (retval < 0) { |
1000 | dprintk(DEBUG_ERROR, "stat error\n"); | 1013 | dprintk(DEBUG_ERROR, "stat error\n"); |
1001 | goto FreeFcall; | 1014 | goto FreeFcall; |
1002 | } | 1015 | } |
1003 | 1016 | ||
1004 | if (!fcall) | 1017 | if (!fcall) |
1005 | return -EIO; | 1018 | return -EIO; |
1006 | 1019 | ||
1007 | if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) { | 1020 | if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) { |
1008 | retval = -EINVAL; | 1021 | retval = -EINVAL; |
1009 | goto FreeFcall; | 1022 | goto FreeFcall; |
1010 | } | 1023 | } |
1011 | 1024 | ||
1012 | /* copy extension buffer into buffer */ | 1025 | /* copy extension buffer into buffer */ |
1013 | if (fcall->params.rstat.stat.extension.len < buflen) | 1026 | if (fcall->params.rstat.stat.extension.len < buflen) |
1014 | buflen = fcall->params.rstat.stat.extension.len + 1; | 1027 | buflen = fcall->params.rstat.stat.extension.len + 1; |
1015 | 1028 | ||
1016 | memmove(buffer, fcall->params.rstat.stat.extension.str, buflen - 1); | 1029 | memmove(buffer, fcall->params.rstat.stat.extension.str, buflen - 1); |
1017 | buffer[buflen-1] = 0; | 1030 | buffer[buflen-1] = 0; |
1018 | 1031 | ||
1019 | dprintk(DEBUG_ERROR, "%s -> %.*s (%s)\n", dentry->d_name.name, fcall->params.rstat.stat.extension.len, | 1032 | dprintk(DEBUG_ERROR, "%s -> %.*s (%s)\n", dentry->d_name.name, fcall->params.rstat.stat.extension.len, |
1020 | fcall->params.rstat.stat.extension.str, buffer); | 1033 | fcall->params.rstat.stat.extension.str, buffer); |
1021 | retval = buflen; | 1034 | retval = buflen; |
1022 | 1035 | ||
1023 | FreeFcall: | 1036 | FreeFcall: |
1024 | kfree(fcall); | 1037 | kfree(fcall); |
1025 | 1038 | ||
1026 | return retval; | 1039 | return retval; |
1027 | } | 1040 | } |
1028 | 1041 | ||
1029 | /** | 1042 | /** |
1030 | * v9fs_vfs_readlink - read a symlink's location | 1043 | * v9fs_vfs_readlink - read a symlink's location |
1031 | * @dentry: dentry for symlink | 1044 | * @dentry: dentry for symlink |
1032 | * @buf: buffer to load symlink location into | 1045 | * @buf: buffer to load symlink location into |
1033 | * @buflen: length of buffer | 1046 | * @buflen: length of buffer |
1034 | * | 1047 | * |
1035 | */ | 1048 | */ |
1036 | 1049 | ||
1037 | static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer, | 1050 | static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer, |
1038 | int buflen) | 1051 | int buflen) |
1039 | { | 1052 | { |
1040 | int retval; | 1053 | int retval; |
1041 | int ret; | 1054 | int ret; |
1042 | char *link = __getname(); | 1055 | char *link = __getname(); |
1043 | 1056 | ||
1044 | if (buflen > PATH_MAX) | 1057 | if (buflen > PATH_MAX) |
1045 | buflen = PATH_MAX; | 1058 | buflen = PATH_MAX; |
1046 | 1059 | ||
1047 | dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); | 1060 | dprintk(DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry); |
1048 | 1061 | ||
1049 | retval = v9fs_readlink(dentry, link, buflen); | 1062 | retval = v9fs_readlink(dentry, link, buflen); |
1050 | 1063 | ||
1051 | if (retval > 0) { | 1064 | if (retval > 0) { |
1052 | if ((ret = copy_to_user(buffer, link, retval)) != 0) { | 1065 | if ((ret = copy_to_user(buffer, link, retval)) != 0) { |
1053 | dprintk(DEBUG_ERROR, "problem copying to user: %d\n", | 1066 | dprintk(DEBUG_ERROR, "problem copying to user: %d\n", |
1054 | ret); | 1067 | ret); |
1055 | retval = ret; | 1068 | retval = ret; |
1056 | } | 1069 | } |
1057 | } | 1070 | } |
1058 | 1071 | ||
1059 | __putname(link); | 1072 | __putname(link); |
1060 | return retval; | 1073 | return retval; |
1061 | } | 1074 | } |
1062 | 1075 | ||
1063 | /** | 1076 | /** |
1064 | * v9fs_vfs_follow_link - follow a symlink path | 1077 | * v9fs_vfs_follow_link - follow a symlink path |
1065 | * @dentry: dentry for symlink | 1078 | * @dentry: dentry for symlink |
1066 | * @nd: nameidata | 1079 | * @nd: nameidata |
1067 | * | 1080 | * |
1068 | */ | 1081 | */ |
1069 | 1082 | ||
1070 | static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd) | 1083 | static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd) |
1071 | { | 1084 | { |
1072 | int len = 0; | 1085 | int len = 0; |
1073 | char *link = __getname(); | 1086 | char *link = __getname(); |
1074 | 1087 | ||
1075 | dprintk(DEBUG_VFS, "%s n", dentry->d_name.name); | 1088 | dprintk(DEBUG_VFS, "%s n", dentry->d_name.name); |
1076 | 1089 | ||
1077 | if (!link) | 1090 | if (!link) |
1078 | link = ERR_PTR(-ENOMEM); | 1091 | link = ERR_PTR(-ENOMEM); |
1079 | else { | 1092 | else { |
1080 | len = v9fs_readlink(dentry, link, PATH_MAX); | 1093 | len = v9fs_readlink(dentry, link, PATH_MAX); |
1081 | 1094 | ||
1082 | if (len < 0) { | 1095 | if (len < 0) { |
1083 | __putname(link); | 1096 | __putname(link); |
1084 | link = ERR_PTR(len); | 1097 | link = ERR_PTR(len); |
1085 | } else | 1098 | } else |
1086 | link[len] = 0; | 1099 | link[len] = 0; |
1087 | } | 1100 | } |
1088 | nd_set_link(nd, link); | 1101 | nd_set_link(nd, link); |
1089 | 1102 | ||
1090 | return NULL; | 1103 | return NULL; |
1091 | } | 1104 | } |
1092 | 1105 | ||
1093 | /** | 1106 | /** |
1094 | * v9fs_vfs_put_link - release a symlink path | 1107 | * v9fs_vfs_put_link - release a symlink path |
1095 | * @dentry: dentry for symlink | 1108 | * @dentry: dentry for symlink |
1096 | * @nd: nameidata | 1109 | * @nd: nameidata |
1097 | * | 1110 | * |
1098 | */ | 1111 | */ |
1099 | 1112 | ||
1100 | static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) | 1113 | static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) |
1101 | { | 1114 | { |
1102 | char *s = nd_get_link(nd); | 1115 | char *s = nd_get_link(nd); |
1103 | 1116 | ||
1104 | dprintk(DEBUG_VFS, " %s %s\n", dentry->d_name.name, s); | 1117 | dprintk(DEBUG_VFS, " %s %s\n", dentry->d_name.name, s); |
1105 | if (!IS_ERR(s)) | 1118 | if (!IS_ERR(s)) |
1106 | __putname(s); | 1119 | __putname(s); |
1107 | } | 1120 | } |
1108 | 1121 | ||
1109 | static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, | 1122 | static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry, |
1110 | int mode, const char *extension) | 1123 | int mode, const char *extension) |
1111 | { | 1124 | { |
1112 | int err; | 1125 | int err; |
1113 | u32 fid, perm; | 1126 | u32 fid, perm; |
1114 | struct v9fs_session_info *v9ses; | 1127 | struct v9fs_session_info *v9ses; |
1115 | struct v9fs_fid *dfid, *vfid; | 1128 | struct v9fs_fid *dfid, *vfid; |
1116 | struct inode *inode; | 1129 | struct inode *inode; |
1117 | 1130 | ||
1118 | inode = NULL; | 1131 | inode = NULL; |
1119 | vfid = NULL; | 1132 | vfid = NULL; |
1120 | v9ses = v9fs_inode2v9ses(dir); | 1133 | v9ses = v9fs_inode2v9ses(dir); |
1121 | dfid = v9fs_fid_lookup(dentry->d_parent); | 1134 | dfid = v9fs_fid_lookup(dentry->d_parent); |
1122 | perm = unixmode2p9mode(v9ses, mode); | 1135 | perm = unixmode2p9mode(v9ses, mode); |
1123 | 1136 | ||
1124 | if (!v9ses->extended) { | 1137 | if (!v9ses->extended) { |
1125 | dprintk(DEBUG_ERROR, "not extended\n"); | 1138 | dprintk(DEBUG_ERROR, "not extended\n"); |
1126 | return -EPERM; | 1139 | return -EPERM; |
1127 | } | 1140 | } |
1128 | 1141 | ||
1129 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, | 1142 | err = v9fs_create(v9ses, dfid->fid, (char *) dentry->d_name.name, |
1130 | perm, V9FS_OREAD, (char *) extension, &fid, NULL, NULL); | 1143 | perm, V9FS_OREAD, (char *) extension, &fid, NULL, NULL); |
1131 | 1144 | ||
1132 | if (err) | 1145 | if (err) |
1133 | goto error; | 1146 | goto error; |
1134 | 1147 | ||
1135 | err = v9fs_t_clunk(v9ses, fid); | 1148 | err = v9fs_t_clunk(v9ses, fid); |
1136 | if (err) | 1149 | if (err) |
1137 | goto error; | 1150 | goto error; |
1138 | 1151 | ||
1139 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); | 1152 | vfid = v9fs_clone_walk(v9ses, dfid->fid, dentry); |
1140 | if (IS_ERR(vfid)) { | 1153 | if (IS_ERR(vfid)) { |
1141 | err = PTR_ERR(vfid); | 1154 | err = PTR_ERR(vfid); |
1142 | vfid = NULL; | 1155 | vfid = NULL; |
1143 | goto error; | 1156 | goto error; |
1144 | } | 1157 | } |
1145 | 1158 | ||
1146 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); | 1159 | inode = v9fs_inode_from_fid(v9ses, vfid->fid, dir->i_sb); |
1147 | if (IS_ERR(inode)) { | 1160 | if (IS_ERR(inode)) { |
1148 | err = PTR_ERR(inode); | 1161 | err = PTR_ERR(inode); |
1149 | inode = NULL; | 1162 | inode = NULL; |
1150 | goto error; | 1163 | goto error; |
1151 | } | 1164 | } |
1152 | 1165 | ||
1153 | dentry->d_op = &v9fs_dentry_operations; | 1166 | dentry->d_op = &v9fs_dentry_operations; |
1154 | d_instantiate(dentry, inode); | 1167 | d_instantiate(dentry, inode); |
1155 | return 0; | 1168 | return 0; |
1156 | 1169 | ||
1157 | error: | 1170 | error: |
1158 | if (vfid) | 1171 | if (vfid) |
1159 | v9fs_fid_destroy(vfid); | 1172 | v9fs_fid_destroy(vfid); |
1160 | 1173 | ||
1161 | if (inode) | 1174 | if (inode) |
1162 | iput(inode); | 1175 | iput(inode); |
1163 | 1176 | ||
1164 | return err; | 1177 | return err; |
1165 | 1178 | ||
1166 | } | 1179 | } |
1167 | 1180 | ||
1168 | /** | 1181 | /** |
1169 | * v9fs_vfs_symlink - helper function to create symlinks | 1182 | * v9fs_vfs_symlink - helper function to create symlinks |
1170 | * @dir: directory inode containing symlink | 1183 | * @dir: directory inode containing symlink |
1171 | * @dentry: dentry for symlink | 1184 | * @dentry: dentry for symlink |
1172 | * @symname: symlink data | 1185 | * @symname: symlink data |
1173 | * | 1186 | * |
1174 | * See 9P2000.u RFC for more information | 1187 | * See 9P2000.u RFC for more information |
1175 | * | 1188 | * |
1176 | */ | 1189 | */ |
1177 | 1190 | ||
1178 | static int | 1191 | static int |
1179 | v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) | 1192 | v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname) |
1180 | { | 1193 | { |
1181 | dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, | 1194 | dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, |
1182 | symname); | 1195 | symname); |
1183 | 1196 | ||
1184 | return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname); | 1197 | return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname); |
1185 | } | 1198 | } |
1186 | 1199 | ||
1187 | /** | 1200 | /** |
1188 | * v9fs_vfs_link - create a hardlink | 1201 | * v9fs_vfs_link - create a hardlink |
1189 | * @old_dentry: dentry for file to link to | 1202 | * @old_dentry: dentry for file to link to |
1190 | * @dir: inode destination for new link | 1203 | * @dir: inode destination for new link |
1191 | * @dentry: dentry for link | 1204 | * @dentry: dentry for link |
1192 | * | 1205 | * |
1193 | */ | 1206 | */ |
1194 | 1207 | ||
1195 | /* XXX - lots of code dup'd from symlink and creates, | 1208 | /* XXX - lots of code dup'd from symlink and creates, |
1196 | * figure out a better reuse strategy | 1209 | * figure out a better reuse strategy |
1197 | */ | 1210 | */ |
1198 | 1211 | ||
1199 | static int | 1212 | static int |
1200 | v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, | 1213 | v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir, |
1201 | struct dentry *dentry) | 1214 | struct dentry *dentry) |
1202 | { | 1215 | { |
1203 | int retval; | 1216 | int retval; |
1204 | struct v9fs_fid *oldfid; | 1217 | struct v9fs_fid *oldfid; |
1205 | char *name; | 1218 | char *name; |
1206 | 1219 | ||
1207 | dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, | 1220 | dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, |
1208 | old_dentry->d_name.name); | 1221 | old_dentry->d_name.name); |
1209 | 1222 | ||
1210 | oldfid = v9fs_fid_lookup(old_dentry); | 1223 | oldfid = v9fs_fid_lookup(old_dentry); |
1211 | if (!oldfid) { | 1224 | if (!oldfid) { |
1212 | dprintk(DEBUG_ERROR, "can't find oldfid\n"); | 1225 | dprintk(DEBUG_ERROR, "can't find oldfid\n"); |
1213 | return -EPERM; | 1226 | return -EPERM; |
1214 | } | 1227 | } |
1215 | 1228 | ||
1216 | name = __getname(); | 1229 | name = __getname(); |
1217 | sprintf(name, "%d\n", oldfid->fid); | 1230 | sprintf(name, "%d\n", oldfid->fid); |
1218 | retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name); | 1231 | retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name); |
1219 | __putname(name); | 1232 | __putname(name); |
1220 | 1233 | ||
1221 | return retval; | 1234 | return retval; |
1222 | } | 1235 | } |
1223 | 1236 | ||
1224 | /** | 1237 | /** |
1225 | * v9fs_vfs_mknod - create a special file | 1238 | * v9fs_vfs_mknod - create a special file |
1226 | * @dir: inode destination for new link | 1239 | * @dir: inode destination for new link |
1227 | * @dentry: dentry for file | 1240 | * @dentry: dentry for file |
1228 | * @mode: mode for creation | 1241 | * @mode: mode for creation |
1229 | * @dev_t: device associated with special file | 1242 | * @dev_t: device associated with special file |
1230 | * | 1243 | * |
1231 | */ | 1244 | */ |
1232 | 1245 | ||
1233 | static int | 1246 | static int |
1234 | v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | 1247 | v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) |
1235 | { | 1248 | { |
1236 | int retval; | 1249 | int retval; |
1237 | char *name; | 1250 | char *name; |
1238 | 1251 | ||
1239 | dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, | 1252 | dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, |
1240 | dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); | 1253 | dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); |
1241 | 1254 | ||
1242 | if (!new_valid_dev(rdev)) | 1255 | if (!new_valid_dev(rdev)) |
1243 | return -EINVAL; | 1256 | return -EINVAL; |
1244 | 1257 | ||
1245 | name = __getname(); | 1258 | name = __getname(); |
1246 | if (!name) | 1259 | if (!name) |
1247 | return -ENOMEM; | 1260 | return -ENOMEM; |
1248 | /* build extension */ | 1261 | /* build extension */ |
1249 | if (S_ISBLK(mode)) | 1262 | if (S_ISBLK(mode)) |
1250 | sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev)); | 1263 | sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev)); |
1251 | else if (S_ISCHR(mode)) | 1264 | else if (S_ISCHR(mode)) |
1252 | sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev)); | 1265 | sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev)); |
1253 | else if (S_ISFIFO(mode)) | 1266 | else if (S_ISFIFO(mode)) |
1254 | *name = 0; | 1267 | *name = 0; |
1255 | else { | 1268 | else { |
1256 | __putname(name); | 1269 | __putname(name); |
1257 | return -EINVAL; | 1270 | return -EINVAL; |
1258 | } | 1271 | } |
1259 | 1272 | ||
1260 | retval = v9fs_vfs_mkspecial(dir, dentry, mode, name); | 1273 | retval = v9fs_vfs_mkspecial(dir, dentry, mode, name); |
1261 | __putname(name); | 1274 | __putname(name); |
1262 | 1275 | ||
1263 | return retval; | 1276 | return retval; |
1264 | } | 1277 | } |
1265 | 1278 | ||
1266 | static struct inode_operations v9fs_dir_inode_operations_ext = { | 1279 | static struct inode_operations v9fs_dir_inode_operations_ext = { |
1267 | .create = v9fs_vfs_create, | 1280 | .create = v9fs_vfs_create, |
1268 | .lookup = v9fs_vfs_lookup, | 1281 | .lookup = v9fs_vfs_lookup, |
1269 | .symlink = v9fs_vfs_symlink, | 1282 | .symlink = v9fs_vfs_symlink, |
1270 | .link = v9fs_vfs_link, | 1283 | .link = v9fs_vfs_link, |
1271 | .unlink = v9fs_vfs_unlink, | 1284 | .unlink = v9fs_vfs_unlink, |
1272 | .mkdir = v9fs_vfs_mkdir, | 1285 | .mkdir = v9fs_vfs_mkdir, |
1273 | .rmdir = v9fs_vfs_rmdir, | 1286 | .rmdir = v9fs_vfs_rmdir, |
1274 | .mknod = v9fs_vfs_mknod, | 1287 | .mknod = v9fs_vfs_mknod, |
1275 | .rename = v9fs_vfs_rename, | 1288 | .rename = v9fs_vfs_rename, |
1276 | .readlink = v9fs_vfs_readlink, | 1289 | .readlink = v9fs_vfs_readlink, |
1277 | .getattr = v9fs_vfs_getattr, | 1290 | .getattr = v9fs_vfs_getattr, |
1278 | .setattr = v9fs_vfs_setattr, | 1291 | .setattr = v9fs_vfs_setattr, |
1279 | }; | 1292 | }; |
1280 | 1293 | ||
1281 | static struct inode_operations v9fs_dir_inode_operations = { | 1294 | static struct inode_operations v9fs_dir_inode_operations = { |
1282 | .create = v9fs_vfs_create, | 1295 | .create = v9fs_vfs_create, |
1283 | .lookup = v9fs_vfs_lookup, | 1296 | .lookup = v9fs_vfs_lookup, |
1284 | .unlink = v9fs_vfs_unlink, | 1297 | .unlink = v9fs_vfs_unlink, |
1285 | .mkdir = v9fs_vfs_mkdir, | 1298 | .mkdir = v9fs_vfs_mkdir, |
1286 | .rmdir = v9fs_vfs_rmdir, | 1299 | .rmdir = v9fs_vfs_rmdir, |
1287 | .mknod = v9fs_vfs_mknod, | 1300 | .mknod = v9fs_vfs_mknod, |
1288 | .rename = v9fs_vfs_rename, | 1301 | .rename = v9fs_vfs_rename, |
1289 | .getattr = v9fs_vfs_getattr, | 1302 | .getattr = v9fs_vfs_getattr, |
1290 | .setattr = v9fs_vfs_setattr, | 1303 | .setattr = v9fs_vfs_setattr, |
1291 | }; | 1304 | }; |
1292 | 1305 | ||
1293 | static struct inode_operations v9fs_file_inode_operations = { | 1306 | static struct inode_operations v9fs_file_inode_operations = { |
1294 | .getattr = v9fs_vfs_getattr, | 1307 | .getattr = v9fs_vfs_getattr, |
1295 | .setattr = v9fs_vfs_setattr, | 1308 | .setattr = v9fs_vfs_setattr, |
1296 | }; | 1309 | }; |
1297 | 1310 | ||
1298 | static struct inode_operations v9fs_symlink_inode_operations = { | 1311 | static struct inode_operations v9fs_symlink_inode_operations = { |
1299 | .readlink = v9fs_vfs_readlink, | 1312 | .readlink = v9fs_vfs_readlink, |
1300 | .follow_link = v9fs_vfs_follow_link, | 1313 | .follow_link = v9fs_vfs_follow_link, |
1301 | .put_link = v9fs_vfs_put_link, | 1314 | .put_link = v9fs_vfs_put_link, |
1302 | .getattr = v9fs_vfs_getattr, | 1315 | .getattr = v9fs_vfs_getattr, |
1303 | .setattr = v9fs_vfs_setattr, | 1316 | .setattr = v9fs_vfs_setattr, |
1304 | }; | 1317 | }; |
1305 | 1318 |