Commit 41e5a6ac80c600e1f8bda0a4871f0b797e097d78

Authored by Latchesar Ionkov
Committed by Linus Torvalds
1 parent 343f1fe6f2

[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

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(&current->sighand->siglock, flags); 940 spin_lock_irqsave(&current->sighand->siglock, flags);
895 recalc_sigpending(); 941 recalc_sigpending();
896 spin_unlock_irqrestore(&current->sighand->siglock, flags); 942 spin_unlock_irqrestore(&current->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 */
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);
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 };
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