xref: /openbmc/linux/fs/9p/vfs_inode.c (revision e8e0929d)
1 /*
2  *  linux/fs/9p/vfs_inode.c
3  *
4  * This file contains vfs inode ops for the 9P2000 protocol.
5  *
6  *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
7  *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
8  *
9  *  This program is free software; you can redistribute it and/or modify
10  *  it under the terms of the GNU General Public License version 2
11  *  as published by the Free Software Foundation.
12  *
13  *  This program is distributed in the hope that it will be useful,
14  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  *  GNU General Public License for more details.
17  *
18  *  You should have received a copy of the GNU General Public License
19  *  along with this program; if not, write to:
20  *  Free Software Foundation
21  *  51 Franklin Street, Fifth Floor
22  *  Boston, MA  02111-1301  USA
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 
45 static const struct inode_operations v9fs_dir_inode_operations;
46 static const struct inode_operations v9fs_dir_inode_operations_ext;
47 static const struct inode_operations v9fs_file_inode_operations;
48 static const struct inode_operations v9fs_symlink_inode_operations;
49 
50 /**
51  * unixmode2p9mode - convert unix mode bits to plan 9
52  * @v9ses: v9fs session information
53  * @mode: mode to convert
54  *
55  */
56 
57 static 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  * p9mode2unixmode- convert plan9 mode bits to unix mode bits
92  * @v9ses: v9fs session information
93  * @mode: mode to convert
94  *
95  */
96 
97 static 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  * v9fs_uflags2omode- convert posix open flags to plan 9 mode bits
135  * @uflags: flags to convert
136  * @extended: if .u extensions are active
137  */
138 
139 int 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  * v9fs_blank_wstat - helper function to setup a 9P stat structure
175  * @wstat: structure to initialize
176  *
177  */
178 
179 static void
180 v9fs_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  * v9fs_alloc_inode - helper function to allocate an inode
204  * This callback is executed before setting up the inode so that we
205  * can associate a vcookie with each inode.
206  *
207  */
208 
209 struct 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  * v9fs_destroy_inode - destroy an inode
225  *
226  */
227 
228 void v9fs_destroy_inode(struct inode *inode)
229 {
230 	kmem_cache_free(vcookie_cache, v9fs_inode2cookie(inode));
231 }
232 #endif
233 
234 /**
235  * v9fs_get_inode - helper function to setup an inode
236  * @sb: superblock
237  * @mode: mode to setup inode with
238  *
239  */
240 
241 struct 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 
306 error:
307 	iput(inode);
308 	return ERR_PTR(err);
309 }
310 
311 /*
312 static struct v9fs_fid*
313 v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry)
314 {
315 	int err;
316 	int nfid;
317 	struct v9fs_fid *ret;
318 	struct v9fs_fcall *fcall;
319 
320 	nfid = v9fs_get_idpool(&v9ses->fidpool);
321 	if (nfid < 0) {
322 		eprintk(KERN_WARNING, "no free fids available\n");
323 		return ERR_PTR(-ENOSPC);
324 	}
325 
326 	err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name,
327 		&fcall);
328 
329 	if (err < 0) {
330 		if (fcall && fcall->id == RWALK)
331 			goto clunk_fid;
332 
333 		PRINT_FCALL_ERROR("walk error", fcall);
334 		v9fs_put_idpool(nfid, &v9ses->fidpool);
335 		goto error;
336 	}
337 
338 	kfree(fcall);
339 	fcall = NULL;
340 	ret = v9fs_fid_create(v9ses, nfid);
341 	if (!ret) {
342 		err = -ENOMEM;
343 		goto clunk_fid;
344 	}
345 
346 	err = v9fs_fid_insert(ret, dentry);
347 	if (err < 0) {
348 		v9fs_fid_destroy(ret);
349 		goto clunk_fid;
350 	}
351 
352 	return ret;
353 
354 clunk_fid:
355 	v9fs_t_clunk(v9ses, nfid);
356 
357 error:
358 	kfree(fcall);
359 	return ERR_PTR(err);
360 }
361 */
362 
363 
364 /**
365  * v9fs_clear_inode - release an inode
366  * @inode: inode to release
367  *
368  */
369 void 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  * v9fs_inode_from_fid - populate an inode by issuing a attribute request
380  * @v9ses: session information
381  * @fid: fid to issue attribute request for
382  * @sb: superblock on which to create inode
383  *
384  */
385 
386 static struct inode *
387 v9fs_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 
418 error:
419 	p9stat_free(st);
420 	kfree(st);
421 	return ERR_PTR(err);
422 }
423 
424 /**
425  * v9fs_remove - helper function to remove files and directories
426  * @dir: directory inode that is being deleted
427  * @file:  dentry that is being deleted
428  * @rmdir: removing a directory
429  *
430  */
431 
432 static 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 
450 static int
451 v9fs_open_created(struct inode *inode, struct file *file)
452 {
453 	return 0;
454 }
455 
456 
457 /**
458  * v9fs_create - Create a file
459  * @v9ses: session information
460  * @dir: directory that dentry is being created in
461  * @dentry:  dentry that is being created
462  * @extension: 9p2000.u extension string to support devices, etc.
463  * @perm: create permissions
464  * @mode: open mode
465  *
466  */
467 static struct p9_fid *
468 v9fs_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 	/* clone a fid to use for creation */
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 	/* now walk from the parent so we can get unopened fid */
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 	/* instantiate inode and assign the unopened fid to the dentry */
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 
535 error:
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  * v9fs_vfs_create - VFS hook to create files
550  * @dir: directory inode that is being created
551  * @dentry:  dentry that is being deleted
552  * @mode: create permissions
553  * @nd: path information
554  *
555  */
556 
557 static int
558 v9fs_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 	/* if we are opening a file, assign the open fid to the file */
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 
599 error:
600 	if (fid)
601 		p9_client_clunk(fid);
602 
603 	return err;
604 }
605 
606 /**
607  * v9fs_vfs_mkdir - VFS mkdir hook to create a directory
608  * @dir:  inode that is being unlinked
609  * @dentry: dentry that is being unlinked
610  * @mode: mode for new directory
611  *
612  */
613 
614 static 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  * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode
639  * @dir:  inode that is being walked from
640  * @dentry: dentry that is being walked to?
641  * @nameidata: path data
642  *
643  */
644 
645 static 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 
695 error:
696 	p9_client_clunk(fid);
697 
698 	return ERR_PTR(result);
699 }
700 
701 /**
702  * v9fs_vfs_unlink - VFS unlink hook to delete an inode
703  * @i:  inode that is being unlinked
704  * @d: dentry that is being unlinked
705  *
706  */
707 
708 static int v9fs_vfs_unlink(struct inode *i, struct dentry *d)
709 {
710 	return v9fs_remove(i, d, 0);
711 }
712 
713 /**
714  * v9fs_vfs_rmdir - VFS unlink hook to delete a directory
715  * @i:  inode that is being unlinked
716  * @d: dentry that is being unlinked
717  *
718  */
719 
720 static int v9fs_vfs_rmdir(struct inode *i, struct dentry *d)
721 {
722 	return v9fs_remove(i, d, 1);
723 }
724 
725 /**
726  * v9fs_vfs_rename - VFS hook to rename an inode
727  * @old_dir:  old dir inode
728  * @old_dentry: old dentry
729  * @new_dir: new dir inode
730  * @new_dentry: new dentry
731  *
732  */
733 
734 static int
735 v9fs_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 	/* 9P can only handle file rename in the same directory */
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 
779 clunk_newdir:
780 	p9_client_clunk(newdirfid);
781 
782 clunk_olddir:
783 	p9_client_clunk(olddirfid);
784 
785 done:
786 	return retval;
787 }
788 
789 /**
790  * v9fs_vfs_getattr - retrieve file metadata
791  * @mnt: mount information
792  * @dentry: file to get attributes on
793  * @stat: metadata structure to populate
794  *
795  */
796 
797 static int
798 v9fs_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  * v9fs_vfs_setattr - set file metadata
829  * @dentry: file whose metadata to set
830  * @iattr: metadata assignment structure
831  *
832  */
833 
834 static 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  * v9fs_stat2inode - populate an inode structure with mistat info
878  * @stat: Plan 9 metadata (mistat) structure
879  * @inode: inode to populate
880  * @sb: superblock of filesystem
881  *
882  */
883 
884 void
885 v9fs_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 	/* not real number of blocks, but 512 byte ones ... */
933 	inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
934 }
935 
936 /**
937  * v9fs_qid2ino - convert qid into inode number
938  * @qid: qid to hash
939  *
940  * BUG: potential for inode number collisions?
941  */
942 
943 ino_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  * v9fs_readlink - read a symlink's location (internal version)
958  * @dentry: dentry for symlink
959  * @buffer: buffer to load symlink location into
960  * @buflen: length of buffer
961  *
962  */
963 
964 static 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 	/* copy extension buffer into buffer */
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 = buflen;
998 
999 done:
1000 	kfree(st);
1001 	return retval;
1002 }
1003 
1004 /**
1005  * v9fs_vfs_readlink - read a symlink's location
1006  * @dentry: dentry for symlink
1007  * @buffer: buffer to load symlink location into
1008  * @buflen: length of buffer
1009  *
1010  */
1011 
1012 static int v9fs_vfs_readlink(struct dentry *dentry, char __user * buffer,
1013 			     int buflen)
1014 {
1015 	int retval;
1016 	int ret;
1017 	char *link = __getname();
1018 
1019 	if (unlikely(!link))
1020 		return -ENOMEM;
1021 
1022 	if (buflen > PATH_MAX)
1023 		buflen = PATH_MAX;
1024 
1025 	P9_DPRINTK(P9_DEBUG_VFS, " dentry: %s (%p)\n", dentry->d_name.name,
1026 									dentry);
1027 
1028 	retval = v9fs_readlink(dentry, link, buflen);
1029 
1030 	if (retval > 0) {
1031 		if ((ret = copy_to_user(buffer, link, retval)) != 0) {
1032 			P9_DPRINTK(P9_DEBUG_ERROR,
1033 					"problem copying to user: %d\n", ret);
1034 			retval = ret;
1035 		}
1036 	}
1037 
1038 	__putname(link);
1039 	return retval;
1040 }
1041 
1042 /**
1043  * v9fs_vfs_follow_link - follow a symlink path
1044  * @dentry: dentry for symlink
1045  * @nd: nameidata
1046  *
1047  */
1048 
1049 static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
1050 {
1051 	int len = 0;
1052 	char *link = __getname();
1053 
1054 	P9_DPRINTK(P9_DEBUG_VFS, "%s n", dentry->d_name.name);
1055 
1056 	if (!link)
1057 		link = ERR_PTR(-ENOMEM);
1058 	else {
1059 		len = v9fs_readlink(dentry, link, PATH_MAX);
1060 
1061 		if (len < 0) {
1062 			__putname(link);
1063 			link = ERR_PTR(len);
1064 		} else
1065 			link[len] = 0;
1066 	}
1067 	nd_set_link(nd, link);
1068 
1069 	return NULL;
1070 }
1071 
1072 /**
1073  * v9fs_vfs_put_link - release a symlink path
1074  * @dentry: dentry for symlink
1075  * @nd: nameidata
1076  * @p: unused
1077  *
1078  */
1079 
1080 static void
1081 v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
1082 {
1083 	char *s = nd_get_link(nd);
1084 
1085 	P9_DPRINTK(P9_DEBUG_VFS, " %s %s\n", dentry->d_name.name,
1086 		IS_ERR(s) ? "<error>" : s);
1087 	if (!IS_ERR(s))
1088 		__putname(s);
1089 }
1090 
1091 /**
1092  * v9fs_vfs_mkspecial - create a special file
1093  * @dir: inode to create special file in
1094  * @dentry: dentry to create
1095  * @mode: mode to create special file
1096  * @extension: 9p2000.u format extension string representing special file
1097  *
1098  */
1099 
1100 static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
1101 	int mode, const char *extension)
1102 {
1103 	u32 perm;
1104 	struct v9fs_session_info *v9ses;
1105 	struct p9_fid *fid;
1106 
1107 	v9ses = v9fs_inode2v9ses(dir);
1108 	if (!v9fs_extended(v9ses)) {
1109 		P9_DPRINTK(P9_DEBUG_ERROR, "not extended\n");
1110 		return -EPERM;
1111 	}
1112 
1113 	perm = unixmode2p9mode(v9ses, mode);
1114 	fid = v9fs_create(v9ses, dir, dentry, (char *) extension, perm,
1115 								P9_OREAD);
1116 	if (IS_ERR(fid))
1117 		return PTR_ERR(fid);
1118 
1119 	p9_client_clunk(fid);
1120 	return 0;
1121 }
1122 
1123 /**
1124  * v9fs_vfs_symlink - helper function to create symlinks
1125  * @dir: directory inode containing symlink
1126  * @dentry: dentry for symlink
1127  * @symname: symlink data
1128  *
1129  * See Also: 9P2000.u RFC for more information
1130  *
1131  */
1132 
1133 static int
1134 v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
1135 {
1136 	P9_DPRINTK(P9_DEBUG_VFS, " %lu,%s,%s\n", dir->i_ino,
1137 					dentry->d_name.name, symname);
1138 
1139 	return v9fs_vfs_mkspecial(dir, dentry, S_IFLNK, symname);
1140 }
1141 
1142 /**
1143  * v9fs_vfs_link - create a hardlink
1144  * @old_dentry: dentry for file to link to
1145  * @dir: inode destination for new link
1146  * @dentry: dentry for link
1147  *
1148  */
1149 
1150 static int
1151 v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
1152 	      struct dentry *dentry)
1153 {
1154 	int retval;
1155 	struct p9_fid *oldfid;
1156 	char *name;
1157 
1158 	P9_DPRINTK(P9_DEBUG_VFS,
1159 		" %lu,%s,%s\n", dir->i_ino, dentry->d_name.name,
1160 		old_dentry->d_name.name);
1161 
1162 	oldfid = v9fs_fid_clone(old_dentry);
1163 	if (IS_ERR(oldfid))
1164 		return PTR_ERR(oldfid);
1165 
1166 	name = __getname();
1167 	if (unlikely(!name)) {
1168 		retval = -ENOMEM;
1169 		goto clunk_fid;
1170 	}
1171 
1172 	sprintf(name, "%d\n", oldfid->fid);
1173 	retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name);
1174 	__putname(name);
1175 
1176 clunk_fid:
1177 	p9_client_clunk(oldfid);
1178 	return retval;
1179 }
1180 
1181 /**
1182  * v9fs_vfs_mknod - create a special file
1183  * @dir: inode destination for new link
1184  * @dentry: dentry for file
1185  * @mode: mode for creation
1186  * @rdev: device associated with special file
1187  *
1188  */
1189 
1190 static int
1191 v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
1192 {
1193 	int retval;
1194 	char *name;
1195 
1196 	P9_DPRINTK(P9_DEBUG_VFS,
1197 		" %lu,%s mode: %x MAJOR: %u MINOR: %u\n", dir->i_ino,
1198 		dentry->d_name.name, mode, MAJOR(rdev), MINOR(rdev));
1199 
1200 	if (!new_valid_dev(rdev))
1201 		return -EINVAL;
1202 
1203 	name = __getname();
1204 	if (!name)
1205 		return -ENOMEM;
1206 	/* build extension */
1207 	if (S_ISBLK(mode))
1208 		sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev));
1209 	else if (S_ISCHR(mode))
1210 		sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev));
1211 	else if (S_ISFIFO(mode))
1212 		*name = 0;
1213 	else {
1214 		__putname(name);
1215 		return -EINVAL;
1216 	}
1217 
1218 	retval = v9fs_vfs_mkspecial(dir, dentry, mode, name);
1219 	__putname(name);
1220 
1221 	return retval;
1222 }
1223 
1224 static const struct inode_operations v9fs_dir_inode_operations_ext = {
1225 	.create = v9fs_vfs_create,
1226 	.lookup = v9fs_vfs_lookup,
1227 	.symlink = v9fs_vfs_symlink,
1228 	.link = v9fs_vfs_link,
1229 	.unlink = v9fs_vfs_unlink,
1230 	.mkdir = v9fs_vfs_mkdir,
1231 	.rmdir = v9fs_vfs_rmdir,
1232 	.mknod = v9fs_vfs_mknod,
1233 	.rename = v9fs_vfs_rename,
1234 	.readlink = v9fs_vfs_readlink,
1235 	.getattr = v9fs_vfs_getattr,
1236 	.setattr = v9fs_vfs_setattr,
1237 };
1238 
1239 static const struct inode_operations v9fs_dir_inode_operations = {
1240 	.create = v9fs_vfs_create,
1241 	.lookup = v9fs_vfs_lookup,
1242 	.unlink = v9fs_vfs_unlink,
1243 	.mkdir = v9fs_vfs_mkdir,
1244 	.rmdir = v9fs_vfs_rmdir,
1245 	.mknod = v9fs_vfs_mknod,
1246 	.rename = v9fs_vfs_rename,
1247 	.getattr = v9fs_vfs_getattr,
1248 	.setattr = v9fs_vfs_setattr,
1249 };
1250 
1251 static const struct inode_operations v9fs_file_inode_operations = {
1252 	.getattr = v9fs_vfs_getattr,
1253 	.setattr = v9fs_vfs_setattr,
1254 };
1255 
1256 static const struct inode_operations v9fs_symlink_inode_operations = {
1257 	.readlink = v9fs_vfs_readlink,
1258 	.follow_link = v9fs_vfs_follow_link,
1259 	.put_link = v9fs_vfs_put_link,
1260 	.getattr = v9fs_vfs_getattr,
1261 	.setattr = v9fs_vfs_setattr,
1262 };
1263