diff options
Diffstat (limited to 'fs/9p/vfs_file.c')
-rw-r--r-- | fs/9p/vfs_file.c | 202 |
1 files changed, 61 insertions, 141 deletions
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 1f8ae7d580ab..bbc3cc63854f 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c | |||
@@ -53,30 +53,36 @@ | |||
53 | int v9fs_file_open(struct inode *inode, struct file *file) | 53 | int v9fs_file_open(struct inode *inode, struct file *file) |
54 | { | 54 | { |
55 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 55 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); |
56 | struct v9fs_fid *v9fid = v9fs_fid_lookup(file->f_dentry, FID_WALK); | 56 | struct v9fs_fid *v9fid, *fid; |
57 | struct v9fs_fid *v9newfid = NULL; | ||
58 | struct v9fs_fcall *fcall = NULL; | 57 | struct v9fs_fcall *fcall = NULL; |
59 | int open_mode = 0; | 58 | int open_mode = 0; |
60 | unsigned int iounit = 0; | 59 | unsigned int iounit = 0; |
61 | int newfid = -1; | 60 | int newfid = -1; |
62 | long result = -1; | 61 | long result = -1; |
63 | 62 | ||
64 | dprintk(DEBUG_VFS, "inode: %p file: %p v9fid= %p\n", inode, file, | 63 | dprintk(DEBUG_VFS, "inode: %p file: %p \n", inode, file); |
65 | v9fid); | 64 | |
65 | v9fid = v9fs_fid_get_created(file->f_dentry); | ||
66 | if (!v9fid) | ||
67 | v9fid = v9fs_fid_lookup(file->f_dentry); | ||
66 | 68 | ||
67 | if (!v9fid) { | 69 | if (!v9fid) { |
68 | struct dentry *dentry = file->f_dentry; | ||
69 | dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); | 70 | dprintk(DEBUG_ERROR, "Couldn't resolve fid from dentry\n"); |
71 | return -EBADF; | ||
72 | } | ||
70 | 73 | ||
71 | /* XXX - some duplication from lookup, generalize later */ | 74 | if (!v9fid->fidcreate) { |
72 | /* basically vfs_lookup is too heavy weight */ | 75 | fid = kmalloc(sizeof(struct v9fs_fid), GFP_KERNEL); |
73 | v9fid = v9fs_fid_lookup(file->f_dentry, FID_OP); | 76 | if (fid == NULL) { |
74 | if (!v9fid) | 77 | dprintk(DEBUG_ERROR, "Out of Memory\n"); |
75 | return -EBADF; | 78 | return -ENOMEM; |
79 | } | ||
76 | 80 | ||
77 | v9fid = v9fs_fid_lookup(dentry->d_parent, FID_WALK); | 81 | fid->fidopen = 0; |
78 | if (!v9fid) | 82 | fid->fidcreate = 0; |
79 | return -EBADF; | 83 | fid->fidclunked = 0; |
84 | fid->iounit = 0; | ||
85 | fid->v9ses = v9ses; | ||
80 | 86 | ||
81 | newfid = v9fs_get_idpool(&v9ses->fidpool); | 87 | newfid = v9fs_get_idpool(&v9ses->fidpool); |
82 | if (newfid < 0) { | 88 | if (newfid < 0) { |
@@ -85,58 +91,16 @@ int v9fs_file_open(struct inode *inode, struct file *file) | |||
85 | } | 91 | } |
86 | 92 | ||
87 | result = | 93 | result = |
88 | v9fs_t_walk(v9ses, v9fid->fid, newfid, | 94 | v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, NULL); |
89 | (char *)file->f_dentry->d_name.name, NULL); | 95 | |
90 | if (result < 0) { | 96 | if (result < 0) { |
91 | v9fs_put_idpool(newfid, &v9ses->fidpool); | 97 | v9fs_put_idpool(newfid, &v9ses->fidpool); |
92 | dprintk(DEBUG_ERROR, "rewalk didn't work\n"); | 98 | dprintk(DEBUG_ERROR, "rewalk didn't work\n"); |
93 | return -EBADF; | 99 | return -EBADF; |
94 | } | 100 | } |
95 | 101 | ||
96 | v9fid = v9fs_fid_create(dentry); | 102 | fid->fid = newfid; |
97 | if (v9fid == NULL) { | 103 | v9fid = fid; |
98 | dprintk(DEBUG_ERROR, "couldn't insert\n"); | ||
99 | return -ENOMEM; | ||
100 | } | ||
101 | v9fid->fid = newfid; | ||
102 | } | ||
103 | |||
104 | if (v9fid->fidcreate) { | ||
105 | /* create case */ | ||
106 | newfid = v9fid->fid; | ||
107 | iounit = v9fid->iounit; | ||
108 | v9fid->fidcreate = 0; | ||
109 | } else { | ||
110 | if (!S_ISDIR(inode->i_mode)) | ||
111 | newfid = v9fid->fid; | ||
112 | else { | ||
113 | newfid = v9fs_get_idpool(&v9ses->fidpool); | ||
114 | if (newfid < 0) { | ||
115 | eprintk(KERN_WARNING, "allocation failed\n"); | ||
116 | return -ENOSPC; | ||
117 | } | ||
118 | /* This would be a somewhat critical clone */ | ||
119 | result = | ||
120 | v9fs_t_walk(v9ses, v9fid->fid, newfid, NULL, | ||
121 | &fcall); | ||
122 | if (result < 0) { | ||
123 | dprintk(DEBUG_ERROR, "clone error: %s\n", | ||
124 | FCALL_ERROR(fcall)); | ||
125 | kfree(fcall); | ||
126 | return result; | ||
127 | } | ||
128 | |||
129 | v9newfid = v9fs_fid_create(file->f_dentry); | ||
130 | v9newfid->fid = newfid; | ||
131 | v9newfid->qid = v9fid->qid; | ||
132 | v9newfid->iounit = v9fid->iounit; | ||
133 | v9newfid->fidopen = 0; | ||
134 | v9newfid->fidclunked = 0; | ||
135 | v9newfid->v9ses = v9ses; | ||
136 | v9fid = v9newfid; | ||
137 | kfree(fcall); | ||
138 | } | ||
139 | |||
140 | /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ | 104 | /* TODO: do special things for O_EXCL, O_NOFOLLOW, O_SYNC */ |
141 | /* translate open mode appropriately */ | 105 | /* translate open mode appropriately */ |
142 | open_mode = file->f_flags & 0x3; | 106 | open_mode = file->f_flags & 0x3; |
@@ -163,9 +127,13 @@ int v9fs_file_open(struct inode *inode, struct file *file) | |||
163 | 127 | ||
164 | iounit = fcall->params.ropen.iounit; | 128 | iounit = fcall->params.ropen.iounit; |
165 | kfree(fcall); | 129 | kfree(fcall); |
130 | } else { | ||
131 | /* create case */ | ||
132 | newfid = v9fid->fid; | ||
133 | iounit = v9fid->iounit; | ||
134 | v9fid->fidcreate = 0; | ||
166 | } | 135 | } |
167 | 136 | ||
168 | |||
169 | file->private_data = v9fid; | 137 | file->private_data = v9fid; |
170 | 138 | ||
171 | v9fid->rdir_pos = 0; | 139 | v9fid->rdir_pos = 0; |
@@ -207,16 +175,16 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) | |||
207 | } | 175 | } |
208 | 176 | ||
209 | /** | 177 | /** |
210 | * v9fs_read - read from a file (internal) | 178 | * v9fs_file_read - read from a file |
211 | * @filep: file pointer to read | 179 | * @filep: file pointer to read |
212 | * @data: data buffer to read data into | 180 | * @data: data buffer to read data into |
213 | * @count: size of buffer | 181 | * @count: size of buffer |
214 | * @offset: offset at which to read data | 182 | * @offset: offset at which to read data |
215 | * | 183 | * |
216 | */ | 184 | */ |
217 | |||
218 | static ssize_t | 185 | static ssize_t |
219 | v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset) | 186 | v9fs_file_read(struct file *filp, char __user * data, size_t count, |
187 | loff_t * offset) | ||
220 | { | 188 | { |
221 | struct inode *inode = filp->f_dentry->d_inode; | 189 | struct inode *inode = filp->f_dentry->d_inode; |
222 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 190 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); |
@@ -226,6 +194,7 @@ v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset) | |||
226 | int rsize = 0; | 194 | int rsize = 0; |
227 | int result = 0; | 195 | int result = 0; |
228 | int total = 0; | 196 | int total = 0; |
197 | int n; | ||
229 | 198 | ||
230 | dprintk(DEBUG_VFS, "\n"); | 199 | dprintk(DEBUG_VFS, "\n"); |
231 | 200 | ||
@@ -248,10 +217,15 @@ v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset) | |||
248 | } else | 217 | } else |
249 | *offset += result; | 218 | *offset += result; |
250 | 219 | ||
251 | /* XXX - extra copy */ | 220 | n = copy_to_user(data, fcall->params.rread.data, result); |
252 | memcpy(buffer, fcall->params.rread.data, result); | 221 | if (n) { |
222 | dprintk(DEBUG_ERROR, "Problem copying to user %d\n", n); | ||
223 | kfree(fcall); | ||
224 | return -EFAULT; | ||
225 | } | ||
226 | |||
253 | count -= result; | 227 | count -= result; |
254 | buffer += result; | 228 | data += result; |
255 | total += result; | 229 | total += result; |
256 | 230 | ||
257 | kfree(fcall); | 231 | kfree(fcall); |
@@ -264,42 +238,7 @@ v9fs_read(struct file *filp, char *buffer, size_t count, loff_t * offset) | |||
264 | } | 238 | } |
265 | 239 | ||
266 | /** | 240 | /** |
267 | * v9fs_file_read - read from a file | 241 | * v9fs_file_write - write to a file |
268 | * @filep: file pointer to read | ||
269 | * @data: data buffer to read data into | ||
270 | * @count: size of buffer | ||
271 | * @offset: offset at which to read data | ||
272 | * | ||
273 | */ | ||
274 | |||
275 | static ssize_t | ||
276 | v9fs_file_read(struct file *filp, char __user * data, size_t count, | ||
277 | loff_t * offset) | ||
278 | { | ||
279 | int retval = -1; | ||
280 | int ret = 0; | ||
281 | char *buffer; | ||
282 | |||
283 | buffer = kmalloc(count, GFP_KERNEL); | ||
284 | if (!buffer) | ||
285 | return -ENOMEM; | ||
286 | |||
287 | retval = v9fs_read(filp, buffer, count, offset); | ||
288 | if (retval > 0) { | ||
289 | if ((ret = copy_to_user(data, buffer, retval)) != 0) { | ||
290 | dprintk(DEBUG_ERROR, "Problem copying to user %d\n", | ||
291 | ret); | ||
292 | retval = ret; | ||
293 | } | ||
294 | } | ||
295 | |||
296 | kfree(buffer); | ||
297 | |||
298 | return retval; | ||
299 | } | ||
300 | |||
301 | /** | ||
302 | * v9fs_write - write to a file | ||
303 | * @filep: file pointer to write | 242 | * @filep: file pointer to write |
304 | * @data: data buffer to write data from | 243 | * @data: data buffer to write data from |
305 | * @count: size of buffer | 244 | * @count: size of buffer |
@@ -308,7 +247,8 @@ v9fs_file_read(struct file *filp, char __user * data, size_t count, | |||
308 | */ | 247 | */ |
309 | 248 | ||
310 | static ssize_t | 249 | static ssize_t |
311 | v9fs_write(struct file *filp, char *buffer, size_t count, loff_t * offset) | 250 | v9fs_file_write(struct file *filp, const char __user * data, |
251 | size_t count, loff_t * offset) | ||
312 | { | 252 | { |
313 | struct inode *inode = filp->f_dentry->d_inode; | 253 | struct inode *inode = filp->f_dentry->d_inode; |
314 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 254 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); |
@@ -318,30 +258,42 @@ v9fs_write(struct file *filp, char *buffer, size_t count, loff_t * offset) | |||
318 | int result = -EIO; | 258 | int result = -EIO; |
319 | int rsize = 0; | 259 | int rsize = 0; |
320 | int total = 0; | 260 | int total = 0; |
261 | char *buf; | ||
321 | 262 | ||
322 | dprintk(DEBUG_VFS, "data %p count %d offset %x\n", buffer, (int)count, | 263 | dprintk(DEBUG_VFS, "data %p count %d offset %x\n", data, (int)count, |
323 | (int)*offset); | 264 | (int)*offset); |
324 | rsize = v9ses->maxdata - V9FS_IOHDRSZ; | 265 | rsize = v9ses->maxdata - V9FS_IOHDRSZ; |
325 | if (v9fid->iounit != 0 && rsize > v9fid->iounit) | 266 | if (v9fid->iounit != 0 && rsize > v9fid->iounit) |
326 | rsize = v9fid->iounit; | 267 | rsize = v9fid->iounit; |
327 | 268 | ||
328 | dump_data(buffer, count); | 269 | buf = kmalloc(v9ses->maxdata - V9FS_IOHDRSZ, GFP_KERNEL); |
270 | if (!buf) | ||
271 | return -ENOMEM; | ||
329 | 272 | ||
330 | do { | 273 | do { |
331 | if (count < rsize) | 274 | if (count < rsize) |
332 | rsize = count; | 275 | rsize = count; |
333 | 276 | ||
334 | result = | 277 | result = copy_from_user(buf, data, rsize); |
335 | v9fs_t_write(v9ses, fid, *offset, rsize, buffer, &fcall); | 278 | if (result) { |
279 | dprintk(DEBUG_ERROR, "Problem copying from user\n"); | ||
280 | kfree(buf); | ||
281 | return -EFAULT; | ||
282 | } | ||
283 | |||
284 | dump_data(buf, rsize); | ||
285 | result = v9fs_t_write(v9ses, fid, *offset, rsize, buf, &fcall); | ||
336 | if (result < 0) { | 286 | if (result < 0) { |
337 | eprintk(KERN_ERR, "error while writing: %s(%d)\n", | 287 | eprintk(KERN_ERR, "error while writing: %s(%d)\n", |
338 | FCALL_ERROR(fcall), result); | 288 | FCALL_ERROR(fcall), result); |
339 | kfree(fcall); | 289 | kfree(fcall); |
290 | kfree(buf); | ||
340 | return result; | 291 | return result; |
341 | } else | 292 | } else |
342 | *offset += result; | 293 | *offset += result; |
343 | 294 | ||
344 | kfree(fcall); | 295 | kfree(fcall); |
296 | fcall = NULL; | ||
345 | 297 | ||
346 | if (result != rsize) { | 298 | if (result != rsize) { |
347 | eprintk(KERN_ERR, | 299 | eprintk(KERN_ERR, |
@@ -351,46 +303,14 @@ v9fs_write(struct file *filp, char *buffer, size_t count, loff_t * offset) | |||
351 | } | 303 | } |
352 | 304 | ||
353 | count -= result; | 305 | count -= result; |
354 | buffer += result; | 306 | data += result; |
355 | total += result; | 307 | total += result; |
356 | } while (count); | 308 | } while (count); |
357 | 309 | ||
310 | kfree(buf); | ||
358 | return total; | 311 | return total; |
359 | } | 312 | } |
360 | 313 | ||
361 | /** | ||
362 | * v9fs_file_write - write to a file | ||
363 | * @filep: file pointer to write | ||
364 | * @data: data buffer to write data from | ||
365 | * @count: size of buffer | ||
366 | * @offset: offset at which to write data | ||
367 | * | ||
368 | */ | ||
369 | |||
370 | static ssize_t | ||
371 | v9fs_file_write(struct file *filp, const char __user * data, | ||
372 | size_t count, loff_t * offset) | ||
373 | { | ||
374 | int ret = -1; | ||
375 | char *buffer; | ||
376 | |||
377 | buffer = kmalloc(count, GFP_KERNEL); | ||
378 | if (buffer == NULL) | ||
379 | return -ENOMEM; | ||
380 | |||
381 | ret = copy_from_user(buffer, data, count); | ||
382 | if (ret) { | ||
383 | dprintk(DEBUG_ERROR, "Problem copying from user\n"); | ||
384 | ret = -EFAULT; | ||
385 | } else { | ||
386 | ret = v9fs_write(filp, buffer, count, offset); | ||
387 | } | ||
388 | |||
389 | kfree(buffer); | ||
390 | |||
391 | return ret; | ||
392 | } | ||
393 | |||
394 | struct file_operations v9fs_file_operations = { | 314 | struct file_operations v9fs_file_operations = { |
395 | .llseek = generic_file_llseek, | 315 | .llseek = generic_file_llseek, |
396 | .read = v9fs_file_read, | 316 | .read = v9fs_file_read, |