vfs_inode.c 34.1 KB
Newer Older
1 2 3
/*
 *  linux/fs/9p/vfs_inode.c
 *
4
 * This file contains vfs inode ops for the 9P2000 protocol.
5 6 7 8 9
 *
 *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
 *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
 *
 *  This program is free software; you can redistribute it and/or modify
10 11
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation.
12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to:
 *  Free Software Foundation
 *  51 Franklin Street, Fifth Floor
 *  Boston, MA  02111-1301  USA
 *
 */

26 27
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

28 29 30 31 32 33 34 35 36 37
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/pagemap.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/inet.h>
#include <linux/namei.h>
#include <linux/idr.h>
A
Alexey Dobriyan 已提交
38
#include <linux/sched.h>
39
#include <linux/slab.h>
40
#include <linux/xattr.h>
41
#include <linux/posix_acl.h>
42 43
#include <net/9p/9p.h>
#include <net/9p/client.h>
44 45 46 47

#include "v9fs.h"
#include "v9fs_vfs.h"
#include "fid.h"
48
#include "cache.h"
49
#include "xattr.h"
50
#include "acl.h"
51

52
static const struct inode_operations v9fs_dir_inode_operations;
53
static const struct inode_operations v9fs_dir_inode_operations_dotu;
54 55
static const struct inode_operations v9fs_file_inode_operations;
static const struct inode_operations v9fs_symlink_inode_operations;
56

57 58 59 60 61 62 63
/**
 * unixmode2p9mode - convert unix mode bits to plan 9
 * @v9ses: v9fs session information
 * @mode: mode to convert
 *
 */

A
Al Viro 已提交
64
static u32 unixmode2p9mode(struct v9fs_session_info *v9ses, umode_t mode)
65 66 67 68
{
	int res;
	res = mode & 0777;
	if (S_ISDIR(mode))
69
		res |= P9_DMDIR;
70
	if (v9fs_proto_dotu(v9ses)) {
71 72
		if (v9ses->nodev == 0) {
			if (S_ISSOCK(mode))
73
				res |= P9_DMSOCKET;
74
			if (S_ISFIFO(mode))
75
				res |= P9_DMNAMEDPIPE;
76
			if (S_ISBLK(mode))
77
				res |= P9_DMDEVICE;
78
			if (S_ISCHR(mode))
79
				res |= P9_DMDEVICE;
80 81 82
		}

		if ((mode & S_ISUID) == S_ISUID)
83
			res |= P9_DMSETUID;
84
		if ((mode & S_ISGID) == S_ISGID)
85
			res |= P9_DMSETGID;
A
Anthony Liguori 已提交
86 87
		if ((mode & S_ISVTX) == S_ISVTX)
			res |= P9_DMSETVTX;
88 89 90 91
	}
	return res;
}

92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
/**
 * p9mode2perm- convert plan9 mode bits to unix permission bits
 * @v9ses: v9fs session information
 * @stat: p9_wstat from which mode need to be derived
 *
 */
static int p9mode2perm(struct v9fs_session_info *v9ses,
		       struct p9_wstat *stat)
{
	int res;
	int mode = stat->mode;

	res = mode & S_IALLUGO;
	if (v9fs_proto_dotu(v9ses)) {
		if ((mode & P9_DMSETUID) == P9_DMSETUID)
			res |= S_ISUID;

		if ((mode & P9_DMSETGID) == P9_DMSETGID)
			res |= S_ISGID;

		if ((mode & P9_DMSETVTX) == P9_DMSETVTX)
			res |= S_ISVTX;
	}
	return res;
}

118 119 120
/**
 * p9mode2unixmode- convert plan9 mode bits to unix mode bits
 * @v9ses: v9fs session information
121 122
 * @stat: p9_wstat from which mode need to be derived
 * @rdev: major number, minor number in case of device files.
123 124
 *
 */
A
Al Viro 已提交
125 126
static umode_t p9mode2unixmode(struct v9fs_session_info *v9ses,
			       struct p9_wstat *stat, dev_t *rdev)
127 128
{
	int res;
A
Al Viro 已提交
129
	u32 mode = stat->mode;
130

131
	*rdev = 0;
132
	res = p9mode2perm(v9ses, stat);
133

134
	if ((mode & P9_DMDIR) == P9_DMDIR)
135
		res |= S_IFDIR;
136
	else if ((mode & P9_DMSYMLINK) && (v9fs_proto_dotu(v9ses)))
137
		res |= S_IFLNK;
138
	else if ((mode & P9_DMSOCKET) && (v9fs_proto_dotu(v9ses))
139 140
		 && (v9ses->nodev == 0))
		res |= S_IFSOCK;
141
	else if ((mode & P9_DMNAMEDPIPE) && (v9fs_proto_dotu(v9ses))
142 143
		 && (v9ses->nodev == 0))
		res |= S_IFIFO;
144
	else if ((mode & P9_DMDEVICE) && (v9fs_proto_dotu(v9ses))
145 146 147 148
		 && (v9ses->nodev == 0)) {
		char type = 0, ext[32];
		int major = -1, minor = -1;

149
		strlcpy(ext, stat->extension, sizeof(ext));
150 151 152 153 154 155 156 157 158
		sscanf(ext, "%c %u %u", &type, &major, &minor);
		switch (type) {
		case 'c':
			res |= S_IFCHR;
			break;
		case 'b':
			res |= S_IFBLK;
			break;
		default:
159 160
			p9_debug(P9_DEBUG_ERROR, "Unknown special type %c %s\n",
				 type, stat->extension);
161 162 163
		};
		*rdev = MKDEV(major, minor);
	} else
164 165 166 167 168
		res |= S_IFREG;

	return res;
}

E
Eric Van Hensbergen 已提交
169 170 171
/**
 * v9fs_uflags2omode- convert posix open flags to plan 9 mode bits
 * @uflags: flags to convert
172
 * @extended: if .u extensions are active
E
Eric Van Hensbergen 已提交
173 174
 */

175
int v9fs_uflags2omode(int uflags, int extended)
176 177 178 179 180 181 182
{
	int ret;

	ret = 0;
	switch (uflags&3) {
	default:
	case O_RDONLY:
183
		ret = P9_OREAD;
184 185 186
		break;

	case O_WRONLY:
187
		ret = P9_OWRITE;
188 189 190
		break;

	case O_RDWR:
191
		ret = P9_ORDWR;
192 193 194
		break;
	}

195 196 197 198 199 200 201
	if (extended) {
		if (uflags & O_EXCL)
			ret |= P9_OEXCL;

		if (uflags & O_APPEND)
			ret |= P9_OAPPEND;
	}
202 203 204 205

	return ret;
}

206
/**
207 208
 * v9fs_blank_wstat - helper function to setup a 9P stat structure
 * @wstat: structure to initialize
209 210 211
 *
 */

