xfs_iops.c 19.0 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>
D
David Chinner 已提交
55
#include <linux/falloc.h>
L
Linus Torvalds 已提交
56

57 58 59 60 61 62 63 64
/*
 * 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)
{
65
	struct inode	*inode = VFS_I(ip);
66

67
	if (!(inode->i_state & I_CLEAR)) {
68 69
		ip->i_d.di_atime.t_sec = (__int32_t)inode->i_atime.tv_sec;
		ip->i_d.di_atime.t_nsec = (__int32_t)inode->i_atime.tv_nsec;
70 71 72
	}
}

73
/*
74
 * If the linux inode is valid, mark it dirty.
75 76 77 78 79 80 81
 * Used when commiting a dirty inode into a transaction so that
 * the inode will get written back by the linux code
 */
void
xfs_mark_inode_dirty_sync(
	xfs_inode_t	*ip)
{
82
	struct inode	*inode = VFS_I(ip);
83

84
	if (!(inode->i_state & (I_WILL_FREE|I_FREEING|I_CLEAR)))
85
		mark_inode_dirty_sync(inode);
86 87
}

88 89 90 91 92 93 94 95 96 97
/*
 * 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.
 */
void
xfs_ichgtime(
	xfs_inode_t	*ip,
	int		flags)
{
98
	struct inode	*inode = VFS_I(ip);
99
	timespec_t	tv;
C
Christoph Hellwig 已提交
100
	int		sync_it = 0;
101

C
Christoph Hellwig 已提交
102 103 104 105
	tv = current_fs_time(inode->i_sb);

	if ((flags & XFS_ICHGTIME_MOD) &&
	    !timespec_equal(&inode->i_mtime, &tv)) {
106 107 108
		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;
C
Christoph Hellwig 已提交
109
		sync_it = 1;
110
	}
C
Christoph Hellwig 已提交
111 112
	if ((flags & XFS_ICHGTIME_CHG) &&
	    !timespec_equal(&inode->i_ctime, &tv)) {
113 114 115
		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;
C
Christoph Hellwig 已提交
116
		sync_it = 1;
117 118 119 120 121 122 123 124 125 126 127
	}

	/*
	 * 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.
	 */
C
Christoph Hellwig 已提交
128 129 130
	if (sync_it) {
		SYNCHRONIZE();
		ip->i_update_core = 1;
131
		xfs_mark_inode_dirty_sync(ip);
C
Christoph Hellwig 已提交
132
	}
133 134
}

135 136 137 138 139 140 141
/*
 * 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
142
xfs_init_security(
143
	struct inode	*inode,
144 145
	struct inode	*dir)
{
146
	struct xfs_inode *ip = XFS_I(inode);
147 148 149 150 151
	size_t		length;
	void		*value;
	char		*name;
	int		error;

152 153
	error = security_inode_init_security(inode, dir, &name,
					     &value, &length);
154 155 156 157 158 159
	if (error) {
		if (error == -EOPNOTSUPP)
			return 0;
		return -error;
	}

160
	error = xfs_attr_set(ip, name, value, length, ATTR_SECURE);
161
	if (!error)
162
		xfs_iflags_set(ip, XFS_IMODIFIED);
163 164 165 166 167 168

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

169 170 171 172 173 174 175 176 177
static void
xfs_dentry_to_name(
	struct xfs_name	*namep,
	struct dentry	*dentry)
{
	namep->name = dentry->d_name.name;
	namep->len = dentry->d_name.len;
}

178
STATIC void
179
xfs_cleanup_inode(
180
	struct inode	*dir,
181
	struct inode	*inode,
182
	struct dentry	*dentry)
183
{
184
	struct xfs_name	teardown;
185 186

	/* Oh, the horror.
187
	 * If we can't add the ACL or we fail in
188
	 * xfs_init_security we must back out.
189 190
	 * ENOSPC can hit here, among other things.
	 */
