vfs_inode_dotl.c 25.6 KB
Newer Older
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 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
/*
 *  linux/fs/9p/vfs_inode_dotl.c
 *
 * This file contains vfs inode ops for the 9P2000.L protocol.
 *
 *  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
 *  it under the terms of the GNU General Public License version 2
 *  as published by the Free Software Foundation.
 *
 *  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
 *
 */

#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>
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/xattr.h>
#include <linux/posix_acl.h>
#include <net/9p/9p.h>
#include <net/9p/client.h>

#include "v9fs.h"
#include "v9fs_vfs.h"
#include "fid.h"
#include "cache.h"
#include "xattr.h"
#include "acl.h"

static int
A
Al Viro 已提交
51
v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
		    dev_t rdev);

/**
 * v9fs_get_fsgid_for_create - Helper function to get the gid for creating a
 * new file system object. This checks the S_ISGID to determine the owning
 * group of the new file system object.
 */

static gid_t v9fs_get_fsgid_for_create(struct inode *dir_inode)
{
	BUG_ON(dir_inode == NULL);

	if (dir_inode->i_mode & S_ISGID) {
		/* set_gid bit is set.*/
		return dir_inode->i_gid;
	}
	return current_fsgid();
}

/**
 * v9fs_dentry_from_dir_inode - helper function to get the dentry from
 * dir inode.
 *
 */

static struct dentry *v9fs_dentry_from_dir_inode(struct inode *inode)
{
	struct dentry *dentry;

	spin_lock(&inode->i_lock);
	/* Directory should have only one entry. */
	BUG_ON(S_ISDIR(inode->i_mode) && !list_is_singular(&inode->i_dentry));
	dentry = list_entry(inode->i_dentry.next, struct dentry, d_alias);
	spin_unlock(&inode->i_lock);
	return dentry;
}

89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
static int v9fs_test_inode_dotl(struct inode *inode, void *data)
{
	struct v9fs_inode *v9inode = V9FS_I(inode);
	struct p9_stat_dotl *st = (struct p9_stat_dotl *)data;

	/* don't match inode of different type */
	if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT))
		return 0;

	if (inode->i_generation != st->st_gen)
		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;
}

111 112 113 114 115 116
/* Always get a new inode */
static int v9fs_test_new_inode_dotl(struct inode *inode, void *data)
{
	return 0;
}

117 118 119 120 121 122 123 124 125 126
static int v9fs_set_inode_dotl(struct inode *inode,  void *data)
{
	struct v9fs_inode *v9inode = V9FS_I(inode);
	struct p9_stat_dotl *st = (struct p9_stat_dotl *)data;

	memcpy(&v9inode->qid, &st->qid, sizeof(st->qid));
	inode->i_generation = st->st_gen;
	return 0;
}

A
Aneesh Kumar K.V 已提交
127 128 129
static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,
					struct p9_qid *qid,
					struct p9_fid *fid,
130 131
					struct p9_stat_dotl *st,
					int new)
A
Aneesh Kumar K.V 已提交
132 133 134 135 136
{
	int retval;
	unsigned long i_ino;
	struct inode *inode;
	struct v9fs_session_info *v9ses = sb->s_fs_info;
137 138 139 140 141 142
	int (*test)(struct inode *, void *);

	if (new)
		test = v9fs_test_new_inode_dotl;
	else
		test = v9fs_test_inode_dotl;
A
Aneesh Kumar K.V 已提交
143 144

	i_ino = v9fs_qid2ino(qid);
145
	inode = iget5_locked(sb, i_ino, test, v9fs_set_inode_dotl, st);
A
Aneesh Kumar K.V 已提交
146 147 148 149 150 151 152 153 154
	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.
	 */
155
	inode->i_ino = i_ino;
156 157
	retval = v9fs_init_inode(v9ses, inode,
				 st->st_mode, new_decode_dev(st->st_rdev));
A
Aneesh Kumar K.V 已提交
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
	if (retval)
		goto error;

	v9fs_stat2inode_dotl(st, inode);
#ifdef CONFIG_9P_FSCACHE
	v9fs_cache_inode_get_cookie(inode);
#endif
	retval = v9fs_get_acl(inode, fid);
	if (retval)
		goto error;

	unlock_new_inode(inode);
	return inode;
error:
	unlock_new_inode(inode);
	iput(inode);
	return ERR_PTR(retval);

}

