xfs_iops.c 18.6 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2 3
 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
 * All Rights Reserved.
L
Linus Torvalds 已提交
4
 *
5 6
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
L
Linus Torvalds 已提交
7 8
 * published by the Free Software Foundation.
 *
9 10 11 12
 * This program is distributed in the hope that it would 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.
L
Linus Torvalds 已提交
13
 *
14 15 16
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write the Free Software Foundation,
 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
L
Linus Torvalds 已提交
17 18 19
 */
#include "xfs.h"
#include "xfs_fs.h"
20
#include "xfs_bit.h"
L
Linus Torvalds 已提交
21
#include "xfs_log.h"
22
#include "xfs_inum.h"
L
Linus Torvalds 已提交
23 24 25 26 27 28 29 30 31
#include "xfs_trans.h"
#include "xfs_sb.h"
#include "xfs_ag.h"
#include "xfs_dir2.h"
#include "xfs_alloc.h"
#include "xfs_dmapi.h"
#include "xfs_quota.h"
#include "xfs_mount.h"
#include "xfs_bmap_btree.h"
32
#include "xfs_alloc_btree.h"
L
Linus Torvalds 已提交
33 34
#include "xfs_ialloc_btree.h"
#include "xfs_dir2_sf.h"
35
#include "xfs_attr_sf.h"
L
Linus Torvalds 已提交
36 37 38
#include "xfs_dinode.h"
#include "xfs_inode.h"
#include "xfs_bmap.h"
39 40
#include "xfs_btree.h"
#include "xfs_ialloc.h"
L
Linus Torvalds 已提交
41 42 43 44 45 46 47 48
#include "xfs_rtalloc.h"
#include "xfs_error.h"
#include "xfs_itable.h"
#include "xfs_rw.h"
#include "xfs_acl.h"
#include "xfs_attr.h"
#include "xfs_buf_item.h"
#include "xfs_utils.h"
49
#include "xfs_vnodeops.h"
L
Linus Torvalds 已提交
50

51
#include <linux/capability.h>
L
Linus Torvalds 已提交
52 53
#include <linux/xattr.h>
#include <linux/namei.h>
54
#include <linux/security.h>
L
Linus Torvalds 已提交
55

56 57 58 59 60 61 62 63
/*
 * Bring the atime in the XFS inode uptodate.
 * Used before logging the inode to disk or when the Linux inode goes away.
 */
void
xfs_synchronize_atime(
	xfs_inode_t	*ip)
{
64
	bhv_vnode_t	*vp;
65 66 67

	vp = XFS_ITOV_NULL(ip);
	if (vp) {
C
Christoph Hellwig 已提交
68 69
		ip->i_d.di_atime.t_sec = (__int32_t)vp->i_atime.tv_sec;
		ip->i_d.di_atime.t_nsec = (__int32_t)vp->i_atime.tv_nsec;
70 71 72
	}
}

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
/*
 * Change the requested timestamp in the given inode.
 * We don't lock across timestamp updates, and we don't log them but
 * we do record the fact that there is dirty information in core.
 *
 * NOTE -- callers MUST combine XFS_ICHGTIME_MOD or XFS_ICHGTIME_CHG
 *		with XFS_ICHGTIME_ACC to be sure that access time
 *		update will take.  Calling first with XFS_ICHGTIME_ACC
 *		and then XFS_ICHGTIME_MOD may fail to modify the access
 *		timestamp if the filesystem is mounted noacctm.
 */
