vfs_inode_dotl.c 24.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 51 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
/*
 *  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
v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
		    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 256 257 258 259 260 261
/**
 * 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
v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, int omode,
		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 287
	p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%x\n",
		 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 397 398 399 400 401 402 403
	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,
			       struct dentry *dentry, int omode)
{
	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 525 526 527 528 529 530 531 532 533 534 535 536 537 538
	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;
}

/**
 * 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;

539
	p9_debug(P9_DEBUG_VFS, "\n");
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555

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

	p9attr.valid = iattr->ia_valid;
	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 已提交
556
	v9ses = v9fs_dentry2v9ses(dentry);
557 558 559 560
	fid = v9fs_fid_lookup(dentry);
	if (IS_ERR(fid))
		return PTR_ERR(fid);

561 562 563 564
	/* Write all dirty data */
	if (S_ISREG(dentry->d_inode->i_mode))
		filemap_write_and_wait(dentry->d_inode->i_mapping);

565 566 567
	retval = p9_client_setattr(fid, &p9attr);
	if (retval < 0)
		return retval;
568

569 570 571 572 573
	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);
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
	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)
{
596
	mode_t mode;
597
	struct v9fs_inode *v9inode = V9FS_I(inode);
598 599 600 601 602 603 604 605 606 607

	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 已提交
608
		set_nlink(inode, stat->st_nlink);
609

610 611 612
		mode = stat->st_mode & S_IALLUGO;
		mode |= inode->i_mode & ~S_IALLUGO;
		inode->i_mode = mode;
613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633

		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 已提交
634
			set_nlink(inode, stat->st_nlink);
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649
		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)
650
		inode->i_generation = stat->st_gen;
651 652 653 654

	/* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION
	 * because the inode structure does not have fields for them.
	 */
655
	v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR;
656 657 658 659 660 661 662 663
}

static int
v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
		const char *symname)
{
	int err;
	gid_t gid;
664 665 666 667 668 669
	char *name;
	struct p9_qid qid;
	struct inode *inode;
	struct p9_fid *dfid;
	struct p9_fid *fid = NULL;
	struct v9fs_session_info *v9ses;
670 671

	name = (char *) dentry->d_name.name;
672
	p9_debug(P9_DEBUG_VFS, "%lu,%s,%s\n", dir->i_ino, name, symname);
673 674 675 676 677
	v9ses = v9fs_inode2v9ses(dir);

	dfid = v9fs_fid_lookup(dentry->d_parent);
	if (IS_ERR(dfid)) {
		err = PTR_ERR(dfid);
678
		p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
679 680 681 682 683 684 685 686 687
		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) {
688
		p9_debug(P9_DEBUG_VFS, "p9_client_symlink failed %d\n", err);
689 690 691
		goto error;
	}

692
	v9fs_invalidate_inode_attr(dir);
693 694 695 696 697
	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);
698 699
			p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
				 err);
700 701 702 703 704
			fid = NULL;
			goto error;
		}

		/* instantiate inode and assign the unopened fid to dentry */
705
		inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
706 707
		if (IS_ERR(inode)) {
			err = PTR_ERR(inode);
708 709
			p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
				 err);
710 711 712 713 714
			goto error;
		}
		err = v9fs_fid_add(dentry, fid);
		if (err < 0)
			goto error;
715
		d_instantiate(dentry, inode);
716 717 718
		fid = NULL;
	} else {
		/* Not in cached mode. No need to populate inode with stat */
719
		inode = v9fs_get_inode(dir->i_sb, S_IFLNK, 0);
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748
		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;
749 750
	struct p9_fid *dfid, *oldfid;
	struct v9fs_session_info *v9ses;
751

752 753
	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);
754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769

	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) {
770
		p9_debug(P9_DEBUG_VFS, "p9_client_link failed %d\n", err);
771 772 773
		return err;
	}

774
	v9fs_invalidate_inode_attr(dir);
775 776 777 778 779 780 781
	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);

