diff options
Diffstat (limited to 'fs/9p/vfs_inode.c')
-rw-r--r-- | fs/9p/vfs_inode.c | 139 |
1 files changed, 87 insertions, 52 deletions
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 8bb5507e822f..e3c03db3c788 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c | |||
@@ -95,15 +95,18 @@ static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode) | |||
95 | /** | 95 | /** |
96 | * p9mode2unixmode- convert plan9 mode bits to unix mode bits | 96 | * p9mode2unixmode- convert plan9 mode bits to unix mode bits |
97 | * @v9ses: v9fs session information | 97 | * @v9ses: v9fs session information |
98 | * @mode: mode to convert | 98 | * @stat: p9_wstat from which mode need to be derived |
99 | * @rdev: major number, minor number in case of device files. | ||
99 | * | 100 | * |
100 | */ | 101 | */ |
101 | 102 | static int p9mode2unixmode(struct v9fs_session_info *v9ses, | |
102 | static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) | 103 | struct p9_wstat *stat, dev_t *rdev) |
103 | { | 104 | { |
104 | int res; | 105 | int res; |
106 | int mode = stat->mode; | ||
105 | 107 | ||
106 | res = mode & 0777; | 108 | res = mode & S_IALLUGO; |
109 | *rdev = 0; | ||
107 | 110 | ||
108 | if ((mode & P9_DMDIR) == P9_DMDIR) | 111 | if ((mode & P9_DMDIR) == P9_DMDIR) |
109 | res |= S_IFDIR; | 112 | res |= S_IFDIR; |
@@ -116,9 +119,26 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) | |||
116 | && (v9ses->nodev == 0)) | 119 | && (v9ses->nodev == 0)) |
117 | res |= S_IFIFO; | 120 | res |= S_IFIFO; |
118 | else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses)) | 121 | else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses)) |
119 | && (v9ses->nodev == 0)) | 122 | && (v9ses->nodev == 0)) { |
120 | res |= S_IFBLK; | 123 | char type = 0, ext[32]; |
121 | else | 124 | int major = -1, minor = -1; |
125 | |||
126 | strncpy(ext, stat->extension, sizeof(ext)); | ||
127 | sscanf(ext, "%c %u %u", &type, &major, &minor); | ||
128 | switch (type) { | ||
129 | case 'c': | ||
130 | res |= S_IFCHR; | ||
131 | break; | ||
132 | case 'b': | ||
133 | res |= S_IFBLK; | ||
134 | break; | ||
135 | default: | ||
136 | P9_DPRINTK(P9_DEBUG_ERROR, | ||
137 | "Unknown special type %c %s\n", type, | ||
138 | stat->extension); | ||
139 | }; | ||
140 | *rdev = MKDEV(major, minor); | ||
141 | } else | ||
122 | res |= S_IFREG; | 142 | res |= S_IFREG; |
123 | 143 | ||
124 | if (v9fs_proto_dotu(v9ses)) { | 144 | if (v9fs_proto_dotu(v9ses)) { |
@@ -131,7 +151,6 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode) | |||
131 | if ((mode & P9_DMSETVTX) == P9_DMSETVTX) | 151 | if ((mode & P9_DMSETVTX) == P9_DMSETVTX) |
132 | res |= S_ISVTX; | 152 | res |= S_ISVTX; |
133 | } | 153 | } |
134 | |||
135 | return res; | 154 | return res; |
136 | } | 155 | } |
137 | 156 | ||
@@ -242,13 +261,13 @@ void v9fs_destroy_inode(struct inode *inode) | |||
242 | } | 261 | } |
243 | 262 | ||
244 | int v9fs_init_inode(struct v9fs_session_info *v9ses, | 263 | int v9fs_init_inode(struct v9fs_session_info *v9ses, |
245 | struct inode *inode, int mode) | 264 | struct inode *inode, int mode, dev_t rdev) |
246 | { | 265 | { |
247 | int err = 0; | 266 | int err = 0; |
248 | 267 | ||
249 | inode_init_owner(inode, NULL, mode); | 268 | inode_init_owner(inode, NULL, mode); |
250 | inode->i_blocks = 0; | 269 | inode->i_blocks = 0; |
251 | inode->i_rdev = 0; | 270 | inode->i_rdev = rdev; |
252 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; | 271 | inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; |
253 | inode->i_mapping->a_ops = &v9fs_addr_operations; | 272 | inode->i_mapping->a_ops = &v9fs_addr_operations; |
254 | 273 | ||
@@ -335,7 +354,7 @@ error: | |||
335 | * | 354 | * |
336 | */ | 355 | */ |
337 | 356 | ||
338 | struct inode *v9fs_get_inode(struct super_block *sb, int mode) | 357 | struct inode *v9fs_get_inode(struct super_block *sb, int mode, dev_t rdev) |
339 | { | 358 | { |
340 | int err; | 359 | int err; |
341 | struct inode *inode; | 360 | struct inode *inode; |
@@ -348,7 +367,7 @@ struct inode *v9fs_get_inode(struct super_block *sb, int mode) | |||
348 | P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n"); | 367 | P9_EPRINTK(KERN_WARNING, "Problem allocating inode\n"); |
349 | return ERR_PTR(-ENOMEM); | 368 | return ERR_PTR(-ENOMEM); |
350 | } | 369 | } |
351 | err = v9fs_init_inode(v9ses, inode, mode); | 370 | err = v9fs_init_inode(v9ses, inode, mode, rdev); |
352 | if (err) { | 371 | if (err) { |
353 | iput(inode); | 372 | iput(inode); |
354 | return ERR_PTR(err); | 373 | return ERR_PTR(err); |
@@ -435,11 +454,12 @@ void v9fs_evict_inode(struct inode *inode) | |||
435 | static int v9fs_test_inode(struct inode *inode, void *data) | 454 | static int v9fs_test_inode(struct inode *inode, void *data) |
436 | { | 455 | { |
437 | int umode; | 456 | int umode; |
457 | dev_t rdev; | ||
438 | struct v9fs_inode *v9inode = V9FS_I(inode); | 458 | struct v9fs_inode *v9inode = V9FS_I(inode); |
439 | struct p9_wstat *st = (struct p9_wstat *)data; | 459 | struct p9_wstat *st = (struct p9_wstat *)data; |
440 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); | 460 | struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode); |
441 | 461 | ||
442 | umode = p9mode2unixmode(v9ses, st->mode); | 462 | umode = p9mode2unixmode(v9ses, st, &rdev); |
443 | /* don't match inode of different type */ | 463 | /* don't match inode of different type */ |
444 | if ((inode->i_mode & S_IFMT) != (umode & S_IFMT)) | 464 | if ((inode->i_mode & S_IFMT) != (umode & S_IFMT)) |
445 | return 0; | 465 | return 0; |
@@ -473,6 +493,7 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, | |||
473 | struct p9_wstat *st, | 493 | struct p9_wstat *st, |
474 | int new) | 494 | int new) |
475 | { | 495 | { |
496 | dev_t rdev; | ||
476 | int retval, umode; | 497 | int retval, umode; |
477 | unsigned long i_ino; | 498 | unsigned long i_ino; |
478 | struct inode *inode; | 499 | struct inode *inode; |
@@ -496,8 +517,8 @@ static struct inode *v9fs_qid_iget(struct super_block *sb, | |||
496 | * later. | 517 | * later. |
497 | */ | 518 | */ |
498 | inode->i_ino = i_ino; | 519 | inode->i_ino = i_ino; |
499 | umode = p9mode2unixmode(v9ses, st->mode); | 520 | umode = p9mode2unixmode(v9ses, st, &rdev); |
500 | retval = v9fs_init_inode(v9ses, inode, umode); | 521 | retval = v9fs_init_inode(v9ses, inode, umode, rdev); |
501 | if (retval) | 522 | if (retval) |
502 | goto error; | 523 | goto error; |
503 | 524 | ||
@@ -532,6 +553,19 @@ v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid, | |||
532 | } | 553 | } |
533 | 554 | ||
534 | /** | 555 | /** |
556 | * v9fs_at_to_dotl_flags- convert Linux specific AT flags to | ||
557 | * plan 9 AT flag. | ||
558 | * @flags: flags to convert | ||
559 | */ | ||
560 | static int v9fs_at_to_dotl_flags(int flags) | ||
561 | { | ||
562 | int rflags = 0; | ||
563 | if (flags & AT_REMOVEDIR) | ||
564 | rflags |= P9_DOTL_AT_REMOVEDIR; | ||
565 | return rflags; | ||
566 | } | ||
567 | |||
568 | /** | ||
535 | * v9fs_remove - helper function to remove files and directories | 569 | * v9fs_remove - helper function to remove files and directories |
536 | * @dir: directory inode that is being deleted | 570 | * @dir: directory inode that is being deleted |
537 | * @dentry: dentry that is being deleted | 571 | * @dentry: dentry that is being deleted |
@@ -558,7 +592,8 @@ static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags) | |||
558 | return retval; | 592 | return retval; |
559 | } | 593 | } |
560 | if (v9fs_proto_dotl(v9ses)) | 594 | if (v9fs_proto_dotl(v9ses)) |
561 | retval = p9_client_unlinkat(dfid, dentry->d_name.name, flags); | 595 | retval = p9_client_unlinkat(dfid, dentry->d_name.name, |
596 | v9fs_at_to_dotl_flags(flags)); | ||
562 | if (retval == -EOPNOTSUPP) { | 597 | if (retval == -EOPNOTSUPP) { |
563 | /* Try the one based on path */ | 598 | /* Try the one based on path */ |
564 | v9fid = v9fs_fid_clone(dentry); | 599 | v9fid = v9fs_fid_clone(dentry); |
@@ -645,13 +680,11 @@ v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir, | |||
645 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); | 680 | P9_DPRINTK(P9_DEBUG_VFS, "inode creation failed %d\n", err); |
646 | goto error; | 681 | goto error; |
647 | } | 682 | } |
648 | d_instantiate(dentry, inode); | ||
649 | err = v9fs_fid_add(dentry, fid); | 683 | err = v9fs_fid_add(dentry, fid); |
650 | if (err < 0) | 684 | if (err < 0) |
651 | goto error; | 685 | goto error; |
652 | 686 | d_instantiate(dentry, inode); | |
653 | return ofid; | 687 | return ofid; |
654 | |||
655 | error: | 688 | error: |
656 | if (ofid) | 689 | if (ofid) |
657 | p9_client_clunk(ofid); | 690 | p9_client_clunk(ofid); |
@@ -792,6 +825,7 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) | |||
792 | struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | 825 | struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, |
793 | struct nameidata *nameidata) | 826 | struct nameidata *nameidata) |
794 | { | 827 | { |
828 | struct dentry *res; | ||
795 | struct super_block *sb; | 829 | struct super_block *sb; |
796 | struct v9fs_session_info *v9ses; | 830 | struct v9fs_session_info *v9ses; |
797 | struct p9_fid *dfid, *fid; | 831 | struct p9_fid *dfid, *fid; |
@@ -823,22 +857,35 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, | |||
823 | 857 | ||
824 | return ERR_PTR(result); | 858 | return ERR_PTR(result); |
825 | } | 859 | } |
826 | 860 | /* | |
827 | inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); | 861 | * Make sure we don't use a wrong inode due to parallel |
862 | * unlink. For cached mode create calls request for new | ||
863 | * inode. But with cache disabled, lookup should do this. | ||
864 | */ | ||
865 | if (v9ses->cache) | ||
866 | inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb); | ||
867 | else | ||
868 | inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb); | ||
828 | if (IS_ERR(inode)) { | 869 | if (IS_ERR(inode)) { |
829 | result = PTR_ERR(inode); | 870 | result = PTR_ERR(inode); |
830 | inode = NULL; | 871 | inode = NULL; |
831 | goto error; | 872 | goto error; |
832 | } | 873 | } |
833 | |||
834 | result = v9fs_fid_add(dentry, fid); | 874 | result = v9fs_fid_add(dentry, fid); |
835 | if (result < 0) | 875 | if (result < 0) |
836 | goto error_iput; | 876 | goto error_iput; |
837 | |||
838 | inst_out: | 877 | inst_out: |
839 | d_add(dentry, inode); | 878 | /* |
840 | return NULL; | 879 | * If we had a rename on the server and a parallel lookup |
841 | 880 | * for the new name, then make sure we instantiate with | |
881 | * the new name. ie look up for a/b, while on server somebody | ||
882 | * moved b under k and client parallely did a lookup for | ||
883 | * k/b. | ||
884 | */ | ||
885 | res = d_materialise_unique(dentry, inode); | ||
886 | if (!IS_ERR(res)) | ||
887 | return res; | ||
888 | result = PTR_ERR(res); | ||
842 | error_iput: | 889 | error_iput: |
843 | iput(inode); | 890 | iput(inode); |
844 | error: | 891 | error: |
@@ -1002,7 +1049,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry, | |||
1002 | return PTR_ERR(st); | 1049 | return PTR_ERR(st); |
1003 | 1050 | ||
1004 | v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb); | 1051 | v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb); |
1005 | generic_fillattr(dentry->d_inode, stat); | 1052 | generic_fillattr(dentry->d_inode, stat); |
1006 | 1053 | ||
1007 | p9stat_free(st); | 1054 | p9stat_free(st); |
1008 | kfree(st); | 1055 | kfree(st); |
@@ -1086,6 +1133,7 @@ void | |||
1086 | v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, | 1133 | v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, |
1087 | struct super_block *sb) | 1134 | struct super_block *sb) |
1088 | { | 1135 | { |
1136 | mode_t mode; | ||
1089 | char ext[32]; | 1137 | char ext[32]; |
1090 | char tag_name[14]; | 1138 | char tag_name[14]; |
1091 | unsigned int i_nlink; | 1139 | unsigned int i_nlink; |
@@ -1121,31 +1169,9 @@ v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode, | |||
1121 | inode->i_nlink = i_nlink; | 1169 | inode->i_nlink = i_nlink; |
1122 | } | 1170 | } |
1123 | } | 1171 | } |
1124 | inode->i_mode = p9mode2unixmode(v9ses, stat->mode); | 1172 | mode = stat->mode & S_IALLUGO; |
1125 | if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { | 1173 | mode |= inode->i_mode & ~S_IALLUGO; |
1126 | char type = 0; | 1174 | inode->i_mode = mode; |
1127 | int major = -1; | ||
1128 | int minor = -1; | ||
1129 | |||
1130 | strncpy(ext, stat->extension, sizeof(ext)); | ||
1131 | sscanf(ext, "%c %u %u", &type, &major, &minor); | ||
1132 | switch (type) { | ||
1133 | case 'c': | ||
1134 | inode->i_mode &= ~S_IFBLK; | ||
1135 | inode->i_mode |= S_IFCHR; | ||
1136 | break; | ||
1137 | case 'b': | ||
1138 | break; | ||
1139 | default: | ||
1140 | P9_DPRINTK(P9_DEBUG_ERROR, | ||
1141 | "Unknown special type %c %s\n", type, | ||
1142 | stat->extension); | ||
1143 | }; | ||
1144 | inode->i_rdev = MKDEV(major, minor); | ||
1145 | init_special_inode(inode, inode->i_mode, inode->i_rdev); | ||
1146 | } else | ||
1147 | inode->i_rdev = 0; | ||
1148 | |||
1149 | i_size_write(inode, stat->length); | 1175 | i_size_write(inode, stat->length); |
1150 | 1176 | ||
1151 | /* not real number of blocks, but 512 byte ones ... */ | 1177 | /* not real number of blocks, but 512 byte ones ... */ |
@@ -1411,6 +1437,8 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | |||
1411 | 1437 | ||
1412 | int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode) | 1438 | int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode) |
1413 | { | 1439 | { |
1440 | int umode; | ||
1441 | dev_t rdev; | ||
1414 | loff_t i_size; | 1442 | loff_t i_size; |
1415 | struct p9_wstat *st; | 1443 | struct p9_wstat *st; |
1416 | struct v9fs_session_info *v9ses; | 1444 | struct v9fs_session_info *v9ses; |
@@ -1419,6 +1447,12 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode) | |||
1419 | st = p9_client_stat(fid); | 1447 | st = p9_client_stat(fid); |
1420 | if (IS_ERR(st)) | 1448 | if (IS_ERR(st)) |
1421 | return PTR_ERR(st); | 1449 | return PTR_ERR(st); |
1450 | /* | ||
1451 | * Don't update inode if the file type is different | ||
1452 | */ | ||
1453 | umode = p9mode2unixmode(v9ses, st, &rdev); | ||
1454 | if ((inode->i_mode & S_IFMT) != (umode & S_IFMT)) | ||
1455 | goto out; | ||
1422 | 1456 | ||
1423 | spin_lock(&inode->i_lock); | 1457 | spin_lock(&inode->i_lock); |
1424 | /* | 1458 | /* |
@@ -1430,6 +1464,7 @@ int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode) | |||
1430 | if (v9ses->cache) | 1464 | if (v9ses->cache) |
1431 | inode->i_size = i_size; | 1465 | inode->i_size = i_size; |
1432 | spin_unlock(&inode->i_lock); | 1466 | spin_unlock(&inode->i_lock); |
1467 | out: | ||
1433 | p9stat_free(st); | 1468 | p9stat_free(st); |
1434 | kfree(st); | 1469 | kfree(st); |
1435 | return 0; | 1470 | return 0; |