void
xfs_ichgtime(
	xfs_inode_t	*ip,
	int		flags)
{
89
	struct inode	*inode = vn_to_inode(XFS_ITOV(ip));
90 91 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 118 119
	timespec_t	tv;

	nanotime(&tv);
	if (flags & XFS_ICHGTIME_MOD) {
		inode->i_mtime = tv;
		ip->i_d.di_mtime.t_sec = (__int32_t)tv.tv_sec;
		ip->i_d.di_mtime.t_nsec = (__int32_t)tv.tv_nsec;
	}
	if (flags & XFS_ICHGTIME_ACC) {
		inode->i_atime = tv;
		ip->i_d.di_atime.t_sec = (__int32_t)tv.tv_sec;
		ip->i_d.di_atime.t_nsec = (__int32_t)tv.tv_nsec;
	}
	if (flags & XFS_ICHGTIME_CHG) {
		inode->i_ctime = tv;
		ip->i_d.di_ctime.t_sec = (__int32_t)tv.tv_sec;
		ip->i_d.di_ctime.t_nsec = (__int32_t)tv.tv_nsec;
	}

	/*
	 * We update the i_update_core field _after_ changing
	 * the timestamps in order to coordinate properly with
	 * xfs_iflush() so that we don't lose timestamp updates.
	 * This keeps us from having to hold the inode lock
	 * while doing this.  We use the SYNCHRONIZE macro to
	 * ensure that the compiler does not reorder the update
	 * of i_update_core above the timestamp updates above.
	 */
	SYNCHRONIZE();
	ip->i_update_core = 1;
120
	if (!(inode->i_state & I_NEW))
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137
		mark_inode_dirty_sync(inode);
}

/*
 * Variant on the above which avoids querying the system clock
 * in situations where we know the Linux inode timestamps have
 * just been updated (and so we can update our inode cheaply).
 */
void
xfs_ichgtime_fast(
	xfs_inode_t	*ip,
	struct inode	*inode,
	int		flags)
{
	timespec_t	*tvp;

	/*
138 139
	 * Atime updates for read() & friends are handled lazily now, and
	 * explicit updates must go through xfs_ichgtime()
140
	 */
141
	ASSERT((flags & XFS_ICHGTIME_ACC) == 0);
142 143

	/*
144 145
	 * We're not supposed to change timestamps in readonly-mounted
	 * filesystems.  Throw it away if anyone asks us.
146
	 */
147
	if (unlikely(IS_RDONLY(inode)))
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171
		return;

	if (flags & XFS_ICHGTIME_MOD) {
		tvp = &inode->i_mtime;
		ip->i_d.di_mtime.t_sec = (__int32_t)tvp->tv_sec;
		ip->i_d.di_mtime.t_nsec = (__int32_t)tvp->tv_nsec;
	}
	if (flags & XFS_ICHGTIME_CHG) {
		tvp = &inode->i_ctime;
		ip->i_d.di_ctime.t_sec = (__int32_t)tvp->tv_sec;
		ip->i_d.di_ctime.t_nsec = (__int32_t)tvp->tv_nsec;
	}

	/*
	 * We update the i_update_core field _after_ changing
	 * the timestamps in order to coordinate properly with
	 * xfs_iflush() so that we don't lose timestamp updates.
	 * This keeps us from having to hold the inode lock
	 * while doing this.  We use the SYNCHRONIZE macro to
	 * ensure that the compiler does not reorder the update
	 * of i_update_core above the timestamp updates above.
	 */
	SYNCHRONIZE();
	ip->i_update_core = 1;
172
	if (!(inode->i_state & I_NEW))
173 174 175
		mark_inode_dirty_sync(inode);
}

L
Linus Torvalds 已提交
176 177 178 179 180

/*
 * Pull the link count and size up from the xfs inode to the linux inode
 */
STATIC void
181
xfs_validate_fields(
C
Christoph Hellwig 已提交
182
	struct inode		*inode)
L
Linus Torvalds 已提交
183
{
C
Christoph Hellwig 已提交
184 185 186 187 188 189 190 191 192 193 194
	struct xfs_inode	*ip = XFS_I(inode);
	loff_t size;

	inode->i_nlink = ip->i_d.di_nlink;
	inode->i_blocks =
		XFS_FSB_TO_BB(ip->i_mount, ip->i_d.di_nblocks +
					   ip->i_delayed_blks);
	/* we're under i_sem so i_size can't change under us */
	size = XFS_ISIZE(ip);
	if (i_size_read(inode) != size)
		i_size_write(inode, size);
L
Linus Torvalds 已提交
195 196
}