191
	xfs_dentry_to_name(&teardown, dentry);
192

193
	xfs_remove(XFS_I(dir), &teardown, XFS_I(inode));
194
	iput(inode);
195 196
}

L
Linus Torvalds 已提交
197
STATIC int
198
xfs_vn_mknod(
L
Linus Torvalds 已提交
199 200 201 202 203
	struct inode	*dir,
	struct dentry	*dentry,
	int		mode,
	dev_t		rdev)
{
C
Christoph Hellwig 已提交
204
	struct inode	*inode;
205
	struct xfs_inode *ip = NULL;
L
Linus Torvalds 已提交
206
	xfs_acl_t	*default_acl = NULL;
207
	struct xfs_name	name;
208
	int (*test_default_acl)(struct inode *) = _ACL_DEFAULT_EXISTS;
L
Linus Torvalds 已提交
209 210 211 212 213 214
	int		error;

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

218
	if (test_default_acl && test_default_acl(dir)) {
219
		if (!_ACL_ALLOC(default_acl)) {
L
Linus Torvalds 已提交
220
			return -ENOMEM;
221
		}
222
		if (!_ACL_GET_DEFAULT(dir, default_acl)) {
L
Linus Torvalds 已提交
223 224 225 226 227
			_ACL_FREE(default_acl);
			default_acl = NULL;
		}
	}

228 229
	xfs_dentry_to_name(&name, dentry);

C
Christoph Hellwig 已提交
230
	if (IS_POSIXACL(dir) && !default_acl)
L
Linus Torvalds 已提交
231 232 233
		mode &= ~current->fs->umask;

	switch (mode & S_IFMT) {
C
Christoph Hellwig 已提交
234 235 236 237
	case S_IFCHR:
	case S_IFBLK:
	case S_IFIFO:
	case S_IFSOCK:
238
		rdev = sysv_encode_dev(rdev);
L
Linus Torvalds 已提交
239
	case S_IFREG:
240
		error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip, NULL);
L
Linus Torvalds 已提交
241 242
		break;
	case S_IFDIR:
243
		error = xfs_mkdir(XFS_I(dir), &name, mode, &ip, NULL);
L
Linus Torvalds 已提交
244 245 246 247 248 249
		break;
	default:
		error = EINVAL;
		break;
	}

C
Christoph Hellwig 已提交
250 251
	if (unlikely(error))
		goto out_free_acl;
252

253
	inode = VFS_I(ip);
254 255

	error = xfs_init_security(inode, dir);
C
Christoph Hellwig 已提交
256 257 258 259
	if (unlikely(error))
		goto out_cleanup_inode;

	if (default_acl) {
260
		error = _ACL_INHERIT(inode, mode, default_acl);
C
Christoph Hellwig 已提交
261 262
		if (unlikely(error))
			goto out_cleanup_inode;
263
		xfs_iflags_set(ip, XFS_IMODIFIED);
L
Linus Torvalds 已提交
264 265 266 267
		_ACL_FREE(default_acl);
	}


C
Christoph Hellwig 已提交
268 269 270 271
	d_instantiate(dentry, inode);
	return -error;

 out_cleanup_inode:
272
	xfs_cleanup_inode(dir, inode, dentry);
C
Christoph Hellwig 已提交
273 274 275
 out_free_acl:
	if (default_acl)
		_ACL_FREE(default_acl);
L
Linus Torvalds 已提交
276 277 278 279
	return -error;
}

STATIC int
280
xfs_vn_create(
L
Linus Torvalds 已提交
281 282 283 284 285
	struct inode	*dir,
	struct dentry	*dentry,
	int		mode,
	struct nameidata *nd)
{
286
	return xfs_vn_mknod(dir, dentry, mode, 0);
L
Linus Torvalds 已提交
287 288 289
}