178
struct inode *
A
Aneesh Kumar K.V 已提交
179
v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
180
			 struct super_block *sb, int new)
181 182
{
	struct p9_stat_dotl *st;
A
Aneesh Kumar K.V 已提交
183
	struct inode *inode = NULL;
184

185
	st = p9_client_getattr_dotl(fid, P9_STATS_BASIC | P9_STATS_GEN);
186 187 188
	if (IS_ERR(st))
		return ERR_CAST(st);

189
	inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st, new);
190
	kfree(st);
A
Aneesh Kumar K.V 已提交
191
	return inode;
192 193
}

194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
struct dotl_openflag_map {
	int open_flag;
	int dotl_flag;
};

static int v9fs_mapped_dotl_flags(int flags)
{
	int i;
	int rflags = 0;
	struct dotl_openflag_map dotl_oflag_map[] = {
		{ O_CREAT,	P9_DOTL_CREATE },
		{ O_EXCL,	P9_DOTL_EXCL },
		{ O_NOCTTY,	P9_DOTL_NOCTTY },
		{ O_TRUNC,	P9_DOTL_TRUNC },
		{ O_APPEND,	P9_DOTL_APPEND },
		{ O_NONBLOCK,	P9_DOTL_NONBLOCK },
		{ O_DSYNC,	P9_DOTL_DSYNC },
		{ FASYNC,	P9_DOTL_FASYNC },
		{ O_DIRECT,	P9_DOTL_DIRECT },
		{ O_LARGEFILE,	P9_DOTL_LARGEFILE },
		{ O_DIRECTORY,	P9_DOTL_DIRECTORY },
		{ O_NOFOLLOW,	P9_DOTL_NOFOLLOW },
		{ O_NOATIME,	P9_DOTL_NOATIME },
		{ O_CLOEXEC,	P9_DOTL_CLOEXEC },
		{ O_SYNC,	P9_DOTL_SYNC},
	};
	for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
		if (flags & dotl_oflag_map[i].open_flag)
			rflags |= dotl_oflag_map[i].dotl_flag;
	}
	return rflags;
}

/**
 * v9fs_open_to_dotl_flags- convert Linux specific open flags to
 * plan 9 open flag.
 * @flags: flags to convert
 */
int v9fs_open_to_dotl_flags(int flags)
{
	int rflags = 0;

	/*
	 * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
	 * and P9_DOTL_NOACCESS
	 */
	rflags |= flags & O_ACCMODE;
	rflags |= v9fs_mapped_dotl_flags(flags);

	return rflags;
}

246 247 248 249 250 251 252 253 254 255
/**
 * v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol.
 * @dir: directory inode that is being created
 * @dentry:  dentry that is being deleted
 * @mode: create permissions
 * @nd: path information
 *
 */

static int
A
Al Viro 已提交
256
v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
257 258 259 260 261
		struct nameidata *nd)
{
	int err = 0;
	gid_t gid;
	int flags;
A
Al Viro 已提交
262
	umode_t mode;
263
	char *name = NULL;
264 265 266
	struct file *filp;
	struct p9_qid qid;
	struct inode *inode;
267 268 269 270
	struct p9_fid *fid = NULL;
	struct v9fs_inode *v9inode;
	struct p9_fid *dfid, *ofid, *inode_fid;
	struct v9fs_session_info *v9ses;
271 272 273
	struct posix_acl *pacl = NULL, *dacl = NULL;

	v9ses = v9fs_inode2v9ses(dir);
274
	if (nd)
275
		flags = nd->intent.open.flags;
276 277 278 279 280 281 282 283 284 285
	else {
		/*
		 * create call without LOOKUP_OPEN is due
		 * to mknod of regular files. So use mknod
		 * operation.
		 */
		return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
	}

	name = (char *) dentry->d_name.name;
286
	p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%hx\n",
287
		 name, flags, omode);
288 289 290 291

	dfid = v9fs_fid_lookup(dentry->d_parent);
	if (IS_ERR(dfid)) {
		err = PTR_ERR(dfid);
292
		p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
293 294 295 296 297 298 299
		return err;
	}

	/* clone a fid to use for creation */
	ofid = p9_client_walk(dfid, 0, NULL, 1);
	if (IS_ERR(ofid)) {
		err = PTR_ERR(ofid);
300
		p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
301 302 303 304 305 306 307 308 309
		return err;
	}

	gid = v9fs_get_fsgid_for_create(dir);

	mode = omode;
	/* Update mode based on ACL value */
	err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
	if (err) {
310 311
		p9_debug(P9_DEBUG_VFS, "Failed to get acl values in creat %d\n",
			 err);
312 313
		goto error;
	}
