1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26#include <linux/module.h>
27#include <linux/errno.h>
28#include <linux/fs.h>
29#include <linux/file.h>
30#include <linux/pagemap.h>
31#include <linux/stat.h>
32#include <linux/string.h>
33#include <linux/inet.h>
34#include <linux/namei.h>
35#include <linux/idr.h>
36#include <linux/sched.h>
37#include <net/9p/9p.h>
38#include <net/9p/client.h>
39
40#include "v9fs.h"
41#include "v9fs_vfs.h"
42#include "fid.h"
43
44static const struct inode_operations v9fs_dir_inode_operations;
45static const struct inode_operations v9fs_dir_inode_operations_ext;
46static const struct inode_operations v9fs_file_inode_operations;
47static const struct inode_operations v9fs_symlink_inode_operations;
48
49
50
51
52
53
54
55
56static int unixmode2p9mode(struct v9fs_session_info *v9ses, int mode)
57{
58 int res;
59 res = mode & 0777;
60 if (S_ISDIR(mode))
61 res |= P9_DMDIR;
62 if (v9fs_extended(v9ses)) {
63 if (S_ISLNK(mode))
64 res |= P9_DMSYMLINK;
65 if (v9ses->nodev == 0) {
66 if (S_ISSOCK(mode))
67 res |= P9_DMSOCKET;
68 if (S_ISFIFO(mode))
69 res |= P9_DMNAMEDPIPE;
70 if (S_ISBLK(mode))
71 res |= P9_DMDEVICE;
72 if (S_ISCHR(mode))
73 res |= P9_DMDEVICE;
74 }
75
76 if ((mode & S_ISUID) == S_ISUID)
77 res |= P9_DMSETUID;
78 if ((mode & S_ISGID) == S_ISGID)
79 res |= P9_DMSETGID;
80 if ((mode & S_ISVTX) == S_ISVTX)
81 res |= P9_DMSETVTX;
82 if ((mode & P9_DMLINK))
83 res |= P9_DMLINK;
84 }
85
86 return res;
87}
88
89
90
91
92
93
94
95
96static int p9mode2unixmode(struct v9fs_session_info *v9ses, int mode)
97{
98 int res;
99
100 res = mode & 0777;
101
102 if ((mode & P9_DMDIR) == P9_DMDIR)
103 res |= S_IFDIR;
104 else if ((mode & P9_DMSYMLINK) && (v9fs_extended(v9ses)))
105 res |= S_IFLNK;
106 else if ((mode & P9_DMSOCKET) && (v9fs_extended(v9ses))
107 && (v9ses->nodev == 0))
108 res |= S_IFSOCK;
109 else if ((mode & P9_DMNAMEDPIPE) && (v9fs_extended(v9ses))
110 && (v9ses->nodev == 0))
111 res |= S_IFIFO;
112 else if ((mode & P9_DMDEVICE) && (v9fs_extended(v9ses))
113 && (v9ses->nodev == 0))
114 res |= S_IFBLK;
115 else
116 res |= S_IFREG;
117
118 if (v9fs_extended(v9ses)) {
119 if ((mode & P9_DMSETUID) == P9_DMSETUID)
120 res |= S_ISUID;
121
122 if ((mode & P9_DMSETGID) == P9_DMSETGID)
123 res |= S_ISGID;
124
125 if ((mode & P9_DMSETVTX) == P9_DMSETVTX)
126 res |= S_ISVTX;
127 }
128
129 return res;
130}
131
132
133
134
135
136
137
138int v9fs_uflags2omode(int uflags, int extended)
139{
140 int ret;
141
142 ret = 0;
143 switch (uflags&3) {
144 default:
145 case O_RDONLY:
146 ret = P9_OREAD;
147 break;
148
149 case O_WRONLY:
150 ret = P9_OWRITE;
151 break;
152
153 case O_RDWR:
154 ret = P9_ORDWR;
155 break;
156 }
157
158 if (uflags & O_TRUNC)
159 ret |= P9_OTRUNC;
160
161 if (extended) {
162 if (uflags & O_EXCL)
163 ret |= P9_OEXCL;
164
165 if (uflags & O_APPEND)
166 ret |= P9_OAPPEND;
167 }
168
169 return ret;
170}
171
172
173
174
175
176
177
178
179static void
180v9fs_blank_wstat(struct p9_wstat *wstat)
181{
182 wstat->type = ~0;
183 wstat->dev = ~0;
184 wstat->qid.type = ~0;
185 wstat->qid.version = ~0;
186 *((long long *)&wstat->qid.path) = ~0;
187 wstat->mode = ~0;
188 wstat->atime = ~0;
189 wstat->mtime = ~0;
190 wstat->length = ~0;
191 wstat->name = NULL;
192 wstat->uid = NULL;
193 wstat->gid = NULL;
194 wstat->muid = NULL;
195 wstat->n_uid = ~0;
196 wstat->n_gid = ~0;
197 wstat->n_muid = ~0;
198 wstat->extension = NULL;
199}
200
201
202
203
204
205
206
207
208struct inode *v9fs_get_inode(struct super_block *sb, int mode)
209{
210 struct inode *inode;
211 struct v9fs_session_info *v9ses = sb->s_fs_info;
212
213 P9_DPRINTK(P9_DEBUG_VFS, "super block: %p mode: %o\n", sb, mode);
214
215 inode = new_inode(sb);
216 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");
266 return ERR_PTR(-ENOMEM);
267 }
268 return inode;
269}
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331static struct inode *
332v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
333 struct super_block *sb)
334{
335 int err, umode;
336 struct inode *ret;
337 struct p9_stat *st;
338
339 ret = NULL;
340 st = p9_client_stat(fid);
341 if (IS_ERR(st)) {
342 err = PTR_ERR(st);
343 st = NULL;
344 goto error;
345 }
346
347 umode = p9mode2unixmode(v9ses, st->mode);
348 ret = v9fs_get_inode(sb, umode);
349 if (IS_ERR(ret)) {
350 err = PTR_ERR(ret);
351 ret = NULL;
352 goto error;
353 }
354
355 v9fs_stat2inode(st, ret, sb);
356 ret->i_ino = v9fs_qid2ino(&st->qid);
357 kfree(st);
358 return ret;
359
360error:
361 kfree(st);
362 if (ret)
363 iput(ret);
364
365 return ERR_PTR(err);
366}
367
368
369
370
371
372
373
374
375
376static int v9fs_remove(struct inode *dir, struct dentry *file, int rmdir)
377{
378 struct inode *file_inode;
379 struct v9fs_session_info *v9ses;
380 struct p9_fid *v9fid;
381
382 P9_DPRINTK(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %d\n", dir, file,
383 rmdir);
384
385 file_inode = file->d_inode;
386 v9ses = v9fs_inode2v9ses(file_inode);
387 v9fid = v9fs_fid_clone(file);
388 if (IS_ERR(v9fid))
389 return PTR_ERR(v9fid);
390
391 return p9_client_remove(v9fid);
392}
393
394static int
395v9fs_open_created(struct inode *inode, struct file *file)
396{
397 return 0;
398}
399
400
401
402
403
404
405
406
407
408
409
410
411static struct p9_fid *
412v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
413 struct dentry *dentry, char *extension, u32 perm, u8 mode)
414{
415 int err;
416 char *name;
417 struct p9_fid *dfid, *ofid, *fid;
418 struct inode *inode;
419
420 err = 0;
421 ofid = NULL;
422 fid = NULL;
423 name = (char *) dentry->d_name.name;
424 dfid = v9fs_fid_clone(dentry->d_parent);
425 if (IS_ERR(dfid)) {
426 err = PTR_ERR(dfid);
427 dfid = NULL;
428 goto error;
429 }
430
431
432 ofid = p9_client_walk(dfid, 0, NULL, 1);
433 if (IS_ERR(ofid)) {
434 err = PTR_ERR(ofid);
435 ofid = NULL;
436 goto error;
437 }
438
439 err = p9_client_fcreate(ofid, name, perm, mode, extension);
440 if (err < 0)
441 goto error;
442
443
444 fid = p9_client_walk(dfid, 1, &name, 0);
445 if (IS_ERR(fid)) {
446 err = PTR_ERR(fid);
447 fid = NULL;
448 goto error;
449 } else
450 dfid = NULL;
451
452
453 inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
454 if (IS_ERR(inode)) {
455 err = PTR_ERR(inode);
456 goto error;
457 }
458
459 if (v9ses->cache)
460 dentry->d_op = &v9fs_cached_dentry_operations;
461 else
462 dentry->d_op = &v9fs_dentry_operations;
463
464 d_instantiate(dentry, inode);
465 v9fs_fid_add(dentry, fid);
466 return ofid;
467
468error:
469 if (dfid)
470 p9_client_clunk(dfid);
471
472 if (ofid)
473 p9_client_clunk(ofid);
474
475 if (fid)
476 p9_client_clunk(fid);
477
478 return ERR_PTR(err);
479}
480
481
482
483
484
485
486
487
488
489
490static int
491v9fs_vfs_create(struct inode *dir, struct dentry *dentry, int mode,
492 struct nameidata *nd)
493{
494 int err;
495 u32 perm;
496 int flags;
497 struct v9fs_session_info *v9ses;
498 struct p9_fid *fid;
499 struct file *filp;
500
501 err = 0;
502 fid = NULL;
503 v9ses = v9fs_inode2v9ses(dir);
504 perm = unixmode2p9mode(v9ses, mode);
505 if (nd && nd->flags & LOOKUP_OPEN)
506 flags = nd->intent.open.flags - 1;
507 else
508 flags = O_RDWR;
509
510 fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
511 v9fs_uflags2omode(flags, v9fs_extended(v9ses)));
512 if (IS_ERR(fid)) {
513 err = PTR_ERR(fid);
514 fid = NULL;
515 goto error;
516 }
517
518
519 if (nd && nd->flags & LOOKUP_OPEN) {
520 filp = lookup_instantiate_filp(nd, dentry, v9fs_open_created);
521 if (IS_ERR(filp)) {
522 err = PTR_ERR(filp);
523 goto error;
524 }
525
526 filp->private_data = fid;
527 } else
528 p9_client_clunk(fid);
529
530 return 0;
531
532error:
533 if (fid)
534 p9_client_clunk(fid);
535
536 return err;
537}
538
539
540
541
542
543
544
545
546
547static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
548{
549 int err;
550 u32 perm;
551 struct v9fs_session_info *v9ses;
552 struct p9_fid *fid;
553
554 P9_DPRINTK(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
555 err = 0;
556 v9ses = v9fs_inode2v9ses(dir);
557 perm = unixmode2p9mode(v9ses, mode | S_IFDIR);
558 fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_OREAD);
559 if (IS_ERR(fid)) {
560 err = PTR_ERR(fid);
561 fid = NULL;
562 }
563
564 if (fid)
565 p9_client_clunk(fid);
566
567 return err;
568}
569
570
571
572
573
574
575
576
577
578static struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
579 struct nameidata *nameidata)
580{
581 struct super_block *sb;
582 struct v9fs_session_info *v9ses;
583 struct p9_fid *dfid, *fid;
584 struct inode *inode;
585 char *name;
586 int result = 0;
587
588 P9_DPRINTK(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p nameidata: %p\n",
589 dir, dentry->d_name.name, dentry, nameidata);
590
591 sb = dir->i_sb;
592 v9ses = v9fs_inode2v9ses(dir);
593 dfid = v9fs_fid_lookup(dentry->d_parent);
594 if (IS_ERR(dfid))
595 return ERR_CAST(dfid);
596
597 name = (char *) dentry->d_name.name;
598 fid = p9_client_walk(dfid, 1, &name, 1);
599 if (IS_ERR(fid)) {
600 result = PTR_ERR(fid);
601 if (result == -ENOENT) {
602 d_add(dentry, NULL);
603 return NULL;
604 }
605
606 return ERR_PTR(result);
607 }
608
609 inode = v9fs_inode_from_fid(v9ses, fid, dir->i_sb);
610 if (IS_ERR(inode)) {
611 result = PTR_ERR(inode);
612 inode = NULL;
613 goto error;
614 }
615
616 result = v9fs_fid_add(dentry, fid);
617 if (result < 0)
618 goto error;
619
620 if ((fid->qid.version) && (v9ses->cache))
621 dentry->d_op = &v9fs_cached_dentry_operations;
622 else
623 dentry->d_op = &v9fs_dentry_operations;
624
625 d_add(dentry, inode);
626 return NULL;
627
628error:
629 if (fid)
630 p9_client_clunk(fid);
631
632 return ERR_PTR(result);
633}
634
635
636
637
638
639
640
641
642static int v9fs_vfs_unlink(struct inode *i, struct dentry *d)
643{
644 return v9fs_remove(i, d, 0);
645}
646
647
648
649
650
651
652
653
654static int v9fs_vfs_rmdir(struct inode *i, struct dentry *d)
655{
656 return v9fs_remove(i, d, 1);
657}
658
659
660
661
662
663
664
665
666
667
668static int
669v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
670 struct inode *new_dir, struct dentry *new_dentry)
671{
672 struct inode *old_inode;
673 struct v9fs_session_info *v9ses;
674 struct p9_fid *oldfid;
675 struct p9_fid *olddirfid;
676 struct p9_fid *newdirfid;
677 struct p9_wstat wstat;
678 int retval;
679
680 P9_DPRINTK(P9_DEBUG_VFS, "\n");
681 retval = 0;
682 old_inode = old_dentry->d_inode;
683 v9ses = v9fs_inode2v9ses(old_inode);
684 oldfid = v9fs_fid_lookup(old_dentry);
685 if (IS_ERR(oldfid))
686 return PTR_ERR(oldfid);
687
688 olddirfid = v9fs_fid_clone(old_dentry->d_parent);
689 if (IS_ERR(olddirfid)) {
690 retval = PTR_ERR(olddirfid);
691 goto done;
692 }
693
694 newdirfid = v9fs_fid_clone(new_dentry->d_parent);
695 if (IS_ERR(newdirfid)) {
696 retval = PTR_ERR(newdirfid);
697 goto clunk_olddir;
698 }
699
700
701 if (memcmp(&olddirfid->qid, &newdirfid->qid, sizeof(newdirfid->qid))) {
702 P9_DPRINTK(P9_DEBUG_ERROR,
703 "old dir and new dir are different\n");
704 retval = -EXDEV;
705 goto clunk_newdir;
706 }
707
708 v9fs_blank_wstat(&wstat);
709 wstat.muid = v9ses->uname;
710 wstat.name = (char *) new_dentry->d_name.name;
711 retval = p9_client_wstat(oldfid, &wstat);
712
713clunk_newdir:
714 p9_client_clunk(newdirfid);
715
716clunk_olddir:
717 p9_client_clunk(olddirfid);
718
719done:
720 return retval;
721}
722
723
724
725
726
727
728
729
730
731static int
732v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
733 struct kstat *stat)
734{
735 int err;
736 struct v9fs_session_info *v9ses;
737 struct p9_fid *fid;
738 struct p9_stat *st;
739
740 P9_DPRINTK(P9_DEBUG_VFS, "dentry: %p\n", dentry);
741 err = -EPERM;
742 v9ses = v9fs_inode2v9ses(dentry->d_inode);
743 if (v9ses->cache == CACHE_LOOSE)
744 return simple_getattr(mnt, dentry, stat);
745
746 fid = v9fs_fid_lookup(dentry);
747 if (IS_ERR(fid))
748 return PTR_ERR(fid);
749
750 st = p9_client_stat(fid);
751 if (IS_ERR(st))
752 return PTR_ERR(st);
753
754 v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb);
755 generic_fillattr(dentry->d_inode, stat);
756
757 kfree(st);
758 return 0;
759}
760
761
762
763
764
765
766
767
768static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
769{
770 int retval;
771 struct v9fs_session_info *v9ses;
772 struct p9_fid *fid;
773 struct p9_wstat wstat;
774
775 P9_DPRINTK(P9_DEBUG_VFS, "\n");
776 retval = -EPERM;
777 v9ses = v9fs_inode2v9ses(dentry->d_inode);
778 fid = v9fs_fid_lookup(dentry);
779 if(IS_ERR(fid))
780 return PTR_ERR(fid);
781
782 v9fs_blank_wstat(&wstat);
783 if (iattr->ia_valid & ATTR_MODE)
784 wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode);
785
786 if (iattr->ia_valid & ATTR_MTIME)
787 wstat.mtime = iattr->ia_mtime.tv_sec;
788
789 if (iattr->ia_valid & ATTR_ATIME)
790 wstat.atime = iattr->ia_atime.tv_sec;
791
792 if (iattr->ia_valid & ATTR_SIZE)
793 wstat.length = iattr->ia_size;
794
795 if (v9fs_extended(v9ses)) {
796 if (iattr->ia_valid & ATTR_UID)
797 wstat.n_uid = iattr->ia_uid;
798
799 if (iattr->ia_valid & ATTR_GID)
800 wstat.n_gid = iattr->ia_gid;
801 }
802
803 retval = p9_client_wstat(fid, &wstat);
804 if (retval >= 0)
805 retval = inode_setattr(dentry->d_inode, iattr);
806
807 return retval;
808}
809
810
811
812
813
814
815
816
817
818void
819v9fs_stat2inode(struct p9_stat *stat, struct inode *inode,
820 struct super_block *sb)
821{
822 int n;
823 char ext[32];
824 struct v9fs_session_info *v9ses = sb->s_fs_info;
825
826 inode->i_nlink = 1;
827
828 inode->i_atime.tv_sec = stat->atime;
829 inode->i_mtime.tv_sec = stat->mtime;
830 inode->i_ctime.tv_sec = stat->mtime;
831
832 inode->i_uid = v9ses->dfltuid;
833 inode->i_gid = v9ses->dfltgid;
834
835 if (v9fs_extended(v9ses)) {
836 inode->i_uid = stat->n_uid;
837 inode->i_gid = stat->n_gid;
838 }
839
840 inode->i_mode = p9mode2unixmode(v9ses, stat->mode);
841 if ((S_ISBLK(inode->i_mode)) || (S_ISCHR(inode->i_mode))) {
842 char type = 0;
843 int major = -1;
844 int minor = -1;
845
846 n = stat->extension.len;
847 if (n > sizeof(ext)-1)
848 n = sizeof(ext)-1;
849 memmove(ext, stat->extension.str, n);
850 ext[n] = 0;
851 sscanf(ext, "%c %u %u", &type, &major, &minor);
852 switch (type) {
853 case 'c':
854 inode->i_mode &= ~S_IFBLK;
855 inode->i_mode |= S_IFCHR;
856 break;
857 case 'b':
858 break;
859 default:
860 P9_DPRINTK(P9_DEBUG_ERROR,
861 "Unknown special type %c (%.*s)\n", type,
862 stat->extension.len, stat->extension.str);
863 };
864 inode->i_rdev = MKDEV(major, minor);
865 } else
866 inode->i_rdev = 0;
867
868 inode->i_size = stat->length;
869
870
871 inode->i_blocks = (inode->i_size + 512 - 1) >> 9;
872}
873
874
875
876
877
878
879
880
881ino_t v9fs_qid2ino(struct p9_qid *qid)
882{
883 u64 path = qid->path + 2;
884 ino_t i = 0;
885
886 if (sizeof(ino_t) == sizeof(path))
887 memcpy(&i, &path, sizeof(ino_t));
888 else
889 i = (ino_t) (path ^ (path >> 32));
890
891 return i;
892}
893
894
895
896
897
898
899
900
901
902static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
903{
904 int retval;
905
906 struct v9fs_session_info *v9ses;
907 struct p9_fid *fid;
908 struct p9_stat *st;
909
910 P9_DPRINTK(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
911 retval = -EPERM;
912 v9ses = v9fs_inode2v9ses(dentry->d_inode);
913 fid = v9fs_fid_lookup(dentry);
914 if (IS_ERR(fid))
915 return PTR_ERR(fid);
916
917 if (!v9fs_extended(v9ses))
918 return -EBADF;
919
920 st = p9_client_stat(fid);
921 if (IS_ERR(st))
922 return PTR_ERR(st);
923
924 if (!(st->mode & P9_DMSYMLINK)) {
925 retval = -EINVAL;
926 goto done;
927 }
928
929
930 if (st->extension.len < buflen)
931 buflen = st->extension.len + 1;
932
933 memmove(buffer, st->extension.str, buflen - 1);
934 buffer[buflen-1] = 0;
935
936 P9_DPRINTK(P9_DEBUG_VFS,
937 "%s -> %.*s (%s)\n", dentry->d_name.name, st->extension.len,
938 st->extension.str, buffer);
939
940 retval = buflen;
941
942done:
943 kfree(st);
944 return retval;
945}
946
947
948
949
950
951
952
953
954
955static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer,
956 int buflen)
957{
958 int retval;
959 int ret;
960 char *link = __getname();
961
962 if (unlikely(!link))
963 return -ENOMEM;
964
965 if (buflen > PATH_MAX)
966 buflen = PATH_MAX;
967
968 P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_iname, dentry);
969
970 retval = v9fs_readlink(dentry, link, buflen);
971
972 if (retval > 0) {
973 if ((ret = copy_to_user(buffer, link, retval)) != 0) {
974 P9_DPRINTK(P9_DEBUG_ERROR,
975 "problem copying to user: %d\n", ret);
976 retval = ret;
977 }
978 }
979
980 __putname(link);
981 return retval;
982}
983
984
985
986
987
988
989
990
991static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
992{
993 int len = 0;
994 char *link = __getname();
995
996 P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name);
997
998 if (!link)
999 link = ERR_PTR(-ENOMEM);
1000 else {
1001 len = v9fs_readlink(dentry, link, PATH_MAX);
1002
1003 if (len < 0) {
1004 __putname(link);
1005 link = ERR_PTR(len);
1006 } else
1007 link[len] = 0;
1008 }
1009 nd_set_link(nd, link);
1010
1011 return NULL;
1012}
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022static void
1023v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
1024{
1025 char *s = nd_get_link(nd);
1026
1027 P9_DPRINTK(P9_DEBUG_VFS, " %s %s\n", dentry->d_name.name, s);
1028 if (!IS_ERR(s))
1029 __putname(s);
1030}
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
1042 int mode, const char *extension)
1043{
1044 u32 perm;
1045 struct v9fs_session_info *v9ses;
1046 struct p9_fid *fid;
1047
1048 v9ses = v9fs_inode2v9ses(dir);
1049 if (!v9fs_extended(v9ses)) {
1050 P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n");
1051 return -EPERM;
1052 }
1053
1054 perm = unixmode2p9mode(v9ses, mode);
1055 fid = v9fs_create(v9ses, dir, dentry, (char *) extension, perm,
1056 P9_OREAD);
1057 if (IS_ERR(fid))
1058 return PTR_ERR(fid);
1059
1060 p9_client_clunk(fid);
1061 return 0;
1062}
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074static int
1075v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
1076{
1077 P9_DPRINTK(P9_DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino,
1078 dentry->d_name.name, symname);
1079
1080 return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname);
1081}
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091static int
1092v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
1093 struct dentry *dentry)
1094{
1095 int retval;
1096 struct p9_fid *oldfid;
1097 char *name;
1098
1099 P9_DPRINTK(P9_DEBUG_VFS,
1100 " %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
1101 old_dentry->d_name.name);
1102
1103 oldfid = v9fs_fid_clone(old_dentry);
1104 if (IS_ERR(oldfid))
1105 return PTR_ERR(oldfid);
1106
1107 name = __getname();
1108 if (unlikely(!name)) {
1109 retval = -ENOMEM;
1110 goto clunk_fid;
1111 }
1112
1113 sprintf(name, "%d\n", oldfid->fid);
1114 retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name);
1115 __putname(name);
1116
1117clunk_fid:
1118 p9_client_clunk(oldfid);
1119 return retval;
1120}
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131static int
1132v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
1133{
1134 int retval;
1135 char *name;
1136
1137 P9_DPRINTK(P9_DEBUG_VFS,
1138 " %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
1139 dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
1140
1141 if (!new_valid_dev(rdev))
1142 return -EINVAL;
1143
1144 name = __getname();
1145 if (!name)
1146 return -ENOMEM;
1147
1148 if (S_ISBLK(mode))
1149 sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev));
1150 else if (S_ISCHR(mode))
1151 sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev));
1152 else if (S_ISFIFO(mode))
1153 *name = 0;
1154 else {
1155 __putname(name);
1156 return -EINVAL;
1157 }
1158
1159 retval = v9fs_vfs_mkspecial(dir, dentry, mode, name);
1160 __putname(name);
1161
1162 return retval;
1163}
1164
1165static const struct inode_operations v9fs_dir_inode_operations_ext = {
1166 .create = v9fs_vfs_create,
1167 .lookup = v9fs_vfs_lookup,
1168 .symlink = v9fs_vfs_symlink,
1169 .link = v9fs_vfs_link,
1170 .unlink = v9fs_vfs_unlink,
1171 .mkdir = v9fs_vfs_mkdir,
1172 .rmdir = v9fs_vfs_rmdir,
1173 .mknod = v9fs_vfs_mknod,
1174 .rename = v9fs_vfs_rename,
1175 .readlink = v9fs_vfs_readlink,
1176 .getattr = v9fs_vfs_getattr,
1177 .setattr = v9fs_vfs_setattr,
1178};
1179
1180static const struct inode_operations v9fs_dir_inode_operations = {
1181 .create = v9fs_vfs_create,
1182 .lookup = v9fs_vfs_lookup,
1183 .unlink = v9fs_vfs_unlink,
1184 .mkdir = v9fs_vfs_mkdir,
1185 .rmdir = v9fs_vfs_rmdir,
1186 .mknod = v9fs_vfs_mknod,
1187 .rename = v9fs_vfs_rename,
1188 .getattr = v9fs_vfs_getattr,
1189 .setattr = v9fs_vfs_setattr,
1190};
1191
1192static const struct inode_operations v9fs_file_inode_operations = {
1193 .getattr = v9fs_vfs_getattr,
1194 .setattr = v9fs_vfs_setattr,
1195};
1196
1197static const struct inode_operations v9fs_symlink_inode_operations = {
1198 .readlink = v9fs_vfs_readlink,
1199 .follow_link = v9fs_vfs_follow_link,
1200 .put_link = v9fs_vfs_put_link,
1201 .getattr = v9fs_vfs_getattr,
1202 .setattr = v9fs_vfs_setattr,
1203};
1204