diff options
author | Latchesar Ionkov <lucho@ionkov.net> | 2006-01-08 04:05:00 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-01-08 23:14:06 -0500 |
commit | 531b1094b74365dcc55fa464d28a9a2497ae825d (patch) | |
tree | a0384dabe3be1c844166d028b3ef7c21c3dfe5fc /fs/9p/vfs_inode.c | |
parent | d8da097afb765654c866062148fd98b11db9003e (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.c | 545 |
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 | ||
46 | static struct inode_operations v9fs_dir_inode_operations; | 45 | static 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 | ||
136 | static void | 135 | static void |
137 | v9fs_blank_mistat(struct v9fs_session_info *v9ses, struct v9fs_stat *mistat) | 136 | v9fs_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 | |||
169 | static void | ||
170 | v9fs_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 | ||
868 | void | 767 | void |
869 | v9fs_mistat2inode(struct v9fs_stat *mistat, struct inode *inode, | 768 | v9fs_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 | |||
958 | static int | ||
959 | v9fs_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 | /** | 977 | static 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 | |||
1164 | static int | ||
1165 | v9fs_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 | ||
1024 | free_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 | |||
1039 | static int | ||
1040 | v9fs_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 | |||
1060 | static int | ||
1061 | v9fs_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, | |||
1240 | static int | 1094 | static int |
1241 | v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) | 1095 | v9fs_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 | } |