212
void
213
v9fs_blank_wstat(struct p9_wstat *wstat)
214
{
215 216 217 218 219 220 221 222 223 224 225 226 227
	wstat->type = ~0;
	wstat->dev = ~0;
	wstat->qid.type = ~0;
	wstat->qid.version = ~0;
	*((long long *)&wstat->qid.path) = ~0;
	wstat->mode = ~0;
	wstat->atime = ~0;
	wstat->mtime = ~0;
	wstat->length = ~0;
	wstat->name = NULL;
	wstat->uid = NULL;
	wstat->gid = NULL;
	wstat->muid = NULL;
228 229 230
	wstat->n_uid = INVALID_UID;
	wstat->n_gid = INVALID_GID;
	wstat->n_muid = INVALID_UID;
231
	wstat->extension = NULL;
232 233
}

234 235 236 237 238 239
/**
 * v9fs_alloc_inode - helper function to allocate an inode
 *
 */
struct inode *v9fs_alloc_inode(struct super_block *sb)
{
A
Aneesh Kumar K.V 已提交
240 241 242 243
	struct v9fs_inode *v9inode;
	v9inode = (struct v9fs_inode *)kmem_cache_alloc(v9fs_inode_cache,
							GFP_KERNEL);
	if (!v9inode)
244
		return NULL;
A
Aneesh Kumar K.V 已提交
245 246 247 248
#ifdef CONFIG_9P_FSCACHE
	v9inode->fscache = NULL;
	spin_lock_init(&v9inode->fscache_lock);
#endif
249
	v9inode->writeback_fid = NULL;
250
	v9inode->cache_validity = 0;
251
	mutex_init(&v9inode->v_mutex);
A
Aneesh Kumar K.V 已提交
252
	return &v9inode->vfs_inode;
253 254 255 256 257 258 259
}

/**
 * v9fs_destroy_inode - destroy an inode
 *
 */

N
Nick Piggin 已提交
260
static void v9fs_i_callback(struct rcu_head *head)
261
{
N
Nick Piggin 已提交
262
	struct inode *inode = container_of(head, struct inode, i_rcu);
A
Aneesh Kumar K.V 已提交
263
	kmem_cache_free(v9fs_inode_cache, V9FS_I(inode));
264
}
N
Nick Piggin 已提交
265 266 267 268 269

void v9fs_destroy_inode(struct inode *inode)
{
	call_rcu(&inode->i_rcu, v9fs_i_callback);
}
270

A
Aneesh Kumar K.V 已提交
271
int v9fs_init_inode(struct v9fs_session_info *v9ses,
A
Al Viro 已提交
272
		    struct inode *inode, umode_t mode, dev_t rdev)
273
{
A
Aneesh Kumar K.V 已提交
274
	int err = 0;
275

276
	inode_init_owner(inode, NULL, mode);
277
	inode->i_blocks = 0;
278
	inode->i_rdev = rdev;
279 280 281 282 283 284 285 286
	inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
	inode->i_mapping->a_ops = &v9fs_addr_operations;

	switch (mode & S_IFMT) {
	case S_IFIFO:
	case S_IFBLK:
	case S_IFCHR:
	case S_IFSOCK:
M
M. Mohan Kumar 已提交
287 288 289 290 291
		if (v9fs_proto_dotl(v9ses)) {
			inode->i_op = &v9fs_file_inode_operations_dotl;
		} else if (v9fs_proto_dotu(v9ses)) {
			inode->i_op = &v9fs_file_inode_operations;
		} else {
292 293
			p9_debug(P9_DEBUG_ERROR,
				 "special files without extended mode\n");
294 295
			err = -EINVAL;
			goto error;
296
		}
297 298 299
		init_special_inode(inode, inode->i_mode, inode->i_rdev);
		break;
	case S_IFREG:
300 301
		if (v9fs_proto_dotl(v9ses)) {
			inode->i_op = &v9fs_file_inode_operations_dotl;
302 303 304 305 306
			if (v9ses->cache)
				inode->i_fop =
					&v9fs_cached_file_operations_dotl;
			else
				inode->i_fop = &v9fs_file_operations_dotl;
307 308
		} else {
			inode->i_op = &v9fs_file_inode_operations;
309 310 311 312
			if (v9ses->cache)
				inode->i_fop = &v9fs_cached_file_operations;
			else
				inode->i_fop = &v9fs_file_operations;
313 314
		}

315 316
		break;
	case S_IFLNK:
317
		if (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)) {
318 319
			p9_debug(P9_DEBUG_ERROR,
				 "extended modes used with legacy protocol\n");
320 321 322
			err = -EINVAL;
			goto error;
		}
323 324 325 326 327 328

		if (v9fs_proto_dotl(v9ses))
			inode->i_op = &v9fs_symlink_inode_operations_dotl;
		else
			inode->i_op = &v9fs_symlink_inode_operations;

329 330 331
		break;
	case S_IFDIR:
		inc_nlink(inode);
332 333 334 335
		if (v9fs_proto_dotl(v9ses))
			inode->i_op = &v9fs_dir_inode_operations_dotl;
		else if (v9fs_proto_dotu(v9ses))
			inode->i_op = &v9fs_dir_inode_operations_dotu;
336 337
		else
			inode->i_op = &v9fs_dir_inode_operations;
338 339 340 341 342 343

		if (v9fs_proto_dotl(v9ses))
			inode->i_fop = &v9fs_dir_operations_dotl;
		else
			inode->i_fop = &v9fs_dir_operations;

344 345
		break;
	default:
346
		p9_debug(P9_DEBUG_ERROR, "BAD mode 0x%hx S_IFMT 0x%x\n",
347
			 mode, mode & S_IFMT);
348 349
		err = -EINVAL;
		goto error;
350
	}
A
Aneesh Kumar K.V 已提交
351 352
error:
	return err;
353

A
Aneesh Kumar K.V 已提交
354
}
355

A
Aneesh Kumar K.V 已提交
356 357 358 359 360 361 362
/**
 * v9fs_get_inode - helper function to setup an inode
 * @sb: superblock
 * @mode: mode to setup inode with
 *
 */

A
Al Viro 已提交
363
struct inode *v9fs_get_inode(struct super_block *sb, umode_t mode, dev_t rdev)
A
Aneesh Kumar K.V 已提交
364 365 366 367 368
{
	int err;
	struct inode *inode;
	struct v9fs_session_info *v9ses = sb->s_fs_info;

369
	p9_debug(P9_DEBUG_VFS, "super block: %p mode: %ho\n", sb, mode);
A
Aneesh Kumar K.V 已提交
370 371 372

	inode = new_inode(sb);
	if (!inode) {
373 374
		pr_warn("%s (%d): Problem allocating inode\n",
			__func__, task_pid_nr(current));
A
Aneesh Kumar K.V 已提交
375 376
		return ERR_PTR(-ENOMEM);
	}
377
	err = v9fs_init_inode(v9ses, inode, mode, rdev);
A
Aneesh Kumar K.V 已提交
378 379 380 381 382
	if (err) {
		iput(inode);
		return ERR_PTR(err);
	}
	return inode;
383 384
}