314 315
	err = p9_client_create_dotl(ofid, name, v9fs_open_to_dotl_flags(flags),
				    mode, gid, &qid);
316
	if (err < 0) {
317 318
		p9_debug(P9_DEBUG_VFS, "p9_client_open_dotl failed in creat %d\n",
			 err);
319 320
		goto error;
	}
321
	v9fs_invalidate_inode_attr(dir);
322

323 324 325 326
	/* instantiate inode and assign the unopened fid to the dentry */
	fid = p9_client_walk(dfid, 1, &name, 1);
	if (IS_ERR(fid)) {
		err = PTR_ERR(fid);
327
		p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
328
		fid = NULL;
329
		goto error;
330
	}
331
	inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
332 333
	if (IS_ERR(inode)) {
		err = PTR_ERR(inode);
334
		p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", err);
335 336 337 338 339
		goto error;
	}
	err = v9fs_fid_add(dentry, fid);
	if (err < 0)
		goto error;
340
	d_instantiate(dentry, inode);
341

342
	/* Now set the ACL based on the default value */
A
Al Viro 已提交
343
	v9fs_set_create_acl(dentry, &dacl, &pacl);
344 345

	v9inode = V9FS_I(inode);
346
	mutex_lock(&v9inode->v_mutex);
347 348
	if (v9ses->cache && !v9inode->writeback_fid &&
	    ((flags & O_ACCMODE) != O_RDONLY)) {
349
		/*
350
		 * clone a fid and add it to writeback_fid
351 352 353 354 355 356 357 358
		 * 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);
359
			mutex_unlock(&v9inode->v_mutex);
360
			goto err_clunk_old_fid;
361
		}
362
		v9inode->writeback_fid = (void *) inode_fid;
363
	}
364
	mutex_unlock(&v9inode->v_mutex);
365 366 367
	/* Since we are opening a file, assign the open fid to the file */
	filp = lookup_instantiate_filp(nd, dentry, generic_file_open);
	if (IS_ERR(filp)) {
368 369
		err = PTR_ERR(filp);
		goto err_clunk_old_fid;
370 371
	}
	filp->private_data = ofid;
372 373 374 375
#ifdef CONFIG_9P_FSCACHE
	if (v9ses->cache)
		v9fs_cache_inode_set_cookie(inode, filp);
#endif
376 377 378 379 380
	return 0;

error:
	if (fid)
		p9_client_clunk(fid);
381 382 383
err_clunk_old_fid:
	if (ofid)
		p9_client_clunk(ofid);
A
Al Viro 已提交
384
	v9fs_set_create_acl(NULL, &dacl, &pacl);
385 386 387 388 389 390 391 392 393 394 395 396
	return err;
}

/**
 * v9fs_vfs_mkdir_dotl - VFS mkdir hook to create a directory
 * @dir:  inode that is being unlinked
 * @dentry: dentry that is being unlinked
 * @mode: mode for new directory
 *
 */

static int v9fs_vfs_mkdir_dotl(struct inode *dir,
397
			       struct dentry *dentry, umode_t omode)
398 399 400 401 402 403
{
	int err;
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid = NULL, *dfid = NULL;
	gid_t gid;
	char *name;
A
Al Viro 已提交
404
	umode_t mode;
405 406 407 408 409
	struct inode *inode;
	struct p9_qid qid;
	struct dentry *dir_dentry;
	struct posix_acl *dacl = NULL, *pacl = NULL;

410
	p9_debug(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
411 412 413 414 415 416 417 418 419 420 421
	err = 0;
	v9ses = v9fs_inode2v9ses(dir);

	omode |= S_IFDIR;
	if (dir->i_mode & S_ISGID)
		omode |= S_ISGID;

	dir_dentry = v9fs_dentry_from_dir_inode(dir);
	dfid = v9fs_fid_lookup(dir_dentry);
	if (IS_ERR(dfid)) {
		err = PTR_ERR(dfid);
422
		p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
423 424 425 426 427 428 429 430 431
		dfid = NULL;
		goto error;
	}

	gid = v9fs_get_fsgid_for_create(dir);
	mode = omode;
	/* Update mode based on ACL value */
	err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
	if (err) {
432 433
		p9_debug(P9_DEBUG_VFS, "Failed to get acl values in mkdir %d\n",
			 err);
434 435 436 437 438 439 440 441 442 443 444 445
		goto error;
	}
	name = (char *) dentry->d_name.name;
	err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid);
	if (err < 0)
		goto error;

	/* instantiate inode and assign the unopened fid to the dentry */
	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
		fid = p9_client_walk(dfid, 1, &name, 1);
		if (IS_ERR(fid)) {
			err = PTR_ERR(fid);
446 447
			p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
				 err);
448 449 450 451
			fid = NULL;
			goto error;
		}