STATIC int
290
xfs_vn_mkdir(
L
Linus Torvalds 已提交
291 292 293 294
	struct inode	*dir,
	struct dentry	*dentry,
	int		mode)
{
295
	return xfs_vn_mknod(dir, dentry, mode|S_IFDIR, 0);
L
Linus Torvalds 已提交
296 297 298
}

STATIC struct dentry *
299
xfs_vn_lookup(
L
Linus Torvalds 已提交
300 301 302 303
	struct inode	*dir,
	struct dentry	*dentry,
	struct nameidata *nd)
{
304
	struct xfs_inode *cip;
305
	struct xfs_name	name;
L
Linus Torvalds 已提交
306 307 308 309 310
	int		error;

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

311
	xfs_dentry_to_name(&name, dentry);
312
	error = xfs_lookup(XFS_I(dir), &name, &cip, NULL);
313
	if (unlikely(error)) {
L
Linus Torvalds 已提交
314 315 316 317 318 319
		if (unlikely(error != ENOENT))
			return ERR_PTR(-error);
		d_add(dentry, NULL);
		return NULL;
	}

320
	return d_splice_alias(VFS_I(cip), dentry);
L
Linus Torvalds 已提交
321 322
}

323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
STATIC struct dentry *
xfs_vn_ci_lookup(
	struct inode	*dir,
	struct dentry	*dentry,
	struct nameidata *nd)
{
	struct xfs_inode *ip;
	struct xfs_name	xname;
	struct xfs_name ci_name;
	struct qstr	dname;
	int		error;

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

	xfs_dentry_to_name(&xname, dentry);
	error = xfs_lookup(XFS_I(dir), &xname, &ip, &ci_name);
	if (unlikely(error)) {
		if (unlikely(error != ENOENT))
			return ERR_PTR(-error);
343 344 345 346 347
		/*
		 * call d_add(dentry, NULL) here when d_drop_negative_children
		 * is called in xfs_vn_mknod (ie. allow negative dentries
		 * with CI filesystems).
		 */
348 349 350 351 352
		return NULL;
	}

	/* if exact match, just splice and exit */
	if (!ci_name.name)
353
		return d_splice_alias(VFS_I(ip), dentry);
354 355 356 357

	/* else case-insensitive match... */
	dname.name = ci_name.name;
	dname.len = ci_name.len;
358
	dentry = d_add_ci(dentry, VFS_I(ip), &dname);
359 360 361 362
	kmem_free(ci_name.name);
	return dentry;
}

L
Linus Torvalds 已提交
363
STATIC int
364
xfs_vn_link(
L
Linus Torvalds 已提交
365 366 367 368
	struct dentry	*old_dentry,
	struct inode	*dir,
	struct dentry	*dentry)
{
369
	struct inode	*inode;	/* inode of guy being linked to */
370
	struct xfs_name	name;
L
Linus Torvalds 已提交
371 372
	int		error;

373
	inode = old_dentry->d_inode;
374
	xfs_dentry_to_name(&name, dentry);
L
Linus Torvalds 已提交
375

376
	igrab(inode);
377
	error = xfs_link(XFS_I(dir), XFS_I(inode), &name);
378
	if (unlikely(error)) {
379 380
		iput(inode);
		return -error;
L
Linus Torvalds 已提交
381
	}
382 383 384 385

	xfs_iflags_set(XFS_I(dir), XFS_IMODIFIED);
	d_instantiate(dentry, inode);
	return 0;
L
Linus Torvalds 已提交
386 387 388
}

STATIC int
389
xfs_vn_unlink(
L
Linus Torvalds 已提交
390 391 392
	struct inode	*dir,
	struct dentry	*dentry)
{
393
	struct xfs_name	name;
L
Linus Torvalds 已提交
394 395
	int		error;

396
	xfs_dentry_to_name(&name, dentry);
L
Linus Torvalds 已提交
397

398 399 400 401 402 403 404 405 406 407 408 409
	error = -xfs_remove(XFS_I(dir), &name, XFS_I(dentry->d_inode));
	if (error)
		return error;