385
/*
386 387 388 389
static struct v9fs_fid*
v9fs_clone_walk(struct v9fs_session_info *v9ses, u32 fid, struct dentry *dentry)
{
	int err;
390
	int nfid;
391 392 393 394 395
	struct v9fs_fid *ret;
	struct v9fs_fcall *fcall;

	nfid = v9fs_get_idpool(&v9ses->fidpool);
	if (nfid < 0) {
396
		eprintk(KERN_WARNING, "no free fids available\n");
397
		return ERR_PTR(-ENOSPC);
398 399
	}

400 401 402 403
	err = v9fs_t_walk(v9ses, fid, nfid, (char *) dentry->d_name.name,
		&fcall);

	if (err < 0) {
404 405 406
		if (fcall && fcall->id == RWALK)
			goto clunk_fid;

407 408 409
		PRINT_FCALL_ERROR("walk error", fcall);
		v9fs_put_idpool(nfid, &v9ses->fidpool);
		goto error;
410
	}
411

412 413
	kfree(fcall);
	fcall = NULL;
414 415 416 417 418
	ret = v9fs_fid_create(v9ses, nfid);
	if (!ret) {
		err = -ENOMEM;
		goto clunk_fid;
	}
419

420 421 422 423
	err = v9fs_fid_insert(ret, dentry);
	if (err < 0) {
		v9fs_fid_destroy(ret);
		goto clunk_fid;
424
	}
425

426
	return ret;
427

428 429
clunk_fid:
	v9fs_t_clunk(v9ses, nfid);
430

431 432 433 434
error:
	kfree(fcall);
	return ERR_PTR(err);
}
435
*/
436

437 438 439 440 441 442

/**
 * v9fs_clear_inode - release an inode
 * @inode: inode to release
 *
 */
443
void v9fs_evict_inode(struct inode *inode)
444
{
445 446
	struct v9fs_inode *v9inode = V9FS_I(inode);

447
	truncate_inode_pages(inode->i_mapping, 0);
448
	clear_inode(inode);
449 450 451
	filemap_fdatawrite(inode->i_mapping);

	v9fs_cache_inode_put_cookie(inode);
452 453 454 455
	/* clunk the fid stashed in writeback_fid */
	if (v9inode->writeback_fid) {
		p9_client_clunk(v9inode->writeback_fid);
		v9inode->writeback_fid = NULL;
456
	}
457 458
}

459 460 461
static int v9fs_test_inode(struct inode *inode, void *data)
{
	int umode;
462
	dev_t rdev;
463 464 465 466
	struct v9fs_inode *v9inode = V9FS_I(inode);
	struct p9_wstat *st = (struct p9_wstat *)data;
	struct v9fs_session_info *v9ses = v9fs_inode2v9ses(inode);

467
	umode = p9mode2unixmode(v9ses, st, &rdev);
468 469 470 471 472 473 474 475 476 477 478 479 480 481
	/* don't match inode of different type */
	if ((inode->i_mode & S_IFMT) != (umode & S_IFMT))
		return 0;

	/* compare qid details */
	if (memcmp(&v9inode->qid.version,
		   &st->qid.version, sizeof(v9inode->qid.version)))
		return 0;

	if (v9inode->qid.type != st->qid.type)
		return 0;
	return 1;
}

482 483 484 485 486
static int v9fs_test_new_inode(struct inode *inode, void *data)
{
	return 0;
}

487 488 489 490 491 492 493 494 495
static int v9fs_set_inode(struct inode *inode,  void *data)
{
	struct v9fs_inode *v9inode = V9FS_I(inode);
	struct p9_wstat *st = (struct p9_wstat *)data;

	memcpy(&v9inode->qid, &st->qid, sizeof(st->qid));
	return 0;
}

A
Aneesh Kumar K.V 已提交
496 497
static struct inode *v9fs_qid_iget(struct super_block *sb,
				   struct p9_qid *qid,
498 499
				   struct p9_wstat *st,
				   int new)
500
{
501
	dev_t rdev;
A
Al Viro 已提交
502 503
	int retval;
	umode_t umode;
A
Aneesh Kumar K.V 已提交
504 505 506
	unsigned long i_ino;
	struct inode *inode;
	struct v9fs_session_info *v9ses = sb->s_fs_info;
507 508 509 510 511 512
	int (*test)(struct inode *, void *);

	if (new)
		test = v9fs_test_new_inode;
	else
		test = v9fs_test_inode;
513

A
Aneesh Kumar K.V 已提交
514
	i_ino = v9fs_qid2ino(qid);
515
	inode = iget5_locked(sb, i_ino, test, v9fs_set_inode, st);
A
Aneesh Kumar K.V 已提交
516 517 518 519 520 521 522 523 524
	if (!inode)
		return ERR_PTR(-ENOMEM);
	if (!(inode->i_state & I_NEW))
		return inode;
	/*
	 * initialize the inode with the stat info
	 * FIXME!! we may need support for stale inodes
	 * later.
	 */
525
	inode->i_ino = i_ino;
526 527
	umode = p9mode2unixmode(v9ses, st, &rdev);
	retval = v9fs_init_inode(v9ses, inode, umode, rdev);
A
Aneesh Kumar K.V 已提交
528
	if (retval)
529
		goto error;
530

A
Aneesh Kumar K.V 已提交
531 532 533 534
	v9fs_stat2inode(st, inode, sb);
	v9fs_cache_inode_get_cookie(inode);
	unlock_new_inode(inode);
	return inode;
535
error:
A
Aneesh Kumar K.V 已提交
536 537 538 539 540 541 542
	unlock_new_inode(inode);
	iput(inode);
	return ERR_PTR(retval);

}

struct inode *
A
Aneesh Kumar K.V 已提交
543
v9fs_inode_from_fid(struct v9fs_session_info *v9ses, struct p9_fid *fid,
544
		    struct super_block *sb, int new)
A
Aneesh Kumar K.V 已提交
545 546 547 548 549 550 551 552
{
	struct p9_wstat *st;
	struct inode *inode = NULL;

	st = p9_client_stat(fid);
	if (IS_ERR(st))
		return ERR_CAST(st);

553
	inode = v9fs_qid_iget(sb, &st->qid, st, new);
554
	p9stat_free(st);
555
	kfree(st);
A
Aneesh Kumar K.V 已提交
556
	return inode;
557 558
}

559 560 561 562 563 564 565 566 567 568 569 570 571
/**
 * v9fs_at_to_dotl_flags- convert Linux specific AT flags to
 * plan 9 AT flag.
 * @flags: flags to convert
 */
static int v9fs_at_to_dotl_flags(int flags)
{
	int rflags = 0;
	if (flags & AT_REMOVEDIR)
		rflags |= P9_DOTL_AT_REMOVEDIR;
	return rflags;
}

572 573
/**
 * v9fs_remove - helper function to remove files and directories
574
 * @dir: directory inode that is being deleted
575
 * @dentry:  dentry that is being deleted
576
 * @rmdir: removing a directory
577 578 579
 *
 */