452
		inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
453 454
		if (IS_ERR(inode)) {
			err = PTR_ERR(inode);
455 456
			p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
				 err);
457 458 459 460 461
			goto error;
		}
		err = v9fs_fid_add(dentry, fid);
		if (err < 0)
			goto error;
462
		d_instantiate(dentry, inode);
463 464 465 466 467 468 469
		fid = NULL;
	} else {
		/*
		 * Not in cached mode. No need to populate
		 * inode with stat. We need to get an inode
		 * so that we can set the acl with dentry
		 */
470
		inode = v9fs_get_inode(dir->i_sb, mode, 0);
471 472 473 474 475 476 477
		if (IS_ERR(inode)) {
			err = PTR_ERR(inode);
			goto error;
		}
		d_instantiate(dentry, inode);
	}
	/* Now set the ACL based on the default value */
A
Al Viro 已提交
478
	v9fs_set_create_acl(dentry, &dacl, &pacl);
479
	inc_nlink(dir);
480
	v9fs_invalidate_inode_attr(dir);
481 482 483
error:
	if (fid)
		p9_client_clunk(fid);
A
Al Viro 已提交
484
	v9fs_set_create_acl(NULL, &dacl, &pacl);
485 486 487 488 489 490 491 492 493 494 495 496
	return err;
}

static int
v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry,
		 struct kstat *stat)
{
	int err;
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid;
	struct p9_stat_dotl *st;

497
	p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
498
	err = -EPERM;
A
Aneesh Kumar K.V 已提交
499
	v9ses = v9fs_dentry2v9ses(dentry);
500 501 502 503
	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
		generic_fillattr(dentry->d_inode, stat);
		return 0;
	}
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524
	fid = v9fs_fid_lookup(dentry);
	if (IS_ERR(fid))
		return PTR_ERR(fid);

	/* Ask for all the fields in stat structure. Server will return
	 * whatever it supports
	 */

	st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
	if (IS_ERR(st))
		return PTR_ERR(st);

	v9fs_stat2inode_dotl(st, dentry->d_inode);
	generic_fillattr(dentry->d_inode, stat);
	/* Change block size to what the server returned */
	stat->blksize = st->st_blksize;

	kfree(st);
	return 0;
}

525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564
/*
 * Attribute flags.
 */
#define P9_ATTR_MODE		(1 << 0)
#define P9_ATTR_UID		(1 << 1)
#define P9_ATTR_GID		(1 << 2)
#define P9_ATTR_SIZE		(1 << 3)
#define P9_ATTR_ATIME		(1 << 4)
#define P9_ATTR_MTIME		(1 << 5)
#define P9_ATTR_CTIME		(1 << 6)
#define P9_ATTR_ATIME_SET	(1 << 7)
#define P9_ATTR_MTIME_SET	(1 << 8)

struct dotl_iattr_map {
	int iattr_valid;
	int p9_iattr_valid;
};

static int v9fs_mapped_iattr_valid(int iattr_valid)
{
	int i;
	int p9_iattr_valid = 0;
	struct dotl_iattr_map dotl_iattr_map[] = {
		{ ATTR_MODE,		P9_ATTR_MODE },
		{ ATTR_UID,		P9_ATTR_UID },
		{ ATTR_GID,		P9_ATTR_GID },
		{ ATTR_SIZE,		P9_ATTR_SIZE },
		{ ATTR_ATIME,		P9_ATTR_ATIME },
		{ ATTR_MTIME,		P9_ATTR_MTIME },
		{ ATTR_CTIME,		P9_ATTR_CTIME },
		{ ATTR_ATIME_SET,	P9_ATTR_ATIME_SET },
		{ ATTR_MTIME_SET,	P9_ATTR_MTIME_SET },
	};
	for (i = 0; i < ARRAY_SIZE(dotl_iattr_map); i++) {
		if (iattr_valid & dotl_iattr_map[i].iattr_valid)
			p9_iattr_valid |= dotl_iattr_map[i].p9_iattr_valid;
	}
	return p9_iattr_valid;
}