	/*
	 * With unlink, the VFS makes the dentry "negative": no inode,
	 * but still hashed. This is incompatible with case-insensitive
	 * mode, so invalidate (unhash) the dentry in CI-mode.
	 */
	if (xfs_sb_version_hasasciici(&XFS_M(dir->i_sb)->m_sb))
		d_invalidate(dentry);
	return 0;
L
Linus Torvalds 已提交
410 411 412
}

STATIC int
413
xfs_vn_symlink(
L
Linus Torvalds 已提交
414 415 416 417
	struct inode	*dir,
	struct dentry	*dentry,
	const char	*symname)
{
418 419
	struct inode	*inode;
	struct xfs_inode *cip = NULL;
420
	struct xfs_name	name;
L
Linus Torvalds 已提交
421
	int		error;
422
	mode_t		mode;
L
Linus Torvalds 已提交
423

424
	mode = S_IFLNK |
425
		(irix_symlink_mode ? 0777 & ~current->fs->umask : S_IRWXUGO);
426
	xfs_dentry_to_name(&name, dentry);
L
Linus Torvalds 已提交
427

428
	error = xfs_symlink(XFS_I(dir), &name, symname, mode, &cip, NULL);
429 430 431
	if (unlikely(error))
		goto out;

432
	inode = VFS_I(cip);
433 434 435 436 437 438 439 440 441

	error = xfs_init_security(inode, dir);
	if (unlikely(error))
		goto out_cleanup_inode;

	d_instantiate(dentry, inode);
	return 0;

 out_cleanup_inode:
442
	xfs_cleanup_inode(dir, inode, dentry);
443
 out:
L
Linus Torvalds 已提交
444 445 446 447
	return -error;
}

STATIC int
448
xfs_vn_rename(
L
Linus Torvalds 已提交
449 450 451 452 453 454
	struct inode	*odir,
	struct dentry	*odentry,
	struct inode	*ndir,
	struct dentry	*ndentry)
{
	struct inode	*new_inode = ndentry->d_inode;
455 456
	struct xfs_name	oname;
	struct xfs_name	nname;
L
Linus Torvalds 已提交
457

458 459 460
	xfs_dentry_to_name(&oname, odentry);
	xfs_dentry_to_name(&nname, ndentry);

461
	return -xfs_rename(XFS_I(odir), &oname, XFS_I(odentry->d_inode),
462 463
			   XFS_I(ndir), &nname, new_inode ?
			   			XFS_I(new_inode) : NULL);
L
Linus Torvalds 已提交
464 465 466 467 468 469 470
}

/*
 * 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...
 */
471
STATIC void *
472
xfs_vn_follow_link(
L
Linus Torvalds 已提交
473 474 475 476
	struct dentry		*dentry,
	struct nameidata	*nd)
{
	char			*link;
477
	int			error = -ENOMEM;
L
Linus Torvalds 已提交
478

479
	link = kmalloc(MAXPATHLEN+1, GFP_KERNEL);
480 481
	if (!link)
		goto out_err;
L
Linus Torvalds 已提交
482

483
	error = -xfs_readlink(XFS_I(dentry->d_inode), link);
484 485
	if (unlikely(error))
		goto out_kfree;
L
Linus Torvalds 已提交
486 487