580
static int v9fs_remove(struct inode *dir, struct dentry *dentry, int flags)
581
{
582 583 584 585
	struct inode *inode;
	int retval = -EOPNOTSUPP;
	struct p9_fid *v9fid, *dfid;
	struct v9fs_session_info *v9ses;
586

587 588
	p9_debug(P9_DEBUG_VFS, "inode: %p dentry: %p rmdir: %x\n",
		 dir, dentry, flags);
589

590 591 592 593 594
	v9ses = v9fs_inode2v9ses(dir);
	inode = dentry->d_inode;
	dfid = v9fs_fid_lookup(dentry->d_parent);
	if (IS_ERR(dfid)) {
		retval = PTR_ERR(dfid);
595
		p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", retval);
596 597 598
		return retval;
	}
	if (v9fs_proto_dotl(v9ses))
599 600
		retval = p9_client_unlinkat(dfid, dentry->d_name.name,
					    v9fs_at_to_dotl_flags(flags));
601 602 603 604 605 606 607
	if (retval == -EOPNOTSUPP) {
		/* Try the one based on path */
		v9fid = v9fs_fid_clone(dentry);
		if (IS_ERR(v9fid))
			return PTR_ERR(v9fid);
		retval = p9_client_remove(v9fid);
	}
608 609 610 611 612
	if (!retval) {
		/*
		 * directories on unlink should have zero
		 * link count
		 */
613 614
		if (flags & AT_REMOVEDIR) {
			clear_nlink(inode);
615 616
			drop_nlink(dir);
		} else
617
			drop_nlink(inode);
618

619
		v9fs_invalidate_inode_attr(inode);
620
		v9fs_invalidate_inode_attr(dir);
621
	}
A
Aneesh Kumar K.V 已提交
622
	return retval;
623 624 625
}

/**
626
 * v9fs_create - Create a file
E
Eric Van Hensbergen 已提交
627 628
 * @v9ses: session information
 * @dir: directory that dentry is being created in
629
 * @dentry:  dentry that is being created
A
Abhishek Kulkarni 已提交
630
 * @extension: 9p2000.u extension string to support devices, etc.
631 632
 * @perm: create permissions
 * @mode: open mode
633 634
 *
 */
635 636 637
static struct p9_fid *
v9fs_create(struct v9fs_session_info *v9ses, struct inode *dir,
		struct dentry *dentry, char *extension, u32 perm, u8 mode)
638
{
639
	int err;
640 641
	char *name;
	struct p9_fid *dfid, *ofid, *fid;
642 643
	struct inode *inode;

644
	p9_debug(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
645

646 647 648 649
	err = 0;
	ofid = NULL;
	fid = NULL;
	name = (char *) dentry->d_name.name;
650
	dfid = v9fs_fid_lookup(dentry->d_parent);
L
Latchesar Ionkov 已提交
651
	if (IS_ERR(dfid)) {
652
		err = PTR_ERR(dfid);
653
		p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
654
		return ERR_PTR(err);
655
	}
656

657 658 659 660
	/* clone a fid to use for creation */
	ofid = p9_client_walk(dfid, 0, NULL, 1);
	if (IS_ERR(ofid)) {
		err = PTR_ERR(ofid);
661
		p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
662
		return ERR_PTR(err);
663
	}
664

665
	err = p9_client_fcreate(ofid, name, perm, mode, extension);
666
	if (err < 0) {
667
		p9_debug(P9_DEBUG_VFS, "p9_client_fcreate failed %d\n", err);
668
		goto error;
669
	}
670

671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
	if (!(perm & P9_DMLINK)) {
		/* now walk from the parent so we can get unopened fid */
		fid = p9_client_walk(dfid, 1, &name, 1);
		if (IS_ERR(fid)) {
			err = PTR_ERR(fid);
			p9_debug(P9_DEBUG_VFS,
				   "p9_client_walk failed %d\n", err);
			fid = NULL;
			goto error;
		}
		/*
		 * instantiate inode and assign the unopened fid to the dentry
		 */
		inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
		if (IS_ERR(inode)) {
			err = PTR_ERR(inode);
			p9_debug(P9_DEBUG_VFS,
				   "inode creation failed %d\n", err);
			goto error;
		}
A
Al Viro 已提交
691
		v9fs_fid_add(dentry, fid);
692
		d_instantiate(dentry, inode);
693
	}
694 695 696 697 698 699 700 701 702 703 704 705
	return ofid;
error:
	if (ofid)
		p9_client_clunk(ofid);

	if (fid)
		p9_client_clunk(fid);

	return ERR_PTR(err);
}

/**
706 707 708 709 710
 * v9fs_vfs_create - VFS hook to create a regular file
 *
 * open(.., O_CREAT) is handled in v9fs_vfs_atomic_open().  This is only called
 * for mknod(2).
 *
E
Eric Van Hensbergen 已提交
711
 * @dir: directory inode that is being created
712 713 714 715
 * @dentry:  dentry that is being deleted
 * @mode: create permissions
 *
 */
716

717
static int
A
Al Viro 已提交
718
v9fs_vfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
A
Al Viro 已提交
719
		bool excl)
720
{
721 722 723
	struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
	u32 perm = unixmode2p9mode(v9ses, mode);
	struct p9_fid *fid;
724

725 726 727 728
	/* P9_OEXCL? */
	fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_ORDWR);
	if (IS_ERR(fid))
		return PTR_ERR(fid);
729

730
	v9fs_invalidate_inode_attr(dir);
731
	p9_client_clunk(fid);
732 733

	return 0;
734 735 736 737
}

/**
 * v9fs_vfs_mkdir - VFS mkdir hook to create a directory
E
Eric Van Hensbergen 已提交
738
 * @dir:  inode that is being unlinked
739 740 741 742 743
 * @dentry: dentry that is being unlinked
 * @mode: mode for new directory
 *
 */

744
static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
745
{
746
	int err;
747 748
	u32 perm;
	struct p9_fid *fid;
749
	struct v9fs_session_info *v9ses;
750

751
	p9_debug(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
752
	err = 0;
753 754
	v9ses = v9fs_inode2v9ses(dir);
	perm = unixmode2p9mode(v9ses, mode | S_IFDIR);
755 756 757 758
	fid = v9fs_create(v9ses, dir, dentry, NULL, perm, P9_OREAD);
	if (IS_ERR(fid)) {
		err = PTR_ERR(fid);
		fid = NULL;
759
	} else {
760
		inc_nlink(dir);
761 762
		v9fs_invalidate_inode_attr(dir);
	}
763

764 765
	if (fid)
		p9_client_clunk(fid);
766 767

	return err;
768 769 770 771 772 773 774 775 776 777
}

/**
 * v9fs_vfs_lookup - VFS lookup hook to "walk" to a new inode
 * @dir:  inode that is being walked from
 * @dentry: dentry that is being walked to?
 * @nameidata: path data
 *
 */

778
struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
A
Al Viro 已提交
779
				      unsigned int flags)
