diff options
Diffstat (limited to 'fs/9p/vfs_inode.c')
-rw-r--r-- | fs/9p/vfs_inode.c | 187 |
1 files changed, 123 insertions, 64 deletions
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 81f8bbf12f9f..5947628aefef 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include "v9fs.h" | 40 | #include "v9fs.h" |
41 | #include "v9fs_vfs.h" | 41 | #include "v9fs_vfs.h" |
42 | #include "fid.h" | 42 | #include "fid.h" |
43 | #include "cache.h" | ||
43 | 44 | ||
44 | static const struct inode_operations v9fs_dir_inode_operations; | 45 | static const struct inode_operations v9fs_dir_inode_operations; |
45 | static const struct inode_operations v9fs_dir_inode_operations_ext; | 46 | static const struct inode_operations v9fs_dir_inode_operations_ext; |
@@ -171,7 +172,6 @@ int v9fs_uflags2omode(int uflags, int extended) | |||
171 | 172 | ||
172 | /** | 173 | /** |
173 | * v9fs_blank_wstat - helper function to setup a 9P stat structure | 174 | * v9fs_blank_wstat - helper function to setup a 9P stat structure |
174 | * @v9ses: 9P session info (for determining extended mode) | ||
175 | * @wstat: structure to initialize | 175 | * @wstat: structure to initialize |
176 | * | 176 | * |
177 | */ | 177 | */ |
@@ -198,6 +198,39 @@ v9fs_blank_wstat(struct p9_wstat *wstat) | |||
198 | wstat->extension = NULL; | 198 | wstat->extension = NULL; |
199 | } | 199 | } |
200 | 200 | ||
201 | #ifdef CONFIG_9P_FSCACHE | ||
202 | /** | ||
203 | * v9fs_alloc_inode - helper function to allocate an inode | ||
204 | * This callback is executed before setting up the inode so that we | ||
205 | * can associate a vcookie with each inode. | ||
206 | * | ||
207 | */ | ||
208 | |||
209 | struct inode *v9fs_alloc_inode(struct super_block *sb) | ||
210 | { | ||
211 | struct v9fs_cookie *vcookie; | ||
212 | vcookie = (struct v9fs_cookie *)kmem_cache_alloc(vcookie_cache, | ||
213 | GFP_KERNEL); | ||
214 | if (!vcookie) | ||
215 | return NULL; | ||
216 | |||
217 | vcookie->fscache = NULL; | ||
218 | vcookie->qid = NULL; | ||
219 | spin_lock_init(&vcookie->lock); | ||
220 | return &vcookie->inode; | ||
221 | } | ||
222 | |||
223 | /** | ||
224 | * v9fs_destroy_inode - destroy an inode | ||
225 | * | ||
226 | */ | ||
227 | |||
228 | void v9fs_destroy_inode(struct inode *inode) | ||
229 | { | ||
230 | kmem_cache_free(vcookie_cache, v9fs_inode2cookie(inode)); | ||
231 | } | ||
232 | #endif | ||
233 | |||
201 | /** | 234 | /** |
202 | * v9fs_get_inode - helper function to setup an inode | 235 | * v9fs_get_inode - helper function to setup an inode |
203 | * @sb: superblock | 236 | * @sb: superblock |
@@ -207,65 +240,72 @@ v9fs_blank_wstat(struct p9_wstat *wstat) | |||
207 | 240 | ||
208 | struct inode *v9fs_get_inode(struct super_block *sb, int mode) | 241 | struct inode *v9fs_get_inode(struct super_block *sb, int mode) |
209 | { | 242 | { |
243 | int err; | ||
210 | struct inode *inode; | 244 | struct inode *inode; |
211 | struct v9fs_session_info *v9ses = sb->s_fs_info; | 245 | struct v9fs_session_info *v9ses = sb->s_fs_info; |
212 | 246 | ||
213 | P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); | 247 | P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode); |
214 | 248 | ||
215 | inode = new_inode(sb); | 249 | inode = new_inode(sb); |
216 | if (inode) { | 250 | if (!inode) { |
217 | inode->i_mode = mode; | ||
218 | inode->i_uid = current_fsuid(); | ||
219 | inode->i_gid = current_fsgid(); | ||
220 | inode->i_blocks = 0; | ||
221 | inode->i_rdev = 0; | ||
222 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
223 | inode->i_mapping->a_ops = &v9fs_addr_operations; | ||
224 | |||
225 | switch (mode & S_IFMT) { | ||
226 | case S_IFIFO: | ||
227 | case S_IFBLK: | ||
228 | case S_IFCHR: | ||
229 | case S_IFSOCK: | ||
230 | if (!v9fs_extended(v9ses)) { | ||
231 | P9_DPRINTK(P9_DEBUG_ERROR, | ||
232 | "special files without extended mode\n"); | ||
233 | return ERR_PTR(-EINVAL); | ||
234 | } | ||
235 | init_special_inode(inode, inode->i_mode, | ||
236 | inode->i_rdev); | ||
237 | break; | ||
238 | case S_IFREG: | ||
239 | inode->i_op = &v9fs_file_inode_operations; | ||
240 | inode->i_fop = &v9fs_file_operations; | ||
241 | break; | ||
242 | case S_IFLNK: | ||
243 | if (!v9fs_extended(v9ses)) { | ||
244 | P9_DPRINTK(P9_DEBUG_ERROR, | ||
245 | "extended modes used w/o 9P2000.u\n"); | ||
246 | return ERR_PTR(-EINVAL); | ||
247 | } | ||
248 | inode->i_op = &v9fs_symlink_inode_operations; | ||
249 | break; | ||
250 | case S_IFDIR: | ||
251 | inc_nlink(inode); | ||
252 | if (v9fs_extended(v9ses)) | ||
253 | inode->i_op = &v9fs_dir_inode_operations_ext; | ||
254 | else | ||
255 | inode->i_op = &v9fs_dir_inode_operations; | ||
256 | inode->i_fop = &v9fs_dir_operations; | ||
257 | break; | ||
258 | default: | ||
259 | P9_DPRINTK(P9_DEBUG_ERROR, | ||
260 | "BAD mode 0x%x S_IFMT 0x%x\n", | ||
261 | mode, mode & S_IFMT); | ||
262 | return ERR_PTR(-EINVAL); | ||
263 | } | ||
264 | } else { | ||
265 | P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n"); | 251 | P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n"); |
266 | return ERR_PTR(-ENOMEM); | 252 | return ERR_PTR(-ENOMEM); |
267 | } | 253 | } |
254 | |||
255 | inode->i_mode = mode; | ||
256 | inode->i_uid = current_fsuid(); | ||
257 | inode->i_gid = current_fsgid(); | ||
258 | inode->i_blocks = 0; | ||
259 | inode->i_rdev = 0; | ||
260 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | ||
261 | inode->i_mapping->a_ops = &v9fs_addr_operations; | ||
262 | |||
263 | switch (mode & S_IFMT) { | ||
264 | case S_IFIFO: | ||
265 | case S_IFBLK: | ||
266 | case S_IFCHR: | ||
267 | case S_IFSOCK: | ||
268 | if (!v9fs_extended(v9ses)) { | ||
269 | P9_DPRINTK(P9_DEBUG_ERROR, | ||
270 | "special files without extended mode\n"); | ||
271 | err = -EINVAL; | ||
272 | goto error; | ||
273 | } | ||
274 | init_special_inode(inode, inode->i_mode, inode->i_rdev); | ||
275 | break; | ||
276 | case S_IFREG: | ||
277 | inode->i_op = &v9fs_file_inode_operations; | ||
278 | inode->i_fop = &v9fs_file_operations; | ||
279 | break; | ||
280 | case S_IFLNK: | ||
281 | if (!v9fs_extended(v9ses)) { | ||
282 | P9_DPRINTK(P9_DEBUG_ERROR, | ||
283 | "extended modes used w/o 9P2000.u\n"); | ||
284 | err = -EINVAL; | ||
285 | goto error; | ||
286 | } | ||
287 | inode->i_op = &v9fs_symlink_inode_operations; | ||
288 | break; | ||
289 | case S_IFDIR: | ||
290 | inc_nlink(inode); | ||
291 | if (v9fs_extended(v9ses)) | ||
292 | inode->i_op = &v9fs_dir_inode_operations_ext; | ||
293 | else | ||
294 | inode->i_op = &v9fs_dir_inode_operations; | ||
295 | inode->i_fop = &v9fs_dir_operations; | ||
296 | break; | ||
297 | default: | ||
298 | P9_DPRINTK(P9_DEBUG_ERROR, "BAD mode 0x%x S_IFMT 0x%x\n", | ||
299 | mode, mode & S_IFMT); | ||
300 | err = -EINVAL; | ||
301 | goto error; | ||
302 | } | ||
303 | |||
268 | return inode; | 304 | return inode; |
305 | |||
306 | error: | ||
307 | iput(inode); | ||
308 | return ERR_PTR(err); | ||
269 | } | 309 | } |
270 | 310 | ||
271 | /* | 311 | /* |
@@ -320,6 +360,21 @@ error: | |||
320 | } | 360 | } |
321 | */ | 361 | */ |
322 | 362 | ||
363 | |||
364 | /** | ||
365 | * v9fs_clear_inode - release an inode | ||
366 | * @inode: inode to release | ||
367 | * | ||
368 | */ | ||
369 | void v9fs_clear_inode(struct inode *inode) | ||
370 | { | ||
371 | filemap_fdatawrite(inode->i_mapping); | ||
372 | |||
373 | #ifdef CONFIG_9P_FSCACHE | ||
374 | v9fs_cache_inode_put_cookie(inode); | ||
375 | #endif | ||
376 | } | ||
377 | |||
323 | /** | 378 | /** |
324 | * v9fs_inode_from_fid - populate an inode by issuing a attribute request | 379 | * v9fs_inode_from_fid - populate an inode by issuing a attribute request |
325 | * @v9ses: session information | 380 | * @v9ses: session information |
@@ -338,30 +393,31 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, | |||
338 | 393 | ||
339 | ret = NULL; | 394 | ret = NULL; |
340 | st = p9_client_stat(fid); | 395 | st = p9_client_stat(fid); |
341 | if (IS_ERR(st)) { | 396 | if (IS_ERR(st)) |
342 | err = PTR_ERR(st); | 397 | return ERR_CAST(st); |
343 | st = NULL; | ||
344 | goto error; | ||
345 | } | ||
346 | 398 | ||
347 | umode = p9mode2unixmode(v9ses, st->mode); | 399 | umode = p9mode2unixmode(v9ses, st->mode); |
348 | ret = v9fs_get_inode(sb, umode); | 400 | ret = v9fs_get_inode(sb, umode); |
349 | if (IS_ERR(ret)) { | 401 | if (IS_ERR(ret)) { |
350 | err = PTR_ERR(ret); | 402 | err = PTR_ERR(ret); |
351 | ret = NULL; | ||
352 | goto error; | 403 | goto error; |
353 | } | 404 | } |
354 | 405 | ||
355 | v9fs_stat2inode(st, ret, sb); | 406 | v9fs_stat2inode(st, ret, sb); |
356 | ret->i_ino = v9fs_qid2ino(&st->qid); | 407 | ret->i_ino = v9fs_qid2ino(&st->qid); |
408 | |||
409 | #ifdef CONFIG_9P_FSCACHE | ||
410 | v9fs_vcookie_set_qid(ret, &st->qid); | ||
411 | v9fs_cache_inode_get_cookie(ret); | ||
412 | #endif | ||
413 | p9stat_free(st); | ||
357 | kfree(st); | 414 | kfree(st); |
415 | |||
358 | return ret; | 416 | return ret; |
359 | 417 | ||
360 | error: | 418 | error: |
419 | p9stat_free(st); | ||
361 | kfree(st); | 420 | kfree(st); |
362 | if (ret) | ||
363 | iput(ret); | ||
364 | |||
365 | return ERR_PTR(err); | 421 | return ERR_PTR(err); |
366 | } | 422 | } |
367 | 423 | ||
@@ -403,9 +459,9 @@ v9fs_open_created(struct inode *inode, struct file *file) | |||
403 | * @v9ses: session information | 459 | * @v9ses: session information |
404 | * @dir: directory that dentry is being created in | 460 | * @dir: directory that dentry is being created in |
405 | * @dentry: dentry that is being created | 461 | * @dentry: dentry that is being created |
462 | * @extension: 9p2000.u extension string to support devices, etc. | ||
406 | * @perm: create permissions | 463 | * @perm: create permissions |
407 | * @mode: open mode | 464 | * @mode: open mode |
408 | * @extension: 9p2000.u extension string to support devices, etc. | ||
409 | * | 465 | * |
410 | */ | 466 | */ |
411 | static struct p9_fid * | 467 | static struct p9_fid * |
@@ -470,7 +526,10 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, | |||
470 | dentry->d_op = &v9fs_dentry_operations; | 526 | dentry->d_op = &v9fs_dentry_operations; |
471 | 527 | ||
472 | d_instantiate(dentry, inode); | 528 | d_instantiate(dentry, inode); |
473 | v9fs_fid_add(dentry, fid); | 529 | err = v9fs_fid_add(dentry, fid); |
530 | if (err < 0) | ||
531 | goto error; | ||
532 | |||
474 | return ofid; | 533 | return ofid; |
475 | 534 | ||
476 | error: | 535 | error: |
@@ -747,7 +806,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
747 | P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); | 806 | P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry); |
748 | err = -EPERM; | 807 | err = -EPERM; |
749 | v9ses = v9fs_inode2v9ses(dentry->d_inode); | 808 | v9ses = v9fs_inode2v9ses(dentry->d_inode); |
750 | if (v9ses->cache == CACHE_LOOSE) | 809 | if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) |
751 | return simple_getattr(mnt, dentry, stat); | 810 | return simple_getattr(mnt, dentry, stat); |
752 | 811 | ||
753 | fid = v9fs_fid_lookup(dentry); | 812 | fid = v9fs_fid_lookup(dentry); |
@@ -868,10 +927,10 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, | |||
868 | } else | 927 | } else |
869 | inode->i_rdev = 0; | 928 | inode->i_rdev = 0; |
870 | 929 | ||
871 | inode->i_size = stat->length; | 930 | i_size_write(inode, stat->length); |
872 | 931 | ||
873 | /* not real number of blocks, but 512 byte ones ... */ | 932 | /* not real number of blocks, but 512 byte ones ... */ |
874 | inode->i_blocks = (inode->i_size + 512 - 1) >> 9; | 933 | inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9; |
875 | } | 934 | } |
876 | 935 | ||
877 | /** | 936 | /** |