565 566 567 568 569 570 571 572 573 574 575 576 577 578
/**
 * v9fs_vfs_setattr_dotl - set file metadata
 * @dentry: file whose metadata to set
 * @iattr: metadata assignment structure
 *
 */

int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
{
	int retval;
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid;
	struct p9_iattr_dotl p9attr;

579
	p9_debug(P9_DEBUG_VFS, "\n");
580 581 582 583 584

	retval = inode_change_ok(dentry->d_inode, iattr);
	if (retval)
		return retval;

585
	p9attr.valid = v9fs_mapped_iattr_valid(iattr->ia_valid);
586 587 588 589 590 591 592 593 594 595
	p9attr.mode = iattr->ia_mode;
	p9attr.uid = iattr->ia_uid;
	p9attr.gid = iattr->ia_gid;
	p9attr.size = iattr->ia_size;
	p9attr.atime_sec = iattr->ia_atime.tv_sec;
	p9attr.atime_nsec = iattr->ia_atime.tv_nsec;
	p9attr.mtime_sec = iattr->ia_mtime.tv_sec;
	p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec;

	retval = -EPERM;
A
Aneesh Kumar K.V 已提交
596
	v9ses = v9fs_dentry2v9ses(dentry);
597 598 599 600
	fid = v9fs_fid_lookup(dentry);
	if (IS_ERR(fid))
		return PTR_ERR(fid);

601 602 603 604
	/* Write all dirty data */
	if (S_ISREG(dentry->d_inode->i_mode))
		filemap_write_and_wait(dentry->d_inode->i_mapping);

605 606 607
	retval = p9_client_setattr(fid, &p9attr);
	if (retval < 0)
		return retval;
608

609 610 611 612 613
	if ((iattr->ia_valid & ATTR_SIZE) &&
	    iattr->ia_size != i_size_read(dentry->d_inode))
		truncate_setsize(dentry->d_inode, iattr->ia_size);

	v9fs_invalidate_inode_attr(dentry->d_inode);
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635
	setattr_copy(dentry->d_inode, iattr);
	mark_inode_dirty(dentry->d_inode);
	if (iattr->ia_valid & ATTR_MODE) {
		/* We also want to update ACL when we update mode bits */
		retval = v9fs_acl_chmod(dentry);
		if (retval < 0)
			return retval;
	}
	return 0;
}

/**
 * v9fs_stat2inode_dotl - populate an inode structure with stat info
 * @stat: stat structure
 * @inode: inode to populate
 * @sb: superblock of filesystem
 *
 */