780
{
781
	struct dentry *res;
782
	struct v9fs_session_info *v9ses;
783
	struct p9_fid *dfid, *fid;
784
	struct inode *inode;
785
	char *name;
786

A
Al Viro 已提交
787 788
	p9_debug(P9_DEBUG_VFS, "dir: %p dentry: (%s) %p flags: %x\n",
		 dir, dentry->d_name.name, dentry, flags);
789

790 791 792
	if (dentry->d_name.len > NAME_MAX)
		return ERR_PTR(-ENAMETOOLONG);

793
	v9ses = v9fs_inode2v9ses(dir);
794
	/* We can walk d_parent because we hold the dir->i_mutex */
795 796
	dfid = v9fs_fid_lookup(dentry->d_parent);
	if (IS_ERR(dfid))
797
		return ERR_CAST(dfid);
798 799 800 801

	name = (char *) dentry->d_name.name;
	fid = p9_client_walk(dfid, 1, &name, 1);
	if (IS_ERR(fid)) {
A
Al Viro 已提交
802 803 804
		if (fid == ERR_PTR(-ENOENT)) {
			d_add(dentry, NULL);
			return NULL;
805
		}
A
Al Viro 已提交
806
		return ERR_CAST(fid);
807
	}
808 809 810 811 812 813 814 815 816
	/*
	 * Make sure we don't use a wrong inode due to parallel
	 * unlink. For cached mode create calls request for new
	 * inode. But with cache disabled, lookup should do this.
	 */
	if (v9ses->cache)
		inode = v9fs_get_inode_from_fid(v9ses, fid, dir->i_sb);
	else
		inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
817
	if (IS_ERR(inode)) {
A
Al Viro 已提交
818 819
		p9_client_clunk(fid);
		return ERR_CAST(inode);
820
	}
821 822 823 824 825 826 827 828
	/*
	 * If we had a rename on the server and a parallel lookup
	 * for the new name, then make sure we instantiate with
	 * the new name. ie look up for a/b, while on server somebody
	 * moved b under k and client parallely did a lookup for
	 * k/b.
	 */
	res = d_materialise_unique(dentry, inode);
829 830 831 832 833
	if (!res)
		v9fs_fid_add(dentry, fid);
	else if (!IS_ERR(res))
		v9fs_fid_add(res, fid);
	else
A
Al Viro 已提交
834 835
		p9_client_clunk(fid);
	return res;
836 837
}

A
Al Viro 已提交
838
static int
839
v9fs_vfs_atomic_open(struct inode *dir, struct dentry *dentry,
A
Al Viro 已提交
840
		     struct file *file, unsigned flags, umode_t mode,
841
		     int *opened)
842 843 844 845 846 847 848 849 850
{
	int err;
	u32 perm;
	struct v9fs_inode *v9inode;
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid, *inode_fid;
	struct dentry *res = NULL;

	if (d_unhashed(dentry)) {
A
Al Viro 已提交
851
		res = v9fs_vfs_lookup(dir, dentry, 0);
852
		if (IS_ERR(res))
A
Al Viro 已提交
853
			return PTR_ERR(res);
854 855 856 857 858 859

		if (res)
			dentry = res;
	}

	/* Only creates */
A
Al Viro 已提交
860 861
	if (!(flags & O_CREAT) || dentry->d_inode)
		return finish_no_open(file, res);
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896

	err = 0;
	fid = NULL;
	v9ses = v9fs_inode2v9ses(dir);
	perm = unixmode2p9mode(v9ses, mode);
	fid = v9fs_create(v9ses, dir, dentry, NULL, perm,
				v9fs_uflags2omode(flags,
						v9fs_proto_dotu(v9ses)));
	if (IS_ERR(fid)) {
		err = PTR_ERR(fid);
		fid = NULL;
		goto error;
	}

	v9fs_invalidate_inode_attr(dir);
	v9inode = V9FS_I(dentry->d_inode);
	mutex_lock(&v9inode->v_mutex);
	if (v9ses->cache && !v9inode->writeback_fid &&
	    ((flags & O_ACCMODE) != O_RDONLY)) {
		/*
		 * clone a fid and add it to writeback_fid
		 * we do it during open time instead of
		 * page dirty time via write_begin/page_mkwrite
		 * because we want write after unlink usecase
		 * to work.
		 */
		inode_fid = v9fs_writeback_fid(dentry);
		if (IS_ERR(inode_fid)) {
			err = PTR_ERR(inode_fid);
			mutex_unlock(&v9inode->v_mutex);
			goto error;
		}
		v9inode->writeback_fid = (void *) inode_fid;
	}
	mutex_unlock(&v9inode->v_mutex);
A
Al Viro 已提交
897 898
	err = finish_open(file, dentry, generic_file_open, opened);
	if (err)
899 900
		goto error;

A
Al Viro 已提交
901
	file->private_data = fid;
902
	if (v9ses->cache)
A
Al Viro 已提交
903
		v9fs_cache_inode_set_cookie(dentry->d_inode, file);
904

905
	*opened |= FILE_CREATED;
906 907
out:
	dput(res);
A
Al Viro 已提交
908
	return err;
909 910 911 912 913 914 915

error:
	if (fid)
		p9_client_clunk(fid);
	goto out;
}

916 917 918
/**
 * v9fs_vfs_unlink - VFS unlink hook to delete an inode
 * @i:  inode that is being unlinked
919
 * @d: dentry that is being unlinked
920 921 922
 *
 */

923
int v9fs_vfs_unlink(struct inode *i, struct dentry *d)
924 925 926 927 928 929 930
{
	return v9fs_remove(i, d, 0);
}

/**
 * v9fs_vfs_rmdir - VFS unlink hook to delete a directory
 * @i:  inode that is being unlinked
931
 * @d: dentry that is being unlinked
932 933 934
 *
 */

935
int v9fs_vfs_rmdir(struct inode *i, struct dentry *d)
936
{
937
	return v9fs_remove(i, d, AT_REMOVEDIR);
938 939 940 941 942 943 944 945 946 947 948
}

/**
 * v9fs_vfs_rename - VFS hook to rename an inode
 * @old_dir:  old dir inode
 * @old_dentry: old dentry
 * @new_dir: new dir inode
 * @new_dentry: new dentry
 *
 */