	nd_set_link(nd, link);
488
	return NULL;
489 490 491 492 493 494

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

497
STATIC void
498
xfs_vn_put_link(
499 500 501
	struct dentry	*dentry,
	struct nameidata *nd,
	void		*p)
L
Linus Torvalds 已提交
502
{
503 504
	char		*s = nd_get_link(nd);

L
Linus Torvalds 已提交
505 506 507 508 509
	if (!IS_ERR(s))
		kfree(s);
}

#ifdef CONFIG_XFS_POSIX_ACL
C
Christoph Hellwig 已提交
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
STATIC int
xfs_check_acl(
	struct inode		*inode,
	int			mask)
{
	struct xfs_inode	*ip = XFS_I(inode);
	int			error;

	xfs_itrace_entry(ip);

	if (XFS_IFORK_Q(ip)) {
		error = xfs_acl_iaccess(ip, mask, NULL);
		if (error != -1)
			return -error;
	}

	return -EAGAIN;
}

L
Linus Torvalds 已提交
529
STATIC int
530
xfs_vn_permission(
C
Christoph Hellwig 已提交
531
	struct inode		*inode,
532
	int			mask)
L
Linus Torvalds 已提交
533
{
C
Christoph Hellwig 已提交
534
	return generic_permission(inode, mask, xfs_check_acl);
L
Linus Torvalds 已提交
535 536
}
#else
537
#define xfs_vn_permission NULL
L
Linus Torvalds 已提交
538 539 540
#endif

STATIC int
541
xfs_vn_getattr(
542 543 544
	struct vfsmount		*mnt,
	struct dentry		*dentry,
	struct kstat		*stat)
L
Linus Torvalds 已提交
545
{
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581
	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:
582
		if (XFS_IS_REALTIME_INODE(ip)) {
583 584 585 586 587 588 589 590 591 592 593
			/*
			 * 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;
594
	}
595 596

	return 0;
L
Linus Torvalds 已提交
597 598 599
}

STATIC int
600
xfs_vn_setattr(
L
Linus Torvalds 已提交
601
	struct dentry	*dentry,
602
	struct iattr	*iattr)
L
Linus Torvalds 已提交
603
{
C
Christoph Hellwig 已提交
604
	return -xfs_setattr(XFS_I(dentry->d_inode), iattr, 0);
L
Linus Torvalds 已提交
605 606
}

607 608 609 610 611
/*
 * block_truncate_page can return an error, but we can't propagate it
 * at all here. Leave a complaint + stack trace in the syslog because
 * this could be bad. If it is bad, we need to propagate the error further.
 */
L
Linus Torvalds 已提交
612
STATIC void
613
xfs_vn_truncate(
L
Linus Torvalds 已提交
614 615
	struct inode	*inode)
{
616 617 618 619
	int	error;
	error = block_truncate_page(inode->i_mapping, inode->i_size,
							xfs_get_blocks);
	WARN_ON(error);
L
Linus Torvalds 已提交
620 621
}

D
David Chinner 已提交
622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
STATIC long
xfs_vn_fallocate(
	struct inode	*inode,
	int		mode,
	loff_t		offset,
	loff_t		len)
{
	long		error;
	loff_t		new_size = 0;
	xfs_flock64_t	bf;
	xfs_inode_t	*ip = XFS_I(inode);

	/* preallocation on directories not yet supported */
	error = -ENODEV;
	if (S_ISDIR(inode->i_mode))
		goto out_error;

	bf.l_whence = 0;
	bf.l_start = offset;
	bf.l_len = len;

	xfs_ilock(ip, XFS_IOLOCK_EXCL);
	error = xfs_change_file_space(ip, XFS_IOC_RESVSP, &bf,
C
Christoph Hellwig 已提交
645
				      0, XFS_ATTR_NOLOCK);
D
David Chinner 已提交
646 647 648 649 650 651
	if (!error && !(mode & FALLOC_FL_KEEP_SIZE) &&
	    offset + len > i_size_read(inode))
		new_size = offset + len;

	/* Change file size if needed */
	if (new_size) {
652
		struct iattr iattr;
D
David Chinner 已提交
653

654 655
		iattr.ia_valid = ATTR_SIZE;
		iattr.ia_size = new_size;
C
Christoph Hellwig 已提交
656
		error = xfs_setattr(ip, &iattr, XFS_ATTR_NOLOCK);
D
David Chinner 已提交
657 658 659 660 661 662
	}

	xfs_iunlock(ip, XFS_IOLOCK_EXCL);
out_error:
	return error;
}
L
Linus Torvalds 已提交
663

664
static const struct inode_operations xfs_inode_operations = {
665 666 667 668
	.permission		= xfs_vn_permission,
	.truncate		= xfs_vn_truncate,
	.getattr		= xfs_vn_getattr,
	.setattr		= xfs_vn_setattr,
669 670 671
	.setxattr		= generic_setxattr,
	.getxattr		= generic_getxattr,
	.removexattr		= generic_removexattr,
672
	.listxattr		= xfs_vn_listxattr,
D
David Chinner 已提交
673
	.fallocate		= xfs_vn_fallocate,
L
Linus Torvalds 已提交
674 675
};

676
static const struct inode_operations xfs_dir_inode_operations = {
677 678 679 680 681 682
	.create			= xfs_vn_create,
	.lookup			= xfs_vn_lookup,
	.link			= xfs_vn_link,
	.unlink			= xfs_vn_unlink,
	.symlink		= xfs_vn_symlink,
	.mkdir			= xfs_vn_mkdir,
683 684 685 686 687 688 689
	/*
	 * Yes, XFS uses the same method for rmdir and unlink.
	 *
	 * There are some subtile differences deeper in the code,
	 * but we use S_ISDIR to check for those.
	 */
	.rmdir			= xfs_vn_unlink,
690 691 692 693 694
	.mknod			= xfs_vn_mknod,
	.rename			= xfs_vn_rename,
	.permission		= xfs_vn_permission,
	.getattr		= xfs_vn_getattr,
	.setattr		= xfs_vn_setattr,
695 696 697
	.setxattr		= generic_setxattr,
	.getxattr		= generic_getxattr,
	.removexattr		= generic_removexattr,
698
	.listxattr		= xfs_vn_listxattr,
L
Linus Torvalds 已提交
699 700
};

701
static const struct inode_operations xfs_dir_ci_inode_operations = {
702 703 704 705 706 707
	.create			= xfs_vn_create,
	.lookup			= xfs_vn_ci_lookup,
	.link			= xfs_vn_link,
	.unlink			= xfs_vn_unlink,
	.symlink		= xfs_vn_symlink,
	.mkdir			= xfs_vn_mkdir,
708 709 710 711 712 713 714
	/*
	 * Yes, XFS uses the same method for rmdir and unlink.
	 *
	 * There are some subtile differences deeper in the code,
	 * but we use S_ISDIR to check for those.
	 */
	.rmdir			= xfs_vn_unlink,
715 716 717 718 719
	.mknod			= xfs_vn_mknod,
	.rename			= xfs_vn_rename,
	.permission		= xfs_vn_permission,
	.getattr		= xfs_vn_getattr,
	.setattr		= xfs_vn_setattr,
720 721 722
	.setxattr		= generic_setxattr,
	.getxattr		= generic_getxattr,
	.removexattr		= generic_removexattr,
723 724 725
	.listxattr		= xfs_vn_listxattr,
};

726
static const struct inode_operations xfs_symlink_inode_operations = {
L
Linus Torvalds 已提交
727
	.readlink		= generic_readlink,
728 729 730 731 732
	.follow_link		= xfs_vn_follow_link,
	.put_link		= xfs_vn_put_link,
	.permission		= xfs_vn_permission,
	.getattr		= xfs_vn_getattr,
	.setattr		= xfs_vn_setattr,
733 734 735
	.setxattr		= generic_setxattr,
	.getxattr		= generic_getxattr,
	.removexattr		= generic_removexattr,
736
	.listxattr		= xfs_vn_listxattr,
L
Linus Torvalds 已提交
737
};
738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768

STATIC void
xfs_diflags_to_iflags(
	struct inode		*inode,
	struct xfs_inode	*ip)
{
	if (ip->i_d.di_flags & XFS_DIFLAG_IMMUTABLE)
		inode->i_flags |= S_IMMUTABLE;
	else
		inode->i_flags &= ~S_IMMUTABLE;
	if (ip->i_d.di_flags & XFS_DIFLAG_APPEND)
		inode->i_flags |= S_APPEND;
	else
		inode->i_flags &= ~S_APPEND;
	if (ip->i_d.di_flags & XFS_DIFLAG_SYNC)
		inode->i_flags |= S_SYNC;
	else
		inode->i_flags &= ~S_SYNC;
	if (ip->i_d.di_flags & XFS_DIFLAG_NOATIME)
		inode->i_flags |= S_NOATIME;
	else
		inode->i_flags &= ~S_NOATIME;
}

/*
 * Initialize the Linux inode, set up the operation vectors and
 * unlock the inode.
 *
 * When reading existing inodes from disk this is called directly
 * from xfs_iget, when creating a new inode it is called from
 * xfs_ialloc after setting up the inode.
769 770 771 772
 *
 * We are always called with an uninitialised linux inode here.
 * We need to initialise the necessary fields and take a reference
 * on it.
773 774 775 776 777
 */
void
xfs_setup_inode(
	struct xfs_inode	*ip)
{
778 779 780 781 782
	struct inode		*inode = &ip->i_vnode;

	inode->i_ino = ip->i_ino;
	inode->i_state = I_NEW|I_LOCK;
	inode_add_to_lists(ip->i_mount->m_super, inode);
783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840

	inode->i_mode	= ip->i_d.di_mode;
	inode->i_nlink	= ip->i_d.di_nlink;
	inode->i_uid	= ip->i_d.di_uid;
	inode->i_gid	= ip->i_d.di_gid;

	switch (inode->i_mode & S_IFMT) {
	case S_IFBLK:
	case S_IFCHR:
		inode->i_rdev =
			MKDEV(sysv_major(ip->i_df.if_u2.if_rdev) & 0x1ff,
			      sysv_minor(ip->i_df.if_u2.if_rdev));
		break;
	default:
		inode->i_rdev = 0;
		break;
	}

	inode->i_generation = ip->i_d.di_gen;
	i_size_write(inode, ip->i_d.di_size);
	inode->i_atime.tv_sec	= ip->i_d.di_atime.t_sec;
	inode->i_atime.tv_nsec	= ip->i_d.di_atime.t_nsec;
	inode->i_mtime.tv_sec	= ip->i_d.di_mtime.t_sec;
	inode->i_mtime.tv_nsec	= ip->i_d.di_mtime.t_nsec;
	inode->i_ctime.tv_sec	= ip->i_d.di_ctime.t_sec;
	inode->i_ctime.tv_nsec	= ip->i_d.di_ctime.t_nsec;
	xfs_diflags_to_iflags(inode, ip);
	xfs_iflags_clear(ip, XFS_IMODIFIED);

	switch (inode->i_mode & S_IFMT) {
	case S_IFREG:
		inode->i_op = &xfs_inode_operations;
		inode->i_fop = &xfs_file_operations;
		inode->i_mapping->a_ops = &xfs_address_space_operations;
		break;
	case S_IFDIR:
		if (xfs_sb_version_hasasciici(&XFS_M(inode->i_sb)->m_sb))
			inode->i_op = &xfs_dir_ci_inode_operations;
		else
			inode->i_op = &xfs_dir_inode_operations;
		inode->i_fop = &xfs_dir_file_operations;
		break;
	case S_IFLNK:
		inode->i_op = &xfs_symlink_inode_operations;
		if (!(ip->i_df.if_flags & XFS_IFINLINE))
			inode->i_mapping->a_ops = &xfs_address_space_operations;
		break;
	default:
		inode->i_op = &xfs_inode_operations;
		init_special_inode(inode, inode->i_mode, inode->i_rdev);
		break;
	}

	xfs_iflags_clear(ip, XFS_INEW);
	barrier();

	unlock_new_inode(inode);
}