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