949
int
950 951 952
v9fs_vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		struct inode *new_dir, struct dentry *new_dentry)
{
953
	int retval;
954
	struct inode *old_inode;
955
	struct inode *new_inode;
956 957 958 959 960
	struct v9fs_session_info *v9ses;
	struct p9_fid *oldfid;
	struct p9_fid *olddirfid;
	struct p9_fid *newdirfid;
	struct p9_wstat wstat;
961

962
	p9_debug(P9_DEBUG_VFS, "\n");
963 964
	retval = 0;
	old_inode = old_dentry->d_inode;
965
	new_inode = new_dentry->d_inode;
966 967
	v9ses = v9fs_inode2v9ses(old_inode);
	oldfid = v9fs_fid_lookup(old_dentry);
L
Latchesar Ionkov 已提交
968
	if (IS_ERR(oldfid))
969 970 971
		return PTR_ERR(oldfid);

	olddirfid = v9fs_fid_clone(old_dentry->d_parent);
L
Latchesar Ionkov 已提交
972
	if (IS_ERR(olddirfid)) {
973
		retval = PTR_ERR(olddirfid);
974
		goto done;
975 976 977
	}

	newdirfid = v9fs_fid_clone(new_dentry->d_parent);
L
Latchesar Ionkov 已提交
978
	if (IS_ERR(newdirfid)) {
979
		retval = PTR_ERR(newdirfid);
980
		goto clunk_olddir;
981 982
	}

983
	down_write(&v9ses->rename_sem);
984
	if (v9fs_proto_dotl(v9ses)) {
985 986 987 988 989 990
		retval = p9_client_renameat(olddirfid, old_dentry->d_name.name,
					    newdirfid, new_dentry->d_name.name);
		if (retval == -EOPNOTSUPP)
			retval = p9_client_rename(oldfid, newdirfid,
						  new_dentry->d_name.name);
		if (retval != -EOPNOTSUPP)
991 992
			goto clunk_newdir;
	}
993 994 995 996
	if (old_dentry->d_parent != new_dentry->d_parent) {
		/*
		 * 9P .u can only handle file rename in the same directory
		 */
997

998
		p9_debug(P9_DEBUG_ERROR, "old dir and new dir are different\n");
999
		retval = -EXDEV;
1000
		goto clunk_newdir;
1001
	}
1002
	v9fs_blank_wstat(&wstat);
L
Latchesar Ionkov 已提交
1003
	wstat.muid = v9ses->uname;
1004
	wstat.name = (char *) new_dentry->d_name.name;
1005
	retval = p9_client_wstat(oldfid, &wstat);
1006

1007
clunk_newdir:
1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019
	if (!retval) {
		if (new_inode) {
			if (S_ISDIR(new_inode->i_mode))
				clear_nlink(new_inode);
			else
				drop_nlink(new_inode);
		}
		if (S_ISDIR(old_inode->i_mode)) {
			if (!new_inode)
				inc_nlink(new_dir);
			drop_nlink(old_dir);
		}
1020
		v9fs_invalidate_inode_attr(old_inode);
1021 1022
		v9fs_invalidate_inode_attr(old_dir);
		v9fs_invalidate_inode_attr(new_dir);
1023

1024 1025
		/* successful rename */
		d_move(old_dentry, new_dentry);
1026
	}
1027
	up_write(&v9ses->rename_sem);
1028
	p9_client_clunk(newdirfid);
1029

1030
clunk_olddir:
1031
	p9_client_clunk(olddirfid);
1032

1033
done:
1034 1035 1036 1037
	return retval;
}

/**
A
Adrian Bunk 已提交
1038
 * v9fs_vfs_getattr - retrieve file metadata
E
Eric Van Hensbergen 已提交
1039 1040 1041
 * @mnt: mount information
 * @dentry: file to get attributes on
 * @stat: metadata structure to populate
1042 1043 1044 1045 1046 1047 1048
 *
 */

static int
v9fs_vfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
		 struct kstat *stat)
{
1049 1050
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid;
1051
	struct p9_wstat *st;
1052

1053
	p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
A
Aneesh Kumar K.V 已提交
1054
	v9ses = v9fs_dentry2v9ses(dentry);
1055 1056 1057 1058
	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
		generic_fillattr(dentry->d_inode, stat);
		return 0;
	}
1059 1060
	fid = v9fs_fid_lookup(dentry);
	if (IS_ERR(fid))
1061
		return PTR_ERR(fid);
1062

1063 1064 1065
	st = p9_client_stat(fid);
	if (IS_ERR(st))
		return PTR_ERR(st);
1066

1067
	v9fs_stat2inode(st, dentry->d_inode, dentry->d_inode->i_sb);
1068
	generic_fillattr(dentry->d_inode, stat);
1069

1070
	p9stat_free(st);
1071 1072
	kfree(st);
	return 0;
1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083
}

/**
 * v9fs_vfs_setattr - set file metadata
 * @dentry: file whose metadata to set
 * @iattr: metadata assignment structure
 *
 */

static int v9fs_vfs_setattr(struct dentry *dentry, struct iattr *iattr)
{
1084 1085 1086 1087
	int retval;
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid;
	struct p9_wstat wstat;
1088

1089
	p9_debug(P9_DEBUG_VFS, "\n");
1090 1091 1092 1093
	retval = inode_change_ok(dentry->d_inode, iattr);
	if (retval)
		return retval;

1094
	retval = -EPERM;
A
Aneesh Kumar K.V 已提交
1095
	v9ses = v9fs_dentry2v9ses(dentry);
1096
	fid = v9fs_fid_lookup(dentry);
1097 1098
	if(IS_ERR(fid))
		return PTR_ERR(fid);
1099

1100
	v9fs_blank_wstat(&wstat);
1101
	if (iattr->ia_valid & ATTR_MODE)
1102
		wstat.mode = unixmode2p9mode(v9ses, iattr->ia_mode);
1103 1104

	if (iattr->ia_valid & ATTR_MTIME)
1105
		wstat.mtime = iattr->ia_mtime.tv_sec;
1106 1107

	if (iattr->ia_valid & ATTR_ATIME)
1108
		wstat.atime = iattr->ia_atime.tv_sec;
1109 1110

	if (iattr->ia_valid & ATTR_SIZE)
1111
		wstat.length = iattr->ia_size;
1112

1113
	if (v9fs_proto_dotu(v9ses)) {
1114 1115
		if (iattr->ia_valid & ATTR_UID)
			wstat.n_uid = iattr->ia_uid;
1116

1117 1118
		if (iattr->ia_valid & ATTR_GID)
			wstat.n_gid = iattr->ia_gid;
1119
	}
1120

1121 1122 1123 1124
	/* Write all dirty data */
	if (S_ISREG(dentry->d_inode->i_mode))
		filemap_write_and_wait(dentry->d_inode->i_mapping);

1125 1126 1127
	retval = p9_client_wstat(fid, &wstat);
	if (retval < 0)
		return retval;
1128 1129 1130 1131 1132

	if ((iattr->ia_valid & ATTR_SIZE) &&
	    iattr->ia_size != i_size_read(dentry->d_inode))
		truncate_setsize(dentry->d_inode, iattr->ia_size);

1133
	v9fs_invalidate_inode_attr(dentry->d_inode);
1134

C
Christoph Hellwig 已提交
1135 1136 1137
	setattr_copy(dentry->d_inode, iattr);
	mark_inode_dirty(dentry->d_inode);
	return 0;
1138 1139 1140
}

/**
1141 1142
 * v9fs_stat2inode - populate an inode structure with mistat info
 * @stat: Plan 9 metadata (mistat) structure
1143 1144 1145 1146 1147 1148
 * @inode: inode to populate
 * @sb: superblock of filesystem
 *
 */

void
1149
v9fs_stat2inode(struct p9_wstat *stat, struct inode *inode,
1150
	struct super_block *sb)