197 198 199 200 201 202 203
/*
 * Hook in SELinux.  This is not quite correct yet, what we really need
 * here (as we do for default ACLs) is a mechanism by which creation of
 * these attrs can be journalled at inode creation time (along with the
 * inode, of course, such that log replay can't cause these to be lost).
 */
STATIC int
204
xfs_init_security(
205
	bhv_vnode_t	*vp,
206 207
	struct inode	*dir)
{
208
	struct inode	*ip = vn_to_inode(vp);
209 210 211 212 213 214 215 216 217 218 219 220
	size_t		length;
	void		*value;
	char		*name;
	int		error;

	error = security_inode_init_security(ip, dir, &name, &value, &length);
	if (error) {
		if (error == -EOPNOTSUPP)
			return 0;
		return -error;
	}

221 222
	error = xfs_attr_set(XFS_I(ip), name, value,
			length, ATTR_SECURE);
223
	if (!error)
224
		xfs_iflags_set(XFS_I(ip), XFS_IMODIFIED);
225 226 227 228 229 230

	kfree(name);
	kfree(value);
	return error;
}

L
Linus Torvalds 已提交
231 232 233 234 235 236
/*
 * Determine whether a process has a valid fs_struct (kernel daemons
 * like knfsd don't have an fs_struct).
 *
 * XXX(hch):  nfsd is broken, better fix it instead.
 */
237
STATIC_INLINE int
238
xfs_has_fs_struct(struct task_struct *task)
L
Linus Torvalds 已提交
239 240 241 242
{
	return (task->fs != init_task.fs);
}

243
STATIC void
244
xfs_cleanup_inode(
245
	struct inode	*dir,
246
	bhv_vnode_t	*vp,
247
	struct dentry	*dentry,
248 249 250 251 252
	int		mode)
{
	struct dentry   teardown = {};

	/* Oh, the horror.
253
	 * If we can't add the ACL or we fail in
254
	 * xfs_init_security we must back out.
255 256
	 * ENOSPC can hit here, among other things.
	 */
257
	teardown.d_inode = vn_to_inode(vp);
258 259 260
	teardown.d_name = dentry->d_name;

	if (S_ISDIR(mode))
261
		xfs_rmdir(XFS_I(dir), &teardown);
262
	else
263
		xfs_remove(XFS_I(dir), &teardown);
264 265 266
	VN_RELE(vp);
}

L
Linus Torvalds 已提交
267
STATIC int
268
xfs_vn_mknod(
L
Linus Torvalds 已提交
269 270 271 272 273 274
	struct inode	*dir,
	struct dentry	*dentry,
	int		mode,
	dev_t		rdev)
{
	struct inode	*ip;
275
	bhv_vnode_t	*vp = NULL, *dvp = vn_from_inode(dir);
L
Linus Torvalds 已提交
276 277 278 279 280 281 282 283
	xfs_acl_t	*default_acl = NULL;
	attrexists_t	test_default_acl = _ACL_DEFAULT_EXISTS;
	int		error;

	/*
	 * Irix uses Missed'em'V split, but doesn't want to see
	 * the upper 5 bits of (14bit) major.
	 */
284
	if (unlikely(!sysv_valid_dev(rdev) || MAJOR(rdev) & ~0x1ff))
L
Linus Torvalds 已提交
285 286
		return -EINVAL;

287 288
	if (unlikely(test_default_acl && test_default_acl(dvp))) {
		if (!_ACL_ALLOC(default_acl)) {
L
Linus Torvalds 已提交
289
			return -ENOMEM;
290
		}
L
Linus Torvalds 已提交
291 292 293 294 295 296
		if (!_ACL_GET_DEFAULT(dvp, default_acl)) {
			_ACL_FREE(default_acl);
			default_acl = NULL;
		}
	}

297
	if (IS_POSIXACL(dir) && !default_acl && xfs_has_fs_struct(current))
L
Linus Torvalds 已提交
298 299 300 301
		mode &= ~current->fs->umask;

	switch (mode & S_IFMT) {
	case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK:
302
		rdev = sysv_encode_dev(rdev);
L
Linus Torvalds 已提交
303
	case S_IFREG:
304
		error = xfs_create(XFS_I(dir), dentry, mode, rdev, &vp, NULL);
L
Linus Torvalds 已提交
305 306
		break;
	case S_IFDIR:
307
		error = xfs_mkdir(XFS_I(dir), dentry, mode, &vp, NULL);
L
Linus Torvalds 已提交
308 309 310 311 312 313
		break;
	default:
		error = EINVAL;
		break;
	}

314
	if (unlikely(!error)) {
315
		error = xfs_init_security(vp, dir);
316
		if (error)
317
			xfs_cleanup_inode(dir, vp, dentry, mode);
318
	}
319

320
	if (unlikely(default_acl)) {
L
Linus Torvalds 已提交
321
		if (!error) {
322
			error = _ACL_INHERIT(vp, mode, default_acl);
323
			if (!error)
C
Christoph Hellwig 已提交
324
				xfs_iflags_set(XFS_I(vp), XFS_IMODIFIED);
325
			else
326
				xfs_cleanup_inode(dir, vp, dentry, mode);
L
Linus Torvalds 已提交
327 328 329 330
		}
		_ACL_FREE(default_acl);
	}

331
	if (likely(!error)) {
L
Linus Torvalds 已提交
332
		ASSERT(vp);
333
		ip = vn_to_inode(vp);
L
Linus Torvalds 已提交
334

C
Christoph Hellwig 已提交
335
		if (S_ISDIR(mode))
C
Christoph Hellwig 已提交
336
			xfs_validate_fields(ip);
L
Linus Torvalds 已提交
337
		d_instantiate(dentry, ip);
C
Christoph Hellwig 已提交
338
		xfs_validate_fields(dir);
L
Linus Torvalds 已提交
339 340 341 342 343
	}
	return -error;
}