void
v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
{
A
Al Viro 已提交
636
	umode_t mode;
637
	struct v9fs_inode *v9inode = V9FS_I(inode);
638 639 640 641 642 643 644 645 646 647

	if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) {
		inode->i_atime.tv_sec = stat->st_atime_sec;
		inode->i_atime.tv_nsec = stat->st_atime_nsec;
		inode->i_mtime.tv_sec = stat->st_mtime_sec;
		inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
		inode->i_ctime.tv_sec = stat->st_ctime_sec;
		inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
		inode->i_uid = stat->st_uid;
		inode->i_gid = stat->st_gid;
M
Miklos Szeredi 已提交
648
		set_nlink(inode, stat->st_nlink);
649

650 651 652
		mode = stat->st_mode & S_IALLUGO;
		mode |= inode->i_mode & ~S_IALLUGO;
		inode->i_mode = mode;
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673

		i_size_write(inode, stat->st_size);
		inode->i_blocks = stat->st_blocks;
	} else {
		if (stat->st_result_mask & P9_STATS_ATIME) {
			inode->i_atime.tv_sec = stat->st_atime_sec;
			inode->i_atime.tv_nsec = stat->st_atime_nsec;
		}
		if (stat->st_result_mask & P9_STATS_MTIME) {
			inode->i_mtime.tv_sec = stat->st_mtime_sec;
			inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
		}
		if (stat->st_result_mask & P9_STATS_CTIME) {
			inode->i_ctime.tv_sec = stat->st_ctime_sec;
			inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
		}
		if (stat->st_result_mask & P9_STATS_UID)
			inode->i_uid = stat->st_uid;
		if (stat->st_result_mask & P9_STATS_GID)
			inode->i_gid = stat->st_gid;
		if (stat->st_result_mask & P9_STATS_NLINK)
M
Miklos Szeredi 已提交
674
			set_nlink(inode, stat->st_nlink);
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
		if (stat->st_result_mask & P9_STATS_MODE) {
			inode->i_mode = stat->st_mode;
			if ((S_ISBLK(inode->i_mode)) ||
						(S_ISCHR(inode->i_mode)))
				init_special_inode(inode, inode->i_mode,
								inode->i_rdev);
		}
		if (stat->st_result_mask & P9_STATS_RDEV)
			inode->i_rdev = new_decode_dev(stat->st_rdev);
		if (stat->st_result_mask & P9_STATS_SIZE)
			i_size_write(inode, stat->st_size);
		if (stat->st_result_mask & P9_STATS_BLOCKS)
			inode->i_blocks = stat->st_blocks;
	}
	if (stat->st_result_mask & P9_STATS_GEN)
690
		inode->i_generation = stat->st_gen;
691 692 693 694

	/* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION
	 * because the inode structure does not have fields for them.
	 */
695
	v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR;
696 697 698 699 700 701 702 703
}

static int
v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
		const char *symname)
{
	int err;
	gid_t gid;
704 705 706 707 708 709
	char *name;
	struct p9_qid qid;
	struct inode *inode;
	struct p9_fid *dfid;
	struct p9_fid *fid = NULL;
	struct v9fs_session_info *v9ses;
710 711

	name = (char *) dentry->d_name.name;
712
	p9_debug(P9_DEBUG_VFS, "%lu,%s,%s\n", dir->i_ino, name, symname);
713 714 715 716 717
	v9ses = v9fs_inode2v9ses(dir);

	dfid = v9fs_fid_lookup(dentry->d_parent);
	if (IS_ERR(dfid)) {
		err = PTR_ERR(dfid);
718
		p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
719 720 721 722 723 724 725 726 727
		return err;
	}

	gid = v9fs_get_fsgid_for_create(dir);

	/* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */
	err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid);

	if (err < 0) {
728
		p9_debug(P9_DEBUG_VFS, "p9_client_symlink failed %d\n", err);
729 730 731
		goto error;
	}

732
	v9fs_invalidate_inode_attr(dir);
733 734 735 736 737
	if (v9ses->cache) {
		/* Now walk from the parent so we can get an unopened fid. */
		fid = p9_client_walk(dfid, 1, &name, 1);
		if (IS_ERR(fid)) {
			err = PTR_ERR(fid);
738 739
			p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
				 err);
740 741 742 743 744
			fid = NULL;
			goto error;
		}

		/* instantiate inode and assign the unopened fid to dentry */
745
		inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
746 747
		if (IS_ERR(inode)) {
			err = PTR_ERR(inode);
748 749
			p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
				 err);
750 751 752 753 754
			goto error;
		}
		err = v9fs_fid_add(dentry, fid);
		if (err < 0)
			goto error;
755
		d_instantiate(dentry, inode);
756 757 758
		fid = NULL;
	} else {
		/* Not in cached mode. No need to populate inode with stat */
759
		inode = v9fs_get_inode(dir->i_sb, S_IFLNK, 0);
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788
		if (IS_ERR(inode)) {
			err = PTR_ERR(inode);
			goto error;
		}
		d_instantiate(dentry, inode);
	}

error:
	if (fid)
		p9_client_clunk(fid);

	return err;
}

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

static int
v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
		struct dentry *dentry)
{
	int err;
	char *name;
	struct dentry *dir_dentry;
789 790
	struct p9_fid *dfid, *oldfid;
	struct v9fs_session_info *v9ses;
791

792 793
	p9_debug(P9_DEBUG_VFS, "dir ino: %lu, old_name: %s, new_name: %s\n",
		 dir->i_ino, old_dentry->d_name.name, dentry->d_name.name);
794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809