1151
{
A
Al Viro 已提交
1152
	umode_t mode;
1153
	char ext[32];
1154 1155
	char tag_name[14];
	unsigned int i_nlink;
1156
	struct v9fs_session_info *v9ses = sb->s_fs_info;
1157
	struct v9fs_inode *v9inode = V9FS_I(inode);
1158

M
Miklos Szeredi 已提交
1159
	set_nlink(inode, 1);
1160

1161 1162 1163
	inode->i_atime.tv_sec = stat->atime;
	inode->i_mtime.tv_sec = stat->mtime;
	inode->i_ctime.tv_sec = stat->mtime;
1164

1165 1166
	inode->i_uid = v9ses->dfltuid;
	inode->i_gid = v9ses->dfltgid;
1167

1168
	if (v9fs_proto_dotu(v9ses)) {
1169 1170
		inode->i_uid = stat->n_uid;
		inode->i_gid = stat->n_gid;
1171
	}
1172 1173 1174 1175 1176 1177 1178 1179 1180
	if ((S_ISREG(inode->i_mode)) || (S_ISDIR(inode->i_mode))) {
		if (v9fs_proto_dotu(v9ses) && (stat->extension[0] != '\0')) {
			/*
			 * Hadlink support got added later to
			 * to the .u extension. So there can be
			 * server out there that doesn't support
			 * this even with .u extension. So check
			 * for non NULL stat->extension
			 */
1181
			strlcpy(ext, stat->extension, sizeof(ext));
1182 1183 1184
			/* HARDLINKCOUNT %u */
			sscanf(ext, "%13s %u", tag_name, &i_nlink);
			if (!strncmp(tag_name, "HARDLINKCOUNT", 13))
M
Miklos Szeredi 已提交
1185
				set_nlink(inode, i_nlink);
1186 1187
		}
	}
1188
	mode = p9mode2perm(v9ses, stat);
1189 1190
	mode |= inode->i_mode & ~S_IALLUGO;
	inode->i_mode = mode;
1191
	i_size_write(inode, stat->length);
1192

1193
	/* not real number of blocks, but 512 byte ones ... */
1194
	inode->i_blocks = (i_size_read(inode) + 512 - 1) >> 9;
1195
	v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR;
1196 1197 1198 1199 1200 1201 1202 1203 1204
}

/**
 * v9fs_qid2ino - convert qid into inode number
 * @qid: qid to hash
 *
 * BUG: potential for inode number collisions?
 */

1205
ino_t v9fs_qid2ino(struct p9_qid *qid)
1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220
{
	u64 path = qid->path + 2;
	ino_t i = 0;

	if (sizeof(ino_t) == sizeof(path))
		memcpy(&i, &path, sizeof(ino_t));
	else
		i = (ino_t) (path ^ (path >> 32));

	return i;
}

/**
 * v9fs_readlink - read a symlink's location (internal version)
 * @dentry: dentry for symlink
1221
 * @buffer: buffer to load symlink location into
1222 1223 1224 1225 1226 1227
 * @buflen: length of buffer
 *
 */

static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
{
1228
	int retval;
1229

1230 1231
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid;
1232
	struct p9_wstat *st;
1233

1234
	p9_debug(P9_DEBUG_VFS, " %s\n", dentry->d_name.name);
1235
	retval = -EPERM;
A
Aneesh Kumar K.V 已提交
1236
	v9ses = v9fs_dentry2v9ses(dentry);
1237
	fid = v9fs_fid_lookup(dentry);
L
Latchesar Ionkov 已提交
1238
	if (IS_ERR(fid))
1239
		return PTR_ERR(fid);
1240

1241
	if (!v9fs_proto_dotu(v9ses))
1242
		return -EBADF;
1243

1244 1245 1246
	st = p9_client_stat(fid);
	if (IS_ERR(st))
		return PTR_ERR(st);
1247

1248
	if (!(st->mode & P9_DMSYMLINK)) {
1249
		retval = -EINVAL;
1250
		goto done;
1251 1252 1253
	}

	/* copy extension buffer into buffer */
1254 1255
	retval = min(strlen(st->extension)+1, (size_t)buflen);
	memcpy(buffer, st->extension, retval);
1256

1257 1258
	p9_debug(P9_DEBUG_VFS, "%s -> %s (%.*s)\n",
		 dentry->d_name.name, st->extension, buflen, buffer);
1259

1260
done:
1261
	p9stat_free(st);
1262
	kfree(st);
1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277
	return retval;
}

/**
 * v9fs_vfs_follow_link - follow a symlink path
 * @dentry: dentry for symlink
 * @nd: nameidata
 *
 */

static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
{
	int len = 0;
	char *link = __getname();

1278
	p9_debug(P9_DEBUG_VFS, "%s\n", dentry->d_name.name);
1279 1280 1281 1282

	if (!link)
		link = ERR_PTR(-ENOMEM);
	else {
1283
		len = v9fs_readlink(dentry, link, PATH_MAX);
1284 1285

		if (len < 0) {
1286
			__putname(link);
1287 1288
			link = ERR_PTR(len);
		} else
M
Martin Stava 已提交
1289
			link[min(len, PATH_MAX-1)] = 0;
1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
	}
	nd_set_link(nd, link);

	return NULL;
}

/**
 * v9fs_vfs_put_link - release a symlink path
 * @dentry: dentry for symlink
 * @nd: nameidata
E
Eric Van Hensbergen 已提交
1300
 * @p: unused
1301 1302 1303
 *
 */

1304
void
E
Eric Van Hensbergen 已提交
1305
v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
1306 1307 1308
{
	char *s = nd_get_link(nd);

1309 1310
	p9_debug(P9_DEBUG_VFS, " %s %s\n",
		 dentry->d_name.name, IS_ERR(s) ? "<error>" : s);
1311
	if (!IS_ERR(s))
1312
		__putname(s);
1313 1314
}

E
Eric Van Hensbergen 已提交
1315 1316 1317 1318 1319 1320 1321 1322 1323
/**
 * v9fs_vfs_mkspecial - create a special file
 * @dir: inode to create special file in
 * @dentry: dentry to create
 * @mode: mode to create special file
 * @extension: 9p2000.u format extension string representing special file
 *
 */

1324
static int v9fs_vfs_mkspecial(struct inode *dir, struct dentry *dentry,
1325
	u32 perm, const char *extension)
1326
{
1327
	struct p9_fid *fid;
1328
	struct v9fs_session_info *v9ses;
1329

1330
	v9ses = v9fs_inode2v9ses(dir);
1331
	if (!v9fs_proto_dotu(v9ses)) {
1332
		p9_debug(P9_DEBUG_ERROR, "not extended\n");
1333
		return -EPERM;
1334 1335
	}

1336 1337 1338 1339
	fid = v9fs_create(v9ses, dir, dentry, (char *) extension, perm,
								P9_OREAD);
	if (IS_ERR(fid))
		return PTR_ERR(fid);
1340

1341
	v9fs_invalidate_inode_attr(dir);
1342
	p9_client_clunk(fid);
1343
	return 0;
1344 1345 1346 1347 1348 1349 1350 1351
}

