aboutsummaryrefslogtreecommitdiffstats
path: root/fs/9p/vfs_inode.c
diff options
context:
space:
mode:
authorLatchesar Ionkov <lucho@ionkov.net>2006-01-08 04:05:00 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-08 23:14:06 -0500
commit531b1094b74365dcc55fa464d28a9a2497ae825d (patch)
treea0384dabe3be1c844166d028b3ef7c21c3dfe5fc /fs/9p/vfs_inode.c
parentd8da097afb765654c866062148fd98b11db9003e (diff)
[PATCH] v9fs: zero copy implementation
Performance enhancement reducing the number of copies in the data and stat paths. Signed-off-by: Latchesar Ionkov <lucho@ionkov.net> Cc: Eric Van Hensbergen <ericvh@ericvh.myip.org> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'fs/9p/vfs_inode.c')
-rw-r--r--fs/9p/vfs_inode.c545
1 files changed, 173 insertions, 372 deletions
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index f11edde6432e..742bcd0dc4a7 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -40,7 +40,6 @@
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 "conv.h"
44#include "fid.h" 43#include "fid.h"
45 44
46static struct inode_operations v9fs_dir_inode_operations; 45static struct inode_operations v9fs_dir_inode_operations;
@@ -127,100 +126,32 @@ static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
127} 126}
128 127
129/** 128/**
130 * v9fs_blank_mistat - helper function to setup a 9P stat structure 129 * v9fs_blank_wstat - helper function to setup a 9P stat structure
131 * @v9ses: 9P session info (for determining extended mode) 130 * @v9ses: 9P session info (for determining extended mode)
132 * @mistat: structure to initialize 131 * @wstat: structure to initialize
133 * 132 *
134 */ 133 */
135 134
136static void 135static void
137v9fs_blank_mistat(struct v9fs_session_info *v9ses, struct v9fs_stat *mistat) 136v9fs_blank_wstat(struct v9fs_wstat *wstat)
138{ 137{
139 mistat->type = ~0; 138 wstat->type = ~0;
140 mistat->dev = ~0; 139 wstat->dev = ~0;
141 mistat->qid.type = ~0; 140 wstat->qid.type = ~0;
142 mistat->qid.version = ~0; 141 wstat->qid.version = ~0;
143 *((long long *)&mistat->qid.path) = ~0; 142 *((long long *)&wstat->qid.path) = ~0;
144 mistat->mode = ~0; 143 wstat->mode = ~0;
145 mistat->atime = ~0; 144 wstat->atime = ~0;
146 mistat->mtime = ~0; 145 wstat->mtime = ~0;
147 mistat->length = ~0; 146 wstat->length = ~0;
148 mistat->name = mistat->data; 147 wstat->name = NULL;
149 mistat->uid = mistat->data; 148 wstat->uid = NULL;
150 mistat->gid = mistat->data; 149 wstat->gid = NULL;
151 mistat->muid = mistat->data; 150 wstat->muid = NULL;
152 if (v9ses->extended) { 151 wstat->n_uid = ~0;
153 mistat->n_uid = ~0; 152 wstat->n_gid = ~0;
154 mistat->n_gid = ~0; 153 wstat->n_muid = ~0;
155 mistat->n_muid = ~0; 154 wstat->extension = NULL;
156 mistat->extension = mistat->data;
157 }
158 *mistat->data = 0;
159}
160
161/**
162 * v9fs_mistat2unix - convert mistat to unix stat
163 * @mistat: Plan 9 metadata (mistat) structure
164 * @buf: unix metadata (stat) structure to populate
165 * @sb: superblock
166 *
167 */
168
169static void
170v9fs_mistat2unix(struct v9fs_stat *mistat, struct stat *buf,
171 struct super_block *sb)
172{
173 struct v9fs_session_info *v9ses = sb ? sb->s_fs_info : NULL;
174
175 buf->st_nlink = 1;
176
177 buf->st_atime = mistat->atime;
178 buf->st_mtime = mistat->mtime;
179 buf->st_ctime = mistat->mtime;
180
181 buf->st_uid = (unsigned short)-1;
182 buf->st_gid = (unsigned short)-1;
183
184 if (v9ses && v9ses->extended) {
185 /* TODO: string to uid mapping via user-space daemon */
186 if (mistat->n_uid != -1)
187 sscanf(mistat->uid, "%x", (unsigned int *)&buf->st_uid);
188
189 if (mistat->n_gid != -1)
190 sscanf(mistat->gid, "%x", (unsigned int *)&buf->st_gid);
191 }
192
193 if (buf->st_uid == (unsigned short)-1)
194 buf->st_uid = v9ses->uid;
195 if (buf->st_gid == (unsigned short)-1)
196 buf->st_gid = v9ses->gid;
197
198 buf->st_mode = p9mode2unixmode(v9ses, mistat->mode);
199 if ((S_ISBLK(buf->st_mode)) || (S_ISCHR(buf->st_mode))) {
200 char type = 0;
201 int major = -1;
202 int minor = -1;
203 sscanf(mistat->extension, "%c %u %u", &type, &major, &minor);
204 switch (type) {
205 case 'c':
206 buf->st_mode &= ~S_IFBLK;
207 buf->st_mode |= S_IFCHR;
208 break;
209 case 'b':
210 break;
211 default:
212 dprintk(DEBUG_ERROR, "Unknown special type %c (%s)\n",
213 type, mistat->extension);
214 };
215 buf->st_rdev = MKDEV(major, minor);
216 } else
217 buf->st_rdev = 0;
218
219 buf->st_size = mistat->length;
220
221 buf->st_blksize = sb->s_blocksize;
222 buf->st_blocks =
223 (buf->st_size + buf->st_blksize - 1) >> sb->s_blocksize_bits;
224} 155}
225 156
226/** 157/**
@@ -312,7 +243,6 @@ v9fs_create(struct inode *dir,
312 struct inode *file_inode = NULL; 243 struct inode *file_inode = NULL;
313 struct v9fs_fcall *fcall = NULL; 244 struct v9fs_fcall *fcall = NULL;
314 struct v9fs_qid qid; 245 struct v9fs_qid qid;
315 struct stat newstat;
316 int dirfidnum = -1; 246 int dirfidnum = -1;
317 long newfid = -1; 247 long newfid = -1;
318 int result = 0; 248 int result = 0;
@@ -350,7 +280,7 @@ v9fs_create(struct inode *dir,
350 280
351 result = v9fs_t_walk(v9ses, dirfidnum, newfid, NULL, &fcall); 281 result = v9fs_t_walk(v9ses, dirfidnum, newfid, NULL, &fcall);
352 if (result < 0) { 282 if (result < 0) {
353 dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); 283 PRINT_FCALL_ERROR("clone error", fcall);
354 v9fs_put_idpool(newfid, &v9ses->fidpool); 284 v9fs_put_idpool(newfid, &v9ses->fidpool);
355 newfid = -1; 285 newfid = -1;
356 goto CleanUpFid; 286 goto CleanUpFid;
@@ -362,9 +292,7 @@ v9fs_create(struct inode *dir,
362 result = v9fs_t_create(v9ses, newfid, (char *)file_dentry->d_name.name, 292 result = v9fs_t_create(v9ses, newfid, (char *)file_dentry->d_name.name,
363 perm, open_mode, &fcall); 293 perm, open_mode, &fcall);
364 if (result < 0) { 294 if (result < 0) {
365 dprintk(DEBUG_ERROR, "create fails: %s(%d)\n", 295 PRINT_FCALL_ERROR("create fails", fcall);
366 FCALL_ERROR(fcall), result);
367
368 goto CleanUpFid; 296 goto CleanUpFid;
369 } 297 }
370 298
@@ -400,7 +328,7 @@ v9fs_create(struct inode *dir,
400 result = v9fs_t_walk(v9ses, dirfidnum, wfidno, 328 result = v9fs_t_walk(v9ses, dirfidnum, wfidno,
401 (char *) file_dentry->d_name.name, &fcall); 329 (char *) file_dentry->d_name.name, &fcall);
402 if (result < 0) { 330 if (result < 0) {
403 dprintk(DEBUG_ERROR, "clone error: %s\n", FCALL_ERROR(fcall)); 331 PRINT_FCALL_ERROR("clone error", fcall);
404 v9fs_put_idpool(wfidno, &v9ses->fidpool); 332 v9fs_put_idpool(wfidno, &v9ses->fidpool);
405 wfidno = -1; 333 wfidno = -1;
406 goto CleanUpFid; 334 goto CleanUpFid;
@@ -421,21 +349,21 @@ v9fs_create(struct inode *dir,
421 349
422 result = v9fs_t_stat(v9ses, wfidno, &fcall); 350 result = v9fs_t_stat(v9ses, wfidno, &fcall);
423 if (result < 0) { 351 if (result < 0) {
424 dprintk(DEBUG_ERROR, "stat error: %s(%d)\n", FCALL_ERROR(fcall), 352 PRINT_FCALL_ERROR("stat error", fcall);
425 result);
426 goto CleanUpFid; 353 goto CleanUpFid;
427 } 354 }
428 355
429 v9fs_mistat2unix(fcall->params.rstat.stat, &newstat, sb);
430 356
431 file_inode = v9fs_get_inode(sb, newstat.st_mode); 357 file_inode = v9fs_get_inode(sb,
358 p9mode2unixmode(v9ses, fcall->params.rstat.stat.mode));
359
432 if ((!file_inode) || IS_ERR(file_inode)) { 360 if ((!file_inode) || IS_ERR(file_inode)) {
433 dprintk(DEBUG_ERROR, "create inode failed\n"); 361 dprintk(DEBUG_ERROR, "create inode failed\n");
434 result = -EBADF; 362 result = -EBADF;
435 goto CleanUpFid; 363 goto CleanUpFid;
436 } 364 }
437 365
438 v9fs_mistat2inode(fcall->params.rstat.stat, file_inode, sb); 366 v9fs_stat2inode(&fcall->params.rstat.stat, file_inode, sb);
439 kfree(fcall); 367 kfree(fcall);
440 fcall = NULL; 368 fcall = NULL;
441 file_dentry->d_op = &v9fs_dentry_operations; 369 file_dentry->d_op = &v9fs_dentry_operations;
@@ -500,10 +428,9 @@ static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
500 } 428 }
501 429
502 result = v9fs_t_remove(v9ses, fid, &fcall); 430 result = v9fs_t_remove(v9ses, fid, &fcall);
503 if (result < 0) 431 if (result < 0) {
504 dprintk(DEBUG_ERROR, "remove of file fails: %s(%d)\n", 432 PRINT_FCALL_ERROR("remove fails", fcall);
505 FCALL_ERROR(fcall), result); 433 } else {
506 else {
507 v9fs_put_idpool(fid, &v9ses->fidpool); 434 v9fs_put_idpool(fid, &v9ses->fidpool);
508 v9fs_fid_destroy(v9fid); 435 v9fs_fid_destroy(v9fid);
509 } 436 }
@@ -558,7 +485,6 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
558 struct v9fs_fid *fid; 485 struct v9fs_fid *fid;
559 struct inode *inode; 486 struct inode *inode;
560 struct v9fs_fcall *fcall = NULL; 487 struct v9fs_fcall *fcall = NULL;
561 struct stat newstat;
562 int dirfidnum = -1; 488 int dirfidnum = -1;
563 int newfid = -1; 489 int newfid = -1;
564 int result = 0; 490 int result = 0;
@@ -611,8 +537,8 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
611 goto FreeFcall; 537 goto FreeFcall;
612 } 538 }
613 539
614 v9fs_mistat2unix(fcall->params.rstat.stat, &newstat, sb); 540 inode = v9fs_get_inode(sb, p9mode2unixmode(v9ses,
615 inode = v9fs_get_inode(sb, newstat.st_mode); 541 fcall->params.rstat.stat.mode));
616 542
617 if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) { 543 if (IS_ERR(inode) && (PTR_ERR(inode) == -ENOSPC)) {
618 eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n", 544 eprintk(KERN_WARNING, "inode alloc failes, returns %ld\n",
@@ -622,7 +548,7 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
622 goto FreeFcall; 548 goto FreeFcall;
623 } 549 }
624 550
625 inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat->qid); 551 inode->i_ino = v9fs_qid2ino(&fcall->params.rstat.stat.qid);
626 552
627 fid = v9fs_fid_create(dentry, v9ses, newfid, 0); 553 fid = v9fs_fid_create(dentry, v9ses, newfid, 0);
628 if (fid == NULL) { 554 if (fid == NULL) {
@@ -631,10 +557,10 @@ static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
631 goto FreeFcall; 557 goto FreeFcall;
632 } 558 }
633 559
634 fid->qid = fcall->params.rstat.stat->qid; 560 fid->qid = fcall->params.rstat.stat.qid;
635 561
636 dentry->d_op = &v9fs_dentry_operations; 562 dentry->d_op = &v9fs_dentry_operations;
637 v9fs_mistat2inode(fcall->params.rstat.stat, inode, inode->i_sb); 563 v9fs_stat2inode(&fcall->params.rstat.stat, inode, inode->i_sb);
638 564
639 d_add(dentry, inode); 565 d_add(dentry, inode);
640 kfree(fcall); 566 kfree(fcall);
@@ -690,7 +616,7 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
690 v9fs_fid_lookup(old_dentry->d_parent); 616 v9fs_fid_lookup(old_dentry->d_parent);
691 struct v9fs_fid *newdirfid = 617 struct v9fs_fid *newdirfid =
692 v9fs_fid_lookup(new_dentry->d_parent); 618 v9fs_fid_lookup(new_dentry->d_parent);
693 struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); 619 struct v9fs_wstat wstat;
694 struct v9fs_fcall *fcall = NULL; 620 struct v9fs_fcall *fcall = NULL;
695 int fid = -1; 621 int fid = -1;
696 int olddirfidnum = -1; 622 int olddirfidnum = -1;
@@ -699,9 +625,6 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
699 625
700 dprintk(DEBUG_VFS, "\n"); 626 dprintk(DEBUG_VFS, "\n");
701 627
702 if (!mistat)
703 return -ENOMEM;
704
705 if ((!oldfid) || (!olddirfid) || (!newdirfid)) { 628 if ((!oldfid) || (!olddirfid) || (!newdirfid)) {
706 dprintk(DEBUG_ERROR, "problem with arguments\n"); 629 dprintk(DEBUG_ERROR, "problem with arguments\n");
707 return -EBADF; 630 return -EBADF;
@@ -725,26 +648,15 @@ v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
725 goto FreeFcallnBail; 648 goto FreeFcallnBail;
726 } 649 }
727 650
728 v9fs_blank_mistat(v9ses, mistat); 651 v9fs_blank_wstat(&wstat);
729 652 wstat.muid = v9ses->name;
730 strcpy(mistat->data + 1, v9ses->name); 653 wstat.name = (char *) new_dentry->d_name.name;
731 mistat->name = mistat->data + 1 + strlen(v9ses->name);
732
733 if (new_dentry->d_name.len >
734 (v9ses->maxdata - strlen(v9ses->name) - sizeof(struct v9fs_stat))) {
735 dprintk(DEBUG_ERROR, "new name too long\n");
736 goto FreeFcallnBail;
737 }
738 654
739 strcpy(mistat->name, new_dentry->d_name.name); 655 retval = v9fs_t_wstat(v9ses, fid, &wstat, &fcall);
740 retval = v9fs_t_wstat(v9ses, fid, mistat, &fcall);
741 656
742 FreeFcallnBail: 657 FreeFcallnBail:
743 kfree(mistat);
744
745 if (retval < 0) 658 if (retval < 0)
746 dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", 659 PRINT_FCALL_ERROR("wstat error", fcall);
747 FCALL_ERROR(fcall));
748 660
749 kfree(fcall); 661 kfree(fcall);
750 return retval; 662 return retval;
@@ -779,7 +691,7 @@ v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
779 if (err < 0) 691 if (err < 0)
780 dprintk(DEBUG_ERROR, "stat error\n"); 692 dprintk(DEBUG_ERROR, "stat error\n");
781 else { 693 else {
782 v9fs_mistat2inode(fcall->params.rstat.stat, dentry->d_inode, 694 v9fs_stat2inode(&fcall->params.rstat.stat, dentry->d_inode,
783 dentry->d_inode->i_sb); 695 dentry->d_inode->i_sb);
784 generic_fillattr(dentry->d_inode, stat); 696 generic_fillattr(dentry->d_inode, stat);
785 } 697 }
@@ -800,57 +712,44 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
800 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode); 712 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dentry->d_inode);
801 struct v9fs_fid *fid = v9fs_fid_lookup(dentry); 713 struct v9fs_fid *fid = v9fs_fid_lookup(dentry);
802 struct v9fs_fcall *fcall = NULL; 714 struct v9fs_fcall *fcall = NULL;
803 struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); 715 struct v9fs_wstat wstat;
804 int res = -EPERM; 716 int res = -EPERM;
805 717
806 dprintk(DEBUG_VFS, "\n"); 718 dprintk(DEBUG_VFS, "\n");
807 719
808 if (!mistat)
809 return -ENOMEM;
810
811 if (!fid) { 720 if (!fid) {
812 dprintk(DEBUG_ERROR, 721 dprintk(DEBUG_ERROR,
813 "Couldn't find fid associated with dentry\n"); 722 "Couldn't find fid associated with dentry\n");
814 return -EBADF; 723 return -EBADF;
815 } 724 }
816 725
817 v9fs_blank_mistat(v9ses, mistat); 726 v9fs_blank_wstat(&wstat);
818 if (iattr->ia_valid & ATTR_MODE) 727 if (iattr->ia_valid & ATTR_MODE)
819 mistat->mode = unixmode2p9mode(v9ses, iattr->ia_mode); 728 wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode);
820 729
821 if (iattr->ia_valid & ATTR_MTIME) 730 if (iattr->ia_valid & ATTR_MTIME)
822 mistat->mtime = iattr->ia_mtime.tv_sec; 731 wstat.mtime = iattr->ia_mtime.tv_sec;
823 732
824 if (iattr->ia_valid & ATTR_ATIME) 733 if (iattr->ia_valid & ATTR_ATIME)
825 mistat->atime = iattr->ia_atime.tv_sec; 734 wstat.atime = iattr->ia_atime.tv_sec;
826 735
827 if (iattr->ia_valid & ATTR_SIZE) 736 if (iattr->ia_valid & ATTR_SIZE)
828 mistat->length = iattr->ia_size; 737 wstat.length = iattr->ia_size;
829 738
830 if (v9ses->extended) { 739 if (v9ses->extended) {
831 char *ptr = mistat->data+1; 740 if (iattr->ia_valid & ATTR_UID)
741 wstat.n_uid = iattr->ia_uid;
832 742
833 if (iattr->ia_valid & ATTR_UID) { 743 if (iattr->ia_valid & ATTR_GID)
834 mistat->uid = ptr; 744 wstat.n_gid = iattr->ia_gid;
835 ptr += 1+sprintf(ptr, "%08x", iattr->ia_uid);
836 mistat->n_uid = iattr->ia_uid;
837 }
838
839 if (iattr->ia_valid & ATTR_GID) {
840 mistat->gid = ptr;
841 ptr += 1+sprintf(ptr, "%08x", iattr->ia_gid);
842 mistat->n_gid = iattr->ia_gid;
843 }
844 } 745 }
845 746
846 res = v9fs_t_wstat(v9ses, fid->fid, mistat, &fcall); 747 res = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall);
847 748
848 if (res < 0) 749 if (res < 0)
849 dprintk(DEBUG_ERROR, "wstat error: %s\n", FCALL_ERROR(fcall)); 750 PRINT_FCALL_ERROR("wstat error", fcall);
850 751
851 kfree(mistat);
852 kfree(fcall); 752 kfree(fcall);
853
854 if (res >= 0) 753 if (res >= 0)
855 res = inode_setattr(dentry->d_inode, iattr); 754 res = inode_setattr(dentry->d_inode, iattr);
856 755
@@ -858,51 +757,42 @@ static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
858} 757}
859 758
860/** 759/**
861 * v9fs_mistat2inode - populate an inode structure with mistat info 760 * v9fs_stat2inode - populate an inode structure with mistat info
862 * @mistat: Plan 9 metadata (mistat) structure 761 * @stat: Plan 9 metadata (mistat) structure
863 * @inode: inode to populate 762 * @inode: inode to populate
864 * @sb: superblock of filesystem 763 * @sb: superblock of filesystem
865 * 764 *
866 */ 765 */
867 766
868void 767void
869v9fs_mistat2inode(struct v9fs_stat *mistat, struct inode *inode, 768v9fs_stat2inode(struct v9fs_stat *stat, struct inode *inode,
870 struct super_block *sb) 769 struct super_block *sb)
871{ 770{
771 char ext[32];
872 struct v9fs_session_info *v9ses = sb->s_fs_info; 772 struct v9fs_session_info *v9ses = sb->s_fs_info;
873 773
874 inode->i_nlink = 1; 774 inode->i_nlink = 1;
875 775
876 inode->i_atime.tv_sec = mistat->atime; 776 inode->i_atime.tv_sec = stat->atime;
877 inode->i_mtime.tv_sec = mistat->mtime; 777 inode->i_mtime.tv_sec = stat->mtime;
878 inode->i_ctime.tv_sec = mistat->mtime; 778 inode->i_ctime.tv_sec = stat->mtime;
879 779
880 inode->i_uid = -1; 780 inode->i_uid = v9ses->uid;
881 inode->i_gid = -1; 781 inode->i_gid = v9ses->gid;
882 782
883 if (v9ses->extended) { 783 if (v9ses->extended) {
884 /* TODO: string to uid mapping via user-space daemon */ 784 inode->i_uid = stat->n_uid;
885 inode->i_uid = mistat->n_uid; 785 inode->i_gid = stat->n_gid;
886 inode->i_gid = mistat->n_gid;
887
888 if (mistat->n_uid == -1)
889 sscanf(mistat->uid, "%x", &inode->i_uid);
890
891 if (mistat->n_gid == -1)
892 sscanf(mistat->gid, "%x", &inode->i_gid);
893 } 786 }
894 787
895 if (inode->i_uid == -1) 788 inode->i_mode = p9mode2unixmode(v9ses, stat->mode);
896 inode->i_uid = v9ses->uid;
897 if (inode->i_gid == -1)
898 inode->i_gid = v9ses->gid;
899
900 inode->i_mode = p9mode2unixmode(v9ses, mistat->mode);
901 if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) { 789 if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) {
902 char type = 0; 790 char type = 0;
903 int major = -1; 791 int major = -1;
904 int minor = -1; 792 int minor = -1;
905 sscanf(mistat->extension, "%c %u %u", &type, &major, &minor); 793
794 v9fs_str_copy(ext, sizeof(ext), &stat->extension);
795 sscanf(ext, "%c %u %u", &type, &major, &minor);
906 switch (type) { 796 switch (type) {
907 case 'c': 797 case 'c':
908 inode->i_mode &= ~S_IFBLK; 798 inode->i_mode &= ~S_IFBLK;
@@ -911,14 +801,14 @@ v9fs_mistat2inode(struct v9fs_stat *mistat, struct inode *inode,
911 case 'b': 801 case 'b':
912 break; 802 break;
913 default: 803 default:
914 dprintk(DEBUG_ERROR, "Unknown special type %c (%s)\n", 804 dprintk(DEBUG_ERROR, "Unknown special type %c (%.*s)\n",
915 type, mistat->extension); 805 type, stat->extension.len, stat->extension.str);
916 }; 806 };
917 inode->i_rdev = MKDEV(major, minor); 807 inode->i_rdev = MKDEV(major, minor);
918 } else 808 } else
919 inode->i_rdev = 0; 809 inode->i_rdev = 0;
920 810
921 inode->i_size = mistat->length; 811 inode->i_size = stat->length;
922 812
923 inode->i_blksize = sb->s_blocksize; 813 inode->i_blksize = sb->s_blocksize;
924 inode->i_blocks = 814 inode->i_blocks =
@@ -946,72 +836,6 @@ ino_t v9fs_qid2ino(struct v9fs_qid *qid)
946} 836}
947 837
948/** 838/**
949 * v9fs_vfs_symlink - helper function to create symlinks
950 * @dir: directory inode containing symlink
951 * @dentry: dentry for symlink
952 * @symname: symlink data
953 *
954 * See 9P2000.u RFC for more information
955 *
956 */
957
958static int
959v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
960{
961 int retval = -EPERM;
962 struct v9fs_fid *newfid;
963 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
964 struct v9fs_fcall *fcall = NULL;
965 struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
966 int err;
967
968 dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
969 symname);
970
971 if (!mistat)
972 return -ENOMEM;
973
974 if (!v9ses->extended) {
975 dprintk(DEBUG_ERROR, "not extended\n");
976 goto FreeFcall;
977 }
978
979 /* issue a create */
980 retval = v9fs_create(dir, dentry, S_IFLNK, 0);
981 if (retval != 0)
982 goto FreeFcall;
983
984 newfid = v9fs_fid_lookup(dentry);
985
986 /* issue a twstat */
987 v9fs_blank_mistat(v9ses, mistat);
988 strcpy(mistat->data + 1, symname);
989 mistat->extension = mistat->data + 1;
990 retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall);
991 if (retval < 0) {
992 dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n",
993 FCALL_ERROR(fcall));
994 goto FreeFcall;
995 }
996
997 kfree(fcall);
998
999 err = v9fs_t_clunk(v9ses, newfid->fid);
1000 if (err < 0) {
1001 dprintk(DEBUG_ERROR, "clunk for symlink failed: %d\n", err);
1002 goto FreeFcall;
1003 }
1004
1005 d_drop(dentry); /* FID - will this also clunk? */
1006
1007 FreeFcall:
1008 kfree(mistat);
1009 kfree(fcall);
1010
1011 return retval;
1012}
1013
1014/**
1015 * v9fs_readlink - read a symlink's location (internal version) 839 * v9fs_readlink - read a symlink's location (internal version)
1016 * @dentry: dentry for symlink 840 * @dentry: dentry for symlink
1017 * @buffer: buffer to load symlink location into 841 * @buffer: buffer to load symlink location into
@@ -1050,16 +874,17 @@ static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
1050 if (!fcall) 874 if (!fcall)
1051 return -EIO; 875 return -EIO;
1052 876
1053 if (!(fcall->params.rstat.stat->mode & V9FS_DMSYMLINK)) { 877 if (!(fcall->params.rstat.stat.mode & V9FS_DMSYMLINK)) {
1054 retval = -EINVAL; 878 retval = -EINVAL;
1055 goto FreeFcall; 879 goto FreeFcall;
1056 } 880 }
1057 881
1058 /* copy extension buffer into buffer */ 882 /* copy extension buffer into buffer */
1059 if (strlen(fcall->params.rstat.stat->extension) < buflen) 883 if (fcall->params.rstat.stat.extension.len < buflen)
1060 buflen = strlen(fcall->params.rstat.stat->extension); 884 buflen = fcall->params.rstat.stat.extension.len;
1061 885
1062 memcpy(buffer, fcall->params.rstat.stat->extension, buflen + 1); 886 memcpy(buffer, fcall->params.rstat.stat.extension.str, buflen - 1);
887 buffer[buflen-1] = 0;
1063 888
1064 retval = buflen; 889 retval = buflen;
1065 890
@@ -1149,82 +974,111 @@ static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void
1149 __putname(s); 974 __putname(s);
1150} 975}
1151 976
1152/** 977static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
1153 * v9fs_vfs_link - create a hardlink 978 int mode, const char *extension)
1154 * @old_dentry: dentry for file to link to
1155 * @dir: inode destination for new link
1156 * @dentry: dentry for link
1157 *
1158 */
1159
1160/* XXX - lots of code dup'd from symlink and creates,
1161 * figure out a better reuse strategy
1162 */
1163
1164static int
1165v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
1166 struct dentry *dentry)
1167{ 979{
1168 int retval = -EPERM; 980 int err, retval;
1169 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir); 981 struct v9fs_session_info *v9ses;
1170 struct v9fs_fcall *fcall = NULL; 982 struct v9fs_fcall *fcall;
1171 struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL); 983 struct v9fs_fid *fid;
1172 struct v9fs_fid *oldfid = v9fs_fid_lookup(old_dentry); 984 struct v9fs_wstat wstat;
1173 struct v9fs_fid *newfid = NULL;
1174 char *symname = __getname();
1175 int err;
1176 985
1177 dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name, 986 v9ses = v9fs_inode2v9ses(dir);
1178 old_dentry->d_name.name); 987 retval = -EPERM;
988 fcall = NULL;
1179 989
1180 if (!v9ses->extended) { 990 if (!v9ses->extended) {
1181 dprintk(DEBUG_ERROR, "not extended\n"); 991 dprintk(DEBUG_ERROR, "not extended\n");
1182 goto FreeMem; 992 goto free_mem;
1183 } 993 }
1184 994
1185 /* get fid of old_dentry */
1186 sprintf(symname, "hardlink(%d)\n", oldfid->fid);
1187
1188 /* issue a create */ 995 /* issue a create */
1189 retval = v9fs_create(dir, dentry, V9FS_DMLINK, 0); 996 retval = v9fs_create(dir, dentry, mode, 0);
1190 if (retval != 0) 997 if (retval != 0)
1191 goto FreeMem; 998 goto free_mem;
1192 999
1193 newfid = v9fs_fid_lookup(dentry); 1000 fid = v9fs_fid_get_created(dentry);
1194 if (!newfid) { 1001 if (!fid) {
1195 dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n"); 1002 dprintk(DEBUG_ERROR, "couldn't resolve fid from dentry\n");
1196 goto FreeMem; 1003 goto free_mem;
1197 } 1004 }
1198 1005
1199 /* issue a twstat */ 1006 /* issue a Twstat */
1200 v9fs_blank_mistat(v9ses, mistat); 1007 v9fs_blank_wstat(&wstat);
1201 strcpy(mistat->data + 1, symname); 1008 wstat.muid = v9ses->name;
1202 mistat->extension = mistat->data + 1; 1009 wstat.extension = (char *) extension;
1203 retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall); 1010 retval = v9fs_t_wstat(v9ses, fid->fid, &wstat, &fcall);
1204 if (retval < 0) { 1011 if (retval < 0) {
1205 dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n", 1012 PRINT_FCALL_ERROR("wstat error", fcall);
1206 FCALL_ERROR(fcall)); 1013 goto free_mem;
1207 goto FreeMem;
1208 } 1014 }
1209 1015
1210 kfree(fcall); 1016 err = v9fs_t_clunk(v9ses, fid->fid);
1211
1212 err = v9fs_t_clunk(v9ses, newfid->fid);
1213
1214 if (err < 0) { 1017 if (err < 0) {
1215 dprintk(DEBUG_ERROR, "clunk for symlink failed: %d\n", err); 1018 dprintk(DEBUG_ERROR, "clunk failed: %d\n", err);
1216 goto FreeMem; 1019 goto free_mem;
1217 } 1020 }
1218 1021
1219 d_drop(dentry); /* FID - will this also clunk? */ 1022 d_drop(dentry); /* FID - will this also clunk? */
1220 1023
1024free_mem:
1221 kfree(fcall); 1025 kfree(fcall);
1222 fcall = NULL; 1026 return retval;
1027}
1028
1029/**
1030 * v9fs_vfs_symlink - helper function to create symlinks
1031 * @dir: directory inode containing symlink
1032 * @dentry: dentry for symlink
1033 * @symname: symlink data
1034 *
1035 * See 9P2000.u RFC for more information
1036 *
1037 */
1038
1039static int
1040v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
1041{
1042 dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
1043 symname);
1044
1045 return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname);
1046}
1047
1048/**
1049 * v9fs_vfs_link - create a hardlink
1050 * @old_dentry: dentry for file to link to
1051 * @dir: inode destination for new link
1052 * @dentry: dentry for link
1053 *
1054 */
1055
1056/* XXX - lots of code dup'd from symlink and creates,
1057 * figure out a better reuse strategy
1058 */
1059
1060static int
1061v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
1062 struct dentry *dentry)
1063{
1064 int retval;
1065 struct v9fs_fid *oldfid;
1066 char *name;
1067
1068 dprintk(DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
1069 old_dentry->d_name.name);
1070
1071 oldfid = v9fs_fid_lookup(old_dentry);
1072 if (!oldfid) {
1073 dprintk(DEBUG_ERROR, "can't find oldfid\n");
1074 return -EPERM;
1075 }
1076
1077 name = __getname();
1078 sprintf(name, "hardlink(%d)\n", oldfid->fid);
1079 retval = v9fs_vfs_mkspecial(dir, dentry, V9FS_DMLINK, name);
1080 __putname(name);
1223 1081
1224 FreeMem:
1225 kfree(mistat);
1226 kfree(fcall);
1227 __putname(symname);
1228 return retval; 1082 return retval;
1229} 1083}
1230 1084
@@ -1240,83 +1094,30 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
1240static int 1094static int
1241v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) 1095v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
1242{ 1096{
1243 int retval = -EPERM; 1097 int retval;
1244 struct v9fs_fid *newfid; 1098 char *name;
1245 struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
1246 struct v9fs_fcall *fcall = NULL;
1247 struct v9fs_stat *mistat = kmalloc(v9ses->maxdata, GFP_KERNEL);
1248 char *symname = __getname();
1249 int err;
1250 1099
1251 dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino, 1100 dprintk(DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
1252 dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev)); 1101 dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
1253 1102
1254 if (!mistat) 1103 if (!new_valid_dev(rdev))
1255 return -ENOMEM; 1104 return -EINVAL;
1256
1257 if (!new_valid_dev(rdev)) {
1258 retval = -EINVAL;
1259 goto FreeMem;
1260 }
1261
1262 if (!v9ses->extended) {
1263 dprintk(DEBUG_ERROR, "not extended\n");
1264 goto FreeMem;
1265 }
1266
1267 /* issue a create */
1268 retval = v9fs_create(dir, dentry, mode, 0);
1269
1270 if (retval != 0)
1271 goto FreeMem;
1272
1273 newfid = v9fs_fid_lookup(dentry);
1274 if (!newfid) {
1275 dprintk(DEBUG_ERROR, "coudn't resove fid from dentry\n");
1276 retval = -EINVAL;
1277 goto FreeMem;
1278 }
1279 1105
1106 name = __getname();
1280 /* build extension */ 1107 /* build extension */
1281 if (S_ISBLK(mode)) 1108 if (S_ISBLK(mode))
1282 sprintf(symname, "b %u %u", MAJOR(rdev), MINOR(rdev)); 1109 sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev));
1283 else if (S_ISCHR(mode)) 1110 else if (S_ISCHR(mode))
1284 sprintf(symname, "c %u %u", MAJOR(rdev), MINOR(rdev)); 1111 sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev));
1285 else if (S_ISFIFO(mode)) 1112 else if (S_ISFIFO(mode))
1286 ; /* DO NOTHING */ 1113 *name = 0;
1287 else { 1114 else {
1288 retval = -EINVAL; 1115 __putname(name);
1289 goto FreeMem; 1116 return -EINVAL;
1290 } 1117 }
1291 1118
1292 if (!S_ISFIFO(mode)) { 1119 retval = v9fs_vfs_mkspecial(dir, dentry, mode, name);
1293 /* issue a twstat */ 1120 __putname(name);
1294 v9fs_blank_mistat(v9ses, mistat);
1295 strcpy(mistat->data + 1, symname);
1296 mistat->extension = mistat->data + 1;
1297 retval = v9fs_t_wstat(v9ses, newfid->fid, mistat, &fcall);
1298 if (retval < 0) {
1299 dprintk(DEBUG_ERROR, "v9fs_t_wstat error: %s\n",
1300 FCALL_ERROR(fcall));
1301 goto FreeMem;
1302 }
1303 }
1304
1305 /* need to update dcache so we show up */
1306 kfree(fcall);
1307
1308 err = v9fs_t_clunk(v9ses, newfid->fid);
1309 if (err < 0) {
1310 dprintk(DEBUG_ERROR, "clunk for symlink failed: %d\n", err);
1311 goto FreeMem;
1312 }
1313
1314 d_drop(dentry); /* FID - will this also clunk? */
1315
1316 FreeMem:
1317 kfree(mistat);
1318 kfree(fcall);
1319 __putname(symname);
1320 1121
1321 return retval; 1122 return retval;
1322} 1123}