STATIC int
344
xfs_vn_create(
L
Linus Torvalds 已提交
345 346 347 348 349
	struct inode	*dir,
	struct dentry	*dentry,
	int		mode,
	struct nameidata *nd)
{
350
	return xfs_vn_mknod(dir, dentry, mode, 0);
L
Linus Torvalds 已提交
351 352 353
}

STATIC int
354
xfs_vn_mkdir(
L
Linus Torvalds 已提交
355 356 357 358
	struct inode	*dir,
	struct dentry	*dentry,
	int		mode)
{
359
	return xfs_vn_mknod(dir, dentry, mode|S_IFDIR, 0);
L
Linus Torvalds 已提交
360 361 362
}

STATIC struct dentry *
363
xfs_vn_lookup(
L
Linus Torvalds 已提交
364 365 366 367
	struct inode	*dir,
	struct dentry	*dentry,
	struct nameidata *nd)
{
368
	bhv_vnode_t	*cvp;
L
Linus Torvalds 已提交
369 370 371 372 373
	int		error;

	if (dentry->d_name.len >= MAXNAMELEN)
		return ERR_PTR(-ENAMETOOLONG);

374
	error = xfs_lookup(XFS_I(dir), dentry, &cvp);
375
	if (unlikely(error)) {
L
Linus Torvalds 已提交
376 377 378 379 380 381
		if (unlikely(error != ENOENT))
			return ERR_PTR(-error);
		d_add(dentry, NULL);
		return NULL;
	}

382
	return d_splice_alias(vn_to_inode(cvp), dentry);
L
Linus Torvalds 已提交
383 384 385
}

STATIC int
386
xfs_vn_link(
L
Linus Torvalds 已提交
387 388 389 390 391
	struct dentry	*old_dentry,
	struct inode	*dir,
	struct dentry	*dentry)
{
	struct inode	*ip;	/* inode of guy being linked to */
392
	bhv_vnode_t	*vp;	/* vp of name being linked */
L
Linus Torvalds 已提交
393 394 395
	int		error;

	ip = old_dentry->d_inode;	/* inode being linked to */
396
	vp = vn_from_inode(ip);
L
Linus Torvalds 已提交
397

398
	VN_HOLD(vp);
399
	error = xfs_link(XFS_I(dir), vp, dentry);
400 401 402
	if (unlikely(error)) {
		VN_RELE(vp);
	} else {
403
		xfs_iflags_set(XFS_I(dir), XFS_IMODIFIED);
C
Christoph Hellwig 已提交
404
		xfs_validate_fields(ip);
L
Linus Torvalds 已提交
405 406 407 408 409 410
		d_instantiate(dentry, ip);
	}
	return -error;
}