/**
 * v9fs_vfs_symlink - helper function to create symlinks
 * @dir: directory inode containing symlink
 * @dentry: dentry for symlink
 * @symname: symlink data
 *
E
Eric Van Hensbergen 已提交
1352
 * See Also: 9P2000.u RFC for more information
1353 1354 1355 1356 1357 1358
 *
 */

static int
v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
{
1359 1360
	p9_debug(P9_DEBUG_VFS, " %lu,%s,%s\n",
		 dir->i_ino, dentry->d_name.name, symname);
1361

1362
	return v9fs_vfs_mkspecial(dir, dentry, P9_DMSYMLINK, symname);
1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378
}

/**
 * v9fs_vfs_link - create a hardlink
 * @old_dentry: dentry for file to link to
 * @dir: inode destination for new link
 * @dentry: dentry for link
 *
 */

static int
v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
	      struct dentry *dentry)
{
	int retval;
	char *name;
1379
	struct p9_fid *oldfid;
1380

1381 1382
	p9_debug(P9_DEBUG_VFS, " %lu,%s,%s\n",
		 dir->i_ino, dentry->d_name.name, old_dentry->d_name.name);
1383

1384
	oldfid = v9fs_fid_clone(old_dentry);
L
Latchesar Ionkov 已提交
1385
	if (IS_ERR(oldfid))
1386
		return PTR_ERR(oldfid);
1387 1388

	name = __getname();
1389 1390 1391 1392
	if (unlikely(!name)) {
		retval = -ENOMEM;
		goto clunk_fid;
	}
1393

1394
	sprintf(name, "%d\n", oldfid->fid);
1395
	retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name);
1396
	__putname(name);
1397 1398
	if (!retval) {
		v9fs_refresh_inode(oldfid, old_dentry->d_inode);
1399
		v9fs_invalidate_inode_attr(dir);
1400
	}
1401
clunk_fid:
1402
	p9_client_clunk(oldfid);
1403 1404 1405 1406 1407 1408 1409 1410
	return retval;
}

/**
 * v9fs_vfs_mknod - create a special file
 * @dir: inode destination for new link
 * @dentry: dentry for file
 * @mode: mode for creation
E
Eric Van Hensbergen 已提交
1411
 * @rdev: device associated with special file
1412 1413 1414 1415
 *
 */

static int
A
Al Viro 已提交
1416
v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev)
1417
{
1418
	struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
1419 1420
	int retval;
	char *name;
1421
	u32 perm;
1422

1423
	p9_debug(P9_DEBUG_VFS, " %lu,%s mode: %hx MAJOR: %u MINOR: %u\n",
1424 1425
		 dir->i_ino, dentry->d_name.name, mode,
		 MAJOR(rdev), MINOR(rdev));
1426

1427 1428
	if (!new_valid_dev(rdev))
		return -EINVAL;
1429

1430
	name = __getname();
1431 1432
	if (!name)
		return -ENOMEM;
1433 1434
	/* build extension */
	if (S_ISBLK(mode))
1435
		sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev));
1436
	else if (S_ISCHR(mode))
1437
		sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev));
1438
	else if (S_ISFIFO(mode))
1439
		*name = 0;
V
Venkateswararao Jujjuri 已提交
1440 1441
	else if (S_ISSOCK(mode))
		*name = 0;
1442
	else {
1443 1444
		__putname(name);
		return -EINVAL;
1445 1446
	}

1447 1448
	perm = unixmode2p9mode(v9ses, mode);
	retval = v9fs_vfs_mkspecial(dir, dentry, perm, name);
1449
	__putname(name);
1450 1451 1452 1453

	return retval;
}

1454 1455
int v9fs_refresh_inode(struct p9_fid *fid, struct inode *inode)
{
1456 1457
	int umode;
	dev_t rdev;
1458 1459 1460 1461 1462 1463 1464 1465
	loff_t i_size;
	struct p9_wstat *st;
	struct v9fs_session_info *v9ses;

	v9ses = v9fs_inode2v9ses(inode);
	st = p9_client_stat(fid);
	if (IS_ERR(st))
		return PTR_ERR(st);
1466 1467 1468 1469 1470 1471
	/*
	 * Don't update inode if the file type is different
	 */
	umode = p9mode2unixmode(v9ses, st, &rdev);
	if ((inode->i_mode & S_IFMT) != (umode & S_IFMT))
		goto out;
1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482

	spin_lock(&inode->i_lock);
	/*
	 * We don't want to refresh inode->i_size,
	 * because we may have cached data
	 */
	i_size = inode->i_size;
	v9fs_stat2inode(st, inode, inode->i_sb);
	if (v9ses->cache)
		inode->i_size = i_size;
	spin_unlock(&inode->i_lock);
1483
out:
1484 1485 1486 1487 1488
	p9stat_free(st);
	kfree(st);
	return 0;
}

1489 1490 1491
static const struct inode_operations v9fs_dir_inode_operations_dotu = {
	.create = v9fs_vfs_create,
	.lookup = v9fs_vfs_lookup,
1492
	.atomic_open = v9fs_vfs_atomic_open,
1493
	.symlink = v9fs_vfs_symlink,
1494
	.link = v9fs_vfs_link,
1495 1496 1497
	.unlink = v9fs_vfs_unlink,
	.mkdir = v9fs_vfs_mkdir,
	.rmdir = v9fs_vfs_rmdir,
1498
	.mknod = v9fs_vfs_mknod,
1499 1500 1501 1502 1503
	.rename = v9fs_vfs_rename,
	.getattr = v9fs_vfs_getattr,
	.setattr = v9fs_vfs_setattr,
};

1504
static const struct inode_operations v9fs_dir_inode_operations = {
1505 1506
	.create = v9fs_vfs_create,
	.lookup = v9fs_vfs_lookup,
1507
	.atomic_open = v9fs_vfs_atomic_open,
1508 1509 1510 1511 1512 1513 1514 1515 1516
	.unlink = v9fs_vfs_unlink,
	.mkdir = v9fs_vfs_mkdir,
	.rmdir = v9fs_vfs_rmdir,
	.mknod = v9fs_vfs_mknod,
	.rename = v9fs_vfs_rename,
	.getattr = v9fs_vfs_getattr,
	.setattr = v9fs_vfs_setattr,
};

1517
static const struct inode_operations v9fs_file_inode_operations = {
1518 1519 1520 1521
	.getattr = v9fs_vfs_getattr,
	.setattr = v9fs_vfs_setattr,
};

1522
static const struct inode_operations v9fs_symlink_inode_operations = {
A
Al Viro 已提交
1523
	.readlink = generic_readlink,
1524 1525 1526 1527 1528
	.follow_link = v9fs_vfs_follow_link,
	.put_link = v9fs_vfs_put_link,
	.getattr = v9fs_vfs_getattr,
	.setattr = v9fs_vfs_setattr,
};
1529