	v9ses = v9fs_inode2v9ses(dir);
	dir_dentry = v9fs_dentry_from_dir_inode(dir);
	dfid = v9fs_fid_lookup(dir_dentry);
	if (IS_ERR(dfid))
		return PTR_ERR(dfid);

	oldfid = v9fs_fid_lookup(old_dentry);
	if (IS_ERR(oldfid))
		return PTR_ERR(oldfid);

	name = (char *) dentry->d_name.name;

	err = p9_client_link(dfid, oldfid, (char *)dentry->d_name.name);

	if (err < 0) {
810
		p9_debug(P9_DEBUG_VFS, "p9_client_link failed %d\n", err);
811 812 813
		return err;
	}

814
	v9fs_invalidate_inode_attr(dir);
815 816 817 818 819 820 821
	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
		/* Get the latest stat info from server. */
		struct p9_fid *fid;
		fid = v9fs_fid_lookup(old_dentry);
		if (IS_ERR(fid))
			return PTR_ERR(fid);

822
		v9fs_refresh_inode_dotl(fid, old_dentry->d_inode);
823
	}
824
	ihold(old_dentry->d_inode);
825 826 827 828 829 830 831 832 833 834 835 836 837 838
	d_instantiate(dentry, old_dentry->d_inode);

	return err;
}

/**
 * v9fs_vfs_mknod_dotl - create a special file
 * @dir: inode destination for new link
 * @dentry: dentry for file
 * @mode: mode for creation
 * @rdev: device associated with special file
 *
 */
static int
A
Al Viro 已提交
839
v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
840 841 842
		dev_t rdev)
{
	int err;
843
	gid_t gid;
844
	char *name;
A
Al Viro 已提交
845
	umode_t mode;
846 847 848 849 850 851 852
	struct v9fs_session_info *v9ses;
	struct p9_fid *fid = NULL, *dfid = NULL;
	struct inode *inode;
	struct p9_qid qid;
	struct dentry *dir_dentry;
	struct posix_acl *dacl = NULL, *pacl = NULL;

853
	p9_debug(P9_DEBUG_VFS, " %lu,%s mode: %hx MAJOR: %u MINOR: %u\n",
854 855
		 dir->i_ino, dentry->d_name.name, omode,
		 MAJOR(rdev), MINOR(rdev));
856 857 858 859 860 861 862 863 864

	if (!new_valid_dev(rdev))
		return -EINVAL;

	v9ses = v9fs_inode2v9ses(dir);
	dir_dentry = v9fs_dentry_from_dir_inode(dir);
	dfid = v9fs_fid_lookup(dir_dentry);
	if (IS_ERR(dfid)) {
		err = PTR_ERR(dfid);
865
		p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
866 867 868 869 870 871 872 873 874
		dfid = NULL;
		goto error;
	}

	gid = v9fs_get_fsgid_for_create(dir);
	mode = omode;
	/* Update mode based on ACL value */
	err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
	if (err) {
875 876
		p9_debug(P9_DEBUG_VFS, "Failed to get acl values in mknod %d\n",
			 err);
877 878 879 880 881 882 883 884
		goto error;
	}
	name = (char *) dentry->d_name.name;

	err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid);
	if (err < 0)
		goto error;

885
	v9fs_invalidate_inode_attr(dir);
886 887 888 889 890
	/* instantiate inode and assign the unopened fid to the dentry */
	if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
		fid = p9_client_walk(dfid, 1, &name, 1);
		if (IS_ERR(fid)) {
			err = PTR_ERR(fid);
891 892
			p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
				 err);
893 894 895 896
			fid = NULL;
			goto error;
		}

897
		inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
898 899
		if (IS_ERR(inode)) {
			err = PTR_ERR(inode);
900 901
			p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
				 err);
902 903 904 905 906
			goto error;
		}
		err = v9fs_fid_add(dentry, fid);
		if (err < 0)
			goto error;
907
		d_instantiate(dentry, inode);
908 909 910 911 912 913
		fid = NULL;
	} else {
		/*
		 * Not in cached mode. No need to populate inode with stat.
		 * socket syscall returns a fd, so we need instantiate
		 */
914
		inode = v9fs_get_inode(dir->i_sb, mode, rdev);
915 916 917 918 919 920 921
		if (IS_ERR(inode)) {
			err = PTR_ERR(inode);
			goto error;
		}
		d_instantiate(dentry, inode);
	}
	/* Now set the ACL based on the default value */