STATIC int
411
xfs_vn_unlink(
L
Linus Torvalds 已提交
412 413 414 415 416 417 418 419
	struct inode	*dir,
	struct dentry	*dentry)
{
	struct inode	*inode;
	int		error;

	inode = dentry->d_inode;

420
	error = xfs_remove(XFS_I(dir), dentry);
421
	if (likely(!error)) {
C
Christoph Hellwig 已提交
422 423
		xfs_validate_fields(dir);	/* size needs update */
		xfs_validate_fields(inode);
L
Linus Torvalds 已提交
424 425 426 427 428
	}
	return -error;
}

STATIC int
429
xfs_vn_symlink(
L
Linus Torvalds 已提交
430 431 432 433 434
	struct inode	*dir,
	struct dentry	*dentry,
	const char	*symname)
{
	struct inode	*ip;
435
	bhv_vnode_t	*cvp;	/* used to lookup symlink to put in dentry */
L
Linus Torvalds 已提交
436
	int		error;
437
	mode_t		mode;
L
Linus Torvalds 已提交
438 439 440

	cvp = NULL;

441
	mode = S_IFLNK |
442
		(irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO);
L
Linus Torvalds 已提交
443

444 445
	error = xfs_symlink(XFS_I(dir), dentry, (char *)symname, mode,
			    &cvp, NULL);
446
	if (likely(!error && cvp)) {
447
		error = xfs_init_security(cvp, dir);
448
		if (likely(!error)) {
449
			ip = vn_to_inode(cvp);
450
			d_instantiate(dentry, ip);
C
Christoph Hellwig 已提交
451 452
			xfs_validate_fields(dir);
			xfs_validate_fields(ip);
453
		} else {
454
			xfs_cleanup_inode(dir, cvp, dentry, 0);
455
		}
L
Linus Torvalds 已提交
456 457 458 459 460
	}
	return -error;
}

STATIC int
461
xfs_vn_rmdir(
L
Linus Torvalds 已提交
462 463 464 465 466 467
	struct inode	*dir,
	struct dentry	*dentry)
{
	struct inode	*inode = dentry->d_inode;
	int		error;

468
	error = xfs_rmdir(XFS_I(dir), dentry);
469
	if (likely(!error)) {
C
Christoph Hellwig 已提交
470 471
		xfs_validate_fields(inode);
		xfs_validate_fields(dir);
L
Linus Torvalds 已提交
472 473 474 475 476
	}
	return -error;
}

STATIC int
477
xfs_vn_rename(
L
Linus Torvalds 已提交
478 479 480 481 482 483
	struct inode	*odir,
	struct dentry	*odentry,
	struct inode	*ndir,
	struct dentry	*ndentry)
{
	struct inode	*new_inode = ndentry->d_inode;
484
	bhv_vnode_t	*tvp;	/* target directory */
L
Linus Torvalds 已提交
485 486
	int		error;

487
	tvp = vn_from_inode(ndir);
L
Linus Torvalds 已提交
488

489
	error = xfs_rename(XFS_I(odir), odentry, tvp, ndentry);
490 491
	if (likely(!error)) {
		if (new_inode)
C
Christoph Hellwig 已提交
492 493
			xfs_validate_fields(new_inode);
		xfs_validate_fields(odir);
494
		if (ndir != odir)
C
Christoph Hellwig 已提交
495
			xfs_validate_fields(ndir);
496 497
	}
	return -error;
L
Linus Torvalds 已提交
498 499 500 501 502 503 504
}

/*
 * careful here - this function can get called recursively, so
 * we need to be very careful about how much stack we use.
 * uio is kmalloced for this reason...
 */