782
		v9fs_refresh_inode_dotl(fid, old_dentry->d_inode);
783
	}
784
	ihold(old_dentry->d_inode);
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802
	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
v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, int omode,
		dev_t rdev)
{
	int err;
803
	gid_t gid;
804
	char *name;
A
Al Viro 已提交
805
	umode_t mode;
806 807 808 809 810 811 812
	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;

813 814 815
	p9_debug(P9_DEBUG_VFS, " %lu,%s mode: %x MAJOR: %u MINOR: %u\n",
		 dir->i_ino, dentry->d_name.name, omode,
		 MAJOR(rdev), MINOR(rdev));
816 817 818 819 820 821 822 823 824

	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);
825
		p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
826 827 828 829 830 831 832 833 834
		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) {
835 836
		p9_debug(P9_DEBUG_VFS, "Failed to get acl values in mknod %d\n",
			 err);
837 838 839 840 841 842 843 844
		goto error;
	}
	name = (char *) dentry->d_name.name;

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

845
	v9fs_invalidate_inode_attr(dir);
846 847 848 849 850
	/* 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);
851 852
			p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
				 err);
853 854 855 856
			fid = NULL;
			goto error;
		}

857
		inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
858 859
		if (IS_ERR(inode)) {
			err = PTR_ERR(inode);
860 861
			p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
				 err);
862 863 864 865 866
			goto error;
		}
		err = v9fs_fid_add(dentry, fid);
		if (err < 0)
			goto error;
867
		d_instantiate(dentry, inode);
868 869 870 871 872 873
		fid = NULL;
	} else {
		/*
		 * Not in cached mode. No need to populate inode with stat.
		 * socket syscall returns a fd, so we need instantiate
		 */
874
		inode = v9fs_get_inode(dir->i_sb, mode, rdev);
875 876 877 878 879 880 881
		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 已提交
882
	v9fs_set_create_acl(dentry, &dacl, &pacl);
883 884 885
error:
	if (fid)
		p9_client_clunk(fid);
A
Al Viro 已提交
886
	v9fs_set_create_acl(NULL, &dacl, &pacl);
887 888 889 890 891 892 893 894 895 896 897 898 899
	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 已提交
900 901
	int retval;
	struct p9_fid *fid;
902
	char *link = __getname();
M
M. Mohan Kumar 已提交
903
	char *target;
904

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

M
M. Mohan Kumar 已提交
907
	if (!link) {
908
		link = ERR_PTR(-ENOMEM);
M
M. Mohan Kumar 已提交
909
		goto ndset;
910
	}
M
M. Mohan Kumar 已提交
911 912 913
	fid = v9fs_fid_lookup(dentry);
	if (IS_ERR(fid)) {
		__putname(link);
914
		link = ERR_CAST(fid);
M
M. Mohan Kumar 已提交
915 916 917 918 919 920 921 922 923 924 925
		goto ndset;
	}
	retval = p9_client_readlink(fid, &target);
	if (!retval) {
		strcpy(link, target);
		kfree(target);
		goto ndset;
	}
	__putname(link);
	link = ERR_PTR(retval);
ndset:
926 927 928 929
	nd_set_link(nd, link);
	return NULL;
}

930 931 932 933 934 935 936 937 938 939
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);
940 941 942 943 944
	/*
	 * Don't update inode if the file type is different
	 */
	if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT))
		goto out;
945 946 947 948 949 950 951 952 953 954 955

	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);
956
out:
957 958 959 960
	kfree(st);
	return 0;
}

961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976
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,
977
	.get_acl = v9fs_iop_get_acl,
978 979 980 981 982 983 984 985 986
};

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,
987
	.get_acl = v9fs_iop_get_acl,
988 989 990
};

const struct inode_operations v9fs_symlink_inode_operations_dotl = {
M
M. Mohan Kumar 已提交
991
	.readlink = generic_readlink,
992 993 994 995 996 997 998 999 1000
	.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,
};