A
Al Viro 已提交
922
	v9fs_set_create_acl(dentry, &dacl, &pacl);
923 924 925
error:
	if (fid)
		p9_client_clunk(fid);
A
Al Viro 已提交
926
	v9fs_set_create_acl(NULL, &dacl, &pacl);
927 928 929 930 931 932 933 934 935 936 937 938 939
	return err;
}

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

static void *
v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd)
{
M
M. Mohan Kumar 已提交
940 941
	int retval;
	struct p9_fid *fid;
942
	char *link = __getname();
M
M. Mohan Kumar 已提交
943
	char *target;
944

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

M
M. Mohan Kumar 已提交
947
	if (!link) {
948
		link = ERR_PTR(-ENOMEM);
M
M. Mohan Kumar 已提交
949
		goto ndset;
950
	}
M
M. Mohan Kumar 已提交
951 952 953
	fid = v9fs_fid_lookup(dentry);
	if (IS_ERR(fid)) {
		__putname(link);
954
		link = ERR_CAST(fid);
M
M. Mohan Kumar 已提交
955 956 957 958 959 960 961 962 963 964 965
		goto ndset;
	}
	retval = p9_client_readlink(fid, &target);
	if (!retval) {
		strcpy(link, target);
		kfree(target);
		goto ndset;
	}
	__putname(link);
	link = ERR_PTR(retval);
ndset:
966 967 968 969
	nd_set_link(nd, link);
	return NULL;
}

970 971 972 973 974 975 976 977 978 979
int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
{
	loff_t i_size;
	struct p9_stat_dotl *st;
	struct v9fs_session_info *v9ses;

	v9ses = v9fs_inode2v9ses(inode);
	st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
	if (IS_ERR(st))
		return PTR_ERR(st);
980 981 982 983 984
	/*
	 * Don't update inode if the file type is different
	 */
	if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT))
		goto out;
985 986 987 988 989 990 991 992 993 994 995

	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_dotl(st, inode);
	if (v9ses->cache)
		inode->i_size = i_size;
	spin_unlock(&inode->i_lock);
996
out:
997 998 999 1000
	kfree(st);
	return 0;
}

1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
const struct inode_operations v9fs_dir_inode_operations_dotl = {
	.create = v9fs_vfs_create_dotl,
	.lookup = v9fs_vfs_lookup,
	.link = v9fs_vfs_link_dotl,
	.symlink = v9fs_vfs_symlink_dotl,
	.unlink = v9fs_vfs_unlink,
	.mkdir = v9fs_vfs_mkdir_dotl,
	.rmdir = v9fs_vfs_rmdir,
	.mknod = v9fs_vfs_mknod_dotl,
	.rename = v9fs_vfs_rename,
	.getattr = v9fs_vfs_getattr_dotl,
	.setattr = v9fs_vfs_setattr_dotl,
	.setxattr = generic_setxattr,
	.getxattr = generic_getxattr,
	.removexattr = generic_removexattr,
	.listxattr = v9fs_listxattr,
1017
	.get_acl = v9fs_iop_get_acl,
1018 1019 1020 1021 1022 1023 1024 1025 1026
};

const struct inode_operations v9fs_file_inode_operations_dotl = {
	.getattr = v9fs_vfs_getattr_dotl,
	.setattr = v9fs_vfs_setattr_dotl,
	.setxattr = generic_setxattr,
	.getxattr = generic_getxattr,
	.removexattr = generic_removexattr,
	.listxattr = v9fs_listxattr,
1027
	.get_acl = v9fs_iop_get_acl,
1028 1029 1030
};

const struct inode_operations v9fs_symlink_inode_operations_dotl = {
M
M. Mohan Kumar 已提交
1031
	.readlink = generic_readlink,
1032 1033 1034 1035 1036 1037 1038 1039 1040
	.follow_link = v9fs_vfs_follow_link_dotl,
	.put_link = v9fs_vfs_put_link,
	.getattr = v9fs_vfs_getattr_dotl,
	.setattr = v9fs_vfs_setattr_dotl,
	.setxattr = generic_setxattr,
	.getxattr = generic_getxattr,
	.removexattr = generic_removexattr,
	.listxattr = v9fs_listxattr,
};