505
STATIC void *
506
xfs_vn_follow_link(
L
Linus Torvalds 已提交
507 508 509 510
	struct dentry		*dentry,
	struct nameidata	*nd)
{
	char			*link;
511
	int			error = -ENOMEM;
L
Linus Torvalds 已提交
512

513
	link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
514 515
	if (!link)
		goto out_err;
L
Linus Torvalds 已提交
516

517
	error = -xfs_readlink(XFS_I(dentry->d_inode), link);
518 519
	if (unlikely(error))
		goto out_kfree;
L
Linus Torvalds 已提交
520 521

	nd_set_link(nd, link);
522
	return NULL;
523 524 525 526 527 528

 out_kfree:
	kfree(link);
 out_err:
	nd_set_link(nd, ERR_PTR(error));
	return NULL;
L
Linus Torvalds 已提交
529 530
}

531
STATIC void
532
xfs_vn_put_link(
533 534 535
	struct dentry	*dentry,
	struct nameidata *nd,
	void		*p)
L
Linus Torvalds 已提交
536
{
537 538
	char		*s = nd_get_link(nd);

L
Linus Torvalds 已提交
539 540 541 542 543 544
	if (!IS_ERR(s))
		kfree(s);
}

#ifdef CONFIG_XFS_POSIX_ACL
STATIC int
545
xfs_vn_permission(
L
Linus Torvalds 已提交
546 547 548 549
	struct inode	*inode,
	int		mode,
	struct nameidata *nd)
{
550
	return -xfs_access(XFS_I(inode), mode << 6, NULL);
L
Linus Torvalds 已提交
551 552
}
#else
553
#define xfs_vn_permission NULL
L
Linus Torvalds 已提交
554 555 556
#endif

STATIC int
557
xfs_vn_getattr(
558 559 560
	struct vfsmount		*mnt,
	struct dentry		*dentry,
	struct kstat		*stat)
L
Linus Torvalds 已提交
561
{
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609
	struct inode		*inode = dentry->d_inode;
	struct xfs_inode	*ip = XFS_I(inode);
	struct xfs_mount	*mp = ip->i_mount;

	xfs_itrace_entry(ip);

	if (XFS_FORCED_SHUTDOWN(mp))
		return XFS_ERROR(EIO);

	stat->size = XFS_ISIZE(ip);
	stat->dev = inode->i_sb->s_dev;
	stat->mode = ip->i_d.di_mode;
	stat->nlink = ip->i_d.di_nlink;
	stat->uid = ip->i_d.di_uid;
	stat->gid = ip->i_d.di_gid;
	stat->ino = ip->i_ino;
#if XFS_BIG_INUMS
	stat->ino += mp->m_inoadd;
#endif
	stat->atime = inode->i_atime;
	stat->mtime.tv_sec = ip->i_d.di_mtime.t_sec;
	stat->mtime.tv_nsec = ip->i_d.di_mtime.t_nsec;
	stat->ctime.tv_sec = ip->i_d.di_ctime.t_sec;
	stat->ctime.tv_nsec = ip->i_d.di_ctime.t_nsec;
	stat->blocks =
		XFS_FSB_TO_BB(mp, ip->i_d.di_nblocks + ip->i_delayed_blks);


	switch (inode->i_mode & S_IFMT) {
	case S_IFBLK:
	case S_IFCHR:
		stat->blksize = BLKDEV_IOSIZE;
		stat->rdev = MKDEV(sysv_major(ip->i_df.if_u2.if_rdev) & 0x1ff,
				   sysv_minor(ip->i_df.if_u2.if_rdev));
		break;
	default:
		if (ip->i_d.di_flags & XFS_DIFLAG_REALTIME) {
			/*
			 * If the file blocks are being allocated from a
			 * realtime volume, then return the inode's realtime
			 * extent size or the realtime volume's extent size.
			 */
			stat->blksize =
				xfs_get_extsz_hint(ip) << mp->m_sb.sb_blocklog;
		} else
			stat->blksize = xfs_preferred_iosize(mp);
		stat->rdev = 0;
		break;
610
	}
611 612

	return 0;
L
Linus Torvalds 已提交
613 614 615
}

STATIC int
616
xfs_vn_setattr(
L
Linus Torvalds 已提交
617 618 619 620 621
	struct dentry	*dentry,
	struct iattr	*attr)
{
	struct inode	*inode = dentry->d_inode;
	unsigned int	ia_valid = attr->ia_valid;
622
	bhv_vattr_t	vattr = { 0 };
L
Linus Torvalds 已提交
623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640
	int		flags = 0;
	int		error;

	if (ia_valid & ATTR_UID) {
		vattr.va_mask |= XFS_AT_UID;
		vattr.va_uid = attr->ia_uid;
	}
	if (ia_valid & ATTR_GID) {
		vattr.va_mask |= XFS_AT_GID;
		vattr.va_gid = attr->ia_gid;
	}
	if (ia_valid & ATTR_SIZE) {
		vattr.va_mask |= XFS_AT_SIZE;
		vattr.va_size = attr->ia_size;
	}
	if (ia_valid & ATTR_ATIME) {
		vattr.va_mask |= XFS_AT_ATIME;
		vattr.va_atime = attr->ia_atime;
641
		inode->i_atime = attr->ia_atime;
L
Linus Torvalds 已提交
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
	}
	if (ia_valid & ATTR_MTIME) {
		vattr.va_mask |= XFS_AT_MTIME;
		vattr.va_mtime = attr->ia_mtime;
	}
	if (ia_valid & ATTR_CTIME) {
		vattr.va_mask |= XFS_AT_CTIME;
		vattr.va_ctime = attr->ia_ctime;
	}
	if (ia_valid & ATTR_MODE) {
		vattr.va_mask |= XFS_AT_MODE;
		vattr.va_mode = attr->ia_mode;
		if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
			inode->i_mode &= ~S_ISGID;
	}

	if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET))
		flags |= ATTR_UTIME;
#ifdef ATTR_NO_BLOCK
	if ((ia_valid & ATTR_NO_BLOCK))
		flags |= ATTR_NONBLOCK;
#endif

665
	error = xfs_setattr(XFS_I(inode), &vattr, flags, NULL);
666
	if (likely(!error))
C
Christoph Hellwig 已提交
667
		vn_revalidate(vn_from_inode(inode));
668
	return -error;
L
Linus Torvalds 已提交
669 670 671
}

STATIC void
672
xfs_vn_truncate(
L
Linus Torvalds 已提交
673 674
	struct inode	*inode)
{
675
	block_truncate_page(inode->i_mapping, inode->i_size, xfs_get_blocks);
L
Linus Torvalds 已提交
676 677 678
}

STATIC int
679
xfs_vn_setxattr(
L
Linus Torvalds 已提交
680 681 682 683 684 685
	struct dentry	*dentry,
	const char	*name,
	const void	*data,
	size_t		size,
	int		flags)
{
686
	bhv_vnode_t	*vp = vn_from_inode(dentry->d_inode);
L
Linus Torvalds 已提交
687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709
	char		*attr = (char *)name;
	attrnames_t	*namesp;
	int		xflags = 0;
	int		error;

	namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
	if (!namesp)
		return -EOPNOTSUPP;
	attr += namesp->attr_namelen;
	error = namesp->attr_capable(vp, NULL);
	if (error)
		return error;

	/* Convert Linux syscall to XFS internal ATTR flags */
	if (flags & XATTR_CREATE)
		xflags |= ATTR_CREATE;
	if (flags & XATTR_REPLACE)
		xflags |= ATTR_REPLACE;
	xflags |= namesp->attr_flag;
	return namesp->attr_set(vp, attr, (void *)data, size, xflags);
}

STATIC ssize_t
710
xfs_vn_getxattr(
L
Linus Torvalds 已提交
711 712 713 714 715
	struct dentry	*dentry,
	const char	*name,
	void		*data,
	size_t		size)
{
716
	bhv_vnode_t	*vp = vn_from_inode(dentry->d_inode);
L
Linus Torvalds 已提交
717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739
	char		*attr = (char *)name;
	attrnames_t	*namesp;
	int		xflags = 0;
	ssize_t		error;

	namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
	if (!namesp)
		return -EOPNOTSUPP;
	attr += namesp->attr_namelen;
	error = namesp->attr_capable(vp, NULL);
	if (error)
		return error;

	/* Convert Linux syscall to XFS internal ATTR flags */
	if (!size) {
		xflags |= ATTR_KERNOVAL;
		data = NULL;
	}
	xflags |= namesp->attr_flag;
	return namesp->attr_get(vp, attr, (void *)data, size, xflags);
}

STATIC ssize_t
740
xfs_vn_listxattr(
L
Linus Torvalds 已提交
741 742 743 744
	struct dentry		*dentry,
	char			*data,
	size_t			size)
{
745
	bhv_vnode_t		*vp = vn_from_inode(dentry->d_inode);
L
Linus Torvalds 已提交
746 747 748 749 750 751 752 753 754 755 756 757 758 759
	int			error, xflags = ATTR_KERNAMELS;
	ssize_t			result;

	if (!size)
		xflags |= ATTR_KERNOVAL;
	xflags |= capable(CAP_SYS_ADMIN) ? ATTR_KERNFULLS : ATTR_KERNORMALS;

	error = attr_generic_list(vp, data, size, xflags, &result);
	if (error < 0)
		return error;
	return result;
}

STATIC int
760
xfs_vn_removexattr(
L
Linus Torvalds 已提交
761 762 763
	struct dentry	*dentry,
	const char	*name)
{
764
	bhv_vnode_t	*vp = vn_from_inode(dentry->d_inode);
L
Linus Torvalds 已提交
765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
	char		*attr = (char *)name;
	attrnames_t	*namesp;
	int		xflags = 0;
	int		error;

	namesp = attr_lookup_namespace(attr, attr_namespaces, ATTR_NAMECOUNT);
	if (!namesp)
		return -EOPNOTSUPP;
	attr += namesp->attr_namelen;
	error = namesp->attr_capable(vp, NULL);
	if (error)
		return error;
	xflags |= namesp->attr_flag;
	return namesp->attr_remove(vp, attr, xflags);
}


782
const struct inode_operations xfs_inode_operations = {
783 784 785 786 787 788 789 790
	.permission		= xfs_vn_permission,
	.truncate		= xfs_vn_truncate,
	.getattr		= xfs_vn_getattr,
	.setattr		= xfs_vn_setattr,
	.setxattr		= xfs_vn_setxattr,
	.getxattr		= xfs_vn_getxattr,
	.listxattr		= xfs_vn_listxattr,
	.removexattr		= xfs_vn_removexattr,
L
Linus Torvalds 已提交
791 792
};

793
const struct inode_operations xfs_dir_inode_operations = {
794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809
	.create			= xfs_vn_create,
	.lookup			= xfs_vn_lookup,
	.link			= xfs_vn_link,
	.unlink			= xfs_vn_unlink,
	.symlink		= xfs_vn_symlink,
	.mkdir			= xfs_vn_mkdir,
	.rmdir			= xfs_vn_rmdir,
	.mknod			= xfs_vn_mknod,
	.rename			= xfs_vn_rename,
	.permission		= xfs_vn_permission,
	.getattr		= xfs_vn_getattr,
	.setattr		= xfs_vn_setattr,
	.setxattr		= xfs_vn_setxattr,
	.getxattr		= xfs_vn_getxattr,
	.listxattr		= xfs_vn_listxattr,
	.removexattr		= xfs_vn_removexattr,
L
Linus Torvalds 已提交
810 811
};

812
const struct inode_operations xfs_symlink_inode_operations = {
L
Linus Torvalds 已提交
813
	.readlink		= generic_readlink,
814 815 816 817 818 819 820 821 822
	.follow_link		= xfs_vn_follow_link,
	.put_link		= xfs_vn_put_link,
	.permission		= xfs_vn_permission,
	.getattr		= xfs_vn_getattr,
	.setattr		= xfs_vn_setattr,
	.setxattr		= xfs_vn_setxattr,
	.getxattr		= xfs_vn_getxattr,
	.listxattr		= xfs_vn_listxattr,
	.removexattr		= xfs_vn_removexattr,
L
Linus Torvalds 已提交
823
};