inode.c 25.1 KB
Newer Older
L
Linus Torvalds 已提交
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
/*
 *  linux/fs/ufs/inode.c
 *
 * Copyright (C) 1998
 * Daniel Pirkl <daniel.pirkl@email.cz>
 * Charles University, Faculty of Mathematics and Physics
 *
 *  from
 *
 *  linux/fs/ext2/inode.c
 *
 * Copyright (C) 1992, 1993, 1994, 1995
 * Remy Card (card@masi.ibp.fr)
 * Laboratoire MASI - Institut Blaise Pascal
 * Universite Pierre et Marie Curie (Paris VI)
 *
 *  from
 *
 *  linux/fs/minix/inode.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 *
 *  Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
 *  Big-endian to little-endian byte-swapping/bitmaps by
 *        David S. Miller (davem@caip.rutgers.edu), 1995
 */

#include <asm/uaccess.h>

#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/time.h>
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/buffer_head.h>
37
#include <linux/writeback.h>
L
Linus Torvalds 已提交
38

39
#include "ufs_fs.h"
40
#include "ufs.h"
L
Linus Torvalds 已提交
41 42 43
#include "swab.h"
#include "util.h"

A
Arnd Bergmann 已提交
44
static u64 ufs_frag_map(struct inode *inode, sector_t frag, bool needs_lock);
45

L
Linus Torvalds 已提交
46 47 48 49 50 51 52 53 54 55 56
static int ufs_block_to_path(struct inode *inode, sector_t i_block, sector_t offsets[4])
{
	struct ufs_sb_private_info *uspi = UFS_SB(inode->i_sb)->s_uspi;
	int ptrs = uspi->s_apb;
	int ptrs_bits = uspi->s_apbshift;
	const long direct_blocks = UFS_NDADDR,
		indirect_blocks = ptrs,
		double_blocks = (1 << (ptrs_bits * 2));
	int n = 0;


E
Evgeniy Dushistov 已提交
57
	UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks);
R
Roel Kluin 已提交
58
	if (i_block < direct_blocks) {
L
Linus Torvalds 已提交
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
		offsets[n++] = i_block;
	} else if ((i_block -= direct_blocks) < indirect_blocks) {
		offsets[n++] = UFS_IND_BLOCK;
		offsets[n++] = i_block;
	} else if ((i_block -= indirect_blocks) < double_blocks) {
		offsets[n++] = UFS_DIND_BLOCK;
		offsets[n++] = i_block >> ptrs_bits;
		offsets[n++] = i_block & (ptrs - 1);
	} else if (((i_block -= double_blocks) >> (ptrs_bits * 2)) < ptrs) {
		offsets[n++] = UFS_TIND_BLOCK;
		offsets[n++] = i_block >> (ptrs_bits * 2);
		offsets[n++] = (i_block >> ptrs_bits) & (ptrs - 1);
		offsets[n++] = i_block & (ptrs - 1);
	} else {
		ufs_warning(inode->i_sb, "ufs_block_to_path", "block > big");
	}
	return n;
}

/*
 * Returns the location of the fragment from
L
Lucas De Marchi 已提交
80
 * the beginning of the filesystem.
L
Linus Torvalds 已提交
81 82
 */

A
Arnd Bergmann 已提交
83
static u64 ufs_frag_map(struct inode *inode, sector_t frag, bool needs_lock)
L
Linus Torvalds 已提交
84 85 86 87 88 89 90 91 92 93 94 95 96 97
{
	struct ufs_inode_info *ufsi = UFS_I(inode);
	struct super_block *sb = inode->i_sb;
	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
	u64 mask = (u64) uspi->s_apbmask>>uspi->s_fpbshift;
	int shift = uspi->s_apbshift-uspi->s_fpbshift;
	sector_t offsets[4], *p;
	int depth = ufs_block_to_path(inode, frag >> uspi->s_fpbshift, offsets);
	u64  ret = 0L;
	__fs32 block;
	__fs64 u2_block = 0L;
	unsigned flags = UFS_SB(sb)->s_flags;
	u64 temp = 0L;

E
Evgeniy Dushistov 已提交
98
	UFSD(": frag = %llu  depth = %d\n", (unsigned long long)frag, depth);
A
Andrew Morton 已提交
99 100 101
	UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx\n",
		uspi->s_fpbshift, uspi->s_apbmask,
		(unsigned long long)mask);
L
Linus Torvalds 已提交
102 103 104 105 106 107

	if (depth == 0)
		return 0;

	p = offsets;

A
Arnd Bergmann 已提交
108 109
	if (needs_lock)
		lock_ufs(sb);
L
Linus Torvalds 已提交
110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
		goto ufs2;

	block = ufsi->i_u1.i_data[*p++];
	if (!block)
		goto out;
	while (--depth) {
		struct buffer_head *bh;
		sector_t n = *p++;

		bh = sb_bread(sb, uspi->s_sbbase + fs32_to_cpu(sb, block)+(n>>shift));
		if (!bh)
			goto out;
		block = ((__fs32 *) bh->b_data)[n & mask];
		brelse (bh);
		if (!block)
			goto out;
	}
	ret = (u64) (uspi->s_sbbase + fs32_to_cpu(sb, block) + (frag & uspi->s_fpbmask));
	goto out;
ufs2:
	u2_block = ufsi->i_u1.u2_i_data[*p++];
	if (!u2_block)
		goto out;


	while (--depth) {
		struct buffer_head *bh;
		sector_t n = *p++;


		temp = (u64)(uspi->s_sbbase) + fs64_to_cpu(sb, u2_block);
		bh = sb_bread(sb, temp +(u64) (n>>shift));
		if (!bh)
			goto out;
		u2_block = ((__fs64 *)bh->b_data)[n & mask];
		brelse(bh);
		if (!u2_block)
			goto out;
	}
	temp = (u64)uspi->s_sbbase + fs64_to_cpu(sb, u2_block);
	ret = temp + (u64) (frag & uspi->s_fpbmask);

out:
A
Arnd Bergmann 已提交
154 155
	if (needs_lock)
		unlock_ufs(sb);
L
Linus Torvalds 已提交
156 157 158
	return ret;
}

E
Evgeniy Dushistov 已提交
159 160 161 162 163 164 165 166 167 168 169 170 171 172
/**
 * ufs_inode_getfrag() - allocate new fragment(s)
 * @inode - pointer to inode
 * @fragment - number of `fragment' which hold pointer
 *   to new allocated fragment(s)
 * @new_fragment - number of new allocated fragment(s)
 * @required - how many fragment(s) we require
 * @err - we set it if something wrong
 * @phys - pointer to where we save physical number of new allocated fragments,
 *   NULL if we allocate not data(indirect blocks for example).
 * @new - we set it if we allocate new block
 * @locked_page - for ufs_new_fragments()
 */
static struct buffer_head *
173
ufs_inode_getfrag(struct inode *inode, u64 fragment,
E
Evgeniy Dushistov 已提交
174 175
		  sector_t new_fragment, unsigned int required, int *err,
		  long *phys, int *new, struct page *locked_page)
L
Linus Torvalds 已提交
176 177
{
	struct ufs_inode_info *ufsi = UFS_I(inode);
E
Evgeniy Dushistov 已提交
178 179
	struct super_block *sb = inode->i_sb;
	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
L
Linus Torvalds 已提交
180
	struct buffer_head * result;
181 182 183
	unsigned blockoff, lastblockoff;
	u64 tmp, goal, lastfrag, block, lastblock;
	void *p, *p2;
L
Linus Torvalds 已提交
184

185 186
	UFSD("ENTER, ino %lu, fragment %llu, new_fragment %llu, required %u, "
	     "metadata %d\n", inode->i_ino, (unsigned long long)fragment,
E
Evgeniy Dushistov 已提交
187
	     (unsigned long long)new_fragment, required, !phys);
L
Linus Torvalds 已提交
188 189 190 191 192 193 194 195

        /* TODO : to be done for write support
        if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
             goto ufs2;
         */

	block = ufs_fragstoblks (fragment);
	blockoff = ufs_fragnum (fragment);
196 197
	p = ufs_get_direct_data_ptr(uspi, ufsi, block);

L
Linus Torvalds 已提交
198 199 200
	goal = 0;

repeat:
201 202
	tmp = ufs_data_ptr_to_cpu(sb, p);

L
Linus Torvalds 已提交
203 204
	lastfrag = ufsi->i_lastfrag;
	if (tmp && fragment < lastfrag) {
E
Evgeniy Dushistov 已提交
205
		if (!phys) {
L
Linus Torvalds 已提交
206
			result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
207 208 209
			if (tmp == ufs_data_ptr_to_cpu(sb, p)) {
				UFSD("EXIT, result %llu\n",
				     (unsigned long long)tmp + blockoff);
L
Linus Torvalds 已提交
210 211 212 213 214
				return result;
			}
			brelse (result);
			goto repeat;
		} else {
215
			*phys = uspi->s_sbbase + tmp + blockoff;
L
Linus Torvalds 已提交
216 217 218 219 220 221 222 223 224 225 226 227 228 229
			return NULL;
		}
	}

	lastblock = ufs_fragstoblks (lastfrag);
	lastblockoff = ufs_fragnum (lastfrag);
	/*
	 * We will extend file into new block beyond last allocated block
	 */
	if (lastblock < block) {
		/*
		 * We must reallocate last allocated block
		 */
		if (lastblockoff) {
230 231 232 233 234
			p2 = ufs_get_direct_data_ptr(uspi, ufsi, lastblock);
			tmp = ufs_new_fragments(inode, p2, lastfrag,
						ufs_data_ptr_to_cpu(sb, p2),
						uspi->s_fpb - lastblockoff,
						err, locked_page);
L
Linus Torvalds 已提交
235 236 237 238 239 240 241 242 243
			if (!tmp) {
				if (lastfrag != ufsi->i_lastfrag)
					goto repeat;
				else
					return NULL;
			}
			lastfrag = ufsi->i_lastfrag;
			
		}
244 245 246
		tmp = ufs_data_ptr_to_cpu(sb,
					 ufs_get_direct_data_ptr(uspi, ufsi,
								 lastblock));
247 248
		if (tmp)
			goal = tmp + uspi->s_fpb;
L
Linus Torvalds 已提交
249
		tmp = ufs_new_fragments (inode, p, fragment - blockoff, 
250
					 goal, required + blockoff,
251 252
					 err,
					 phys != NULL ? locked_page : NULL);
253
	} else if (lastblock == block) {
L
Linus Torvalds 已提交
254 255 256
	/*
	 * We will extend last allocated block
	 */
257 258 259 260
		tmp = ufs_new_fragments(inode, p, fragment -
					(blockoff - lastblockoff),
					ufs_data_ptr_to_cpu(sb, p),
					required +  (blockoff - lastblockoff),
261
					err, phys != NULL ? locked_page : NULL);
262
	} else /* (lastblock > block) */ {
L
Linus Torvalds 已提交
263 264 265
	/*
	 * We will allocate new block before last allocated block
	 */
266
		if (block) {
267 268
			tmp = ufs_data_ptr_to_cpu(sb,
						 ufs_get_direct_data_ptr(uspi, ufsi, block - 1));
269 270 271
			if (tmp)
				goal = tmp + uspi->s_fpb;
		}
272
		tmp = ufs_new_fragments(inode, p, fragment - blockoff,
273 274
					goal, uspi->s_fpb, err,
					phys != NULL ? locked_page : NULL);
L
Linus Torvalds 已提交
275 276
	}
	if (!tmp) {
277
		if ((!blockoff && ufs_data_ptr_to_cpu(sb, p)) ||
L
Linus Torvalds 已提交
278 279 280 281 282 283
		    (blockoff && lastfrag != ufsi->i_lastfrag))
			goto repeat;
		*err = -ENOSPC;
		return NULL;
	}

E
Evgeniy Dushistov 已提交
284
	if (!phys) {
285
		result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
L
Linus Torvalds 已提交
286
	} else {
287
		*phys = uspi->s_sbbase + tmp + blockoff;
L
Linus Torvalds 已提交
288 289 290 291 292 293 294 295 296
		result = NULL;
		*err = 0;
		*new = 1;
	}

	inode->i_ctime = CURRENT_TIME_SEC;
	if (IS_SYNC(inode))
		ufs_sync_inode (inode);
	mark_inode_dirty(inode);
297
	UFSD("EXIT, result %llu\n", (unsigned long long)tmp + blockoff);
L
Linus Torvalds 已提交
298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315
	return result;

     /* This part : To be implemented ....
        Required only for writing, not required for READ-ONLY.
ufs2:

	u2_block = ufs_fragstoblks(fragment);
	u2_blockoff = ufs_fragnum(fragment);
	p = ufsi->i_u1.u2_i_data + block;
	goal = 0;

repeat2:
	tmp = fs32_to_cpu(sb, *p);
	lastfrag = ufsi->i_lastfrag;

     */
}

E
Evgeniy Dushistov 已提交
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
/**
 * ufs_inode_getblock() - allocate new block
 * @inode - pointer to inode
 * @bh - pointer to block which hold "pointer" to new allocated block
 * @fragment - number of `fragment' which hold pointer
 *   to new allocated block
 * @new_fragment - number of new allocated fragment
 *  (block will hold this fragment and also uspi->s_fpb-1)
 * @err - see ufs_inode_getfrag()
 * @phys - see ufs_inode_getfrag()
 * @new - see ufs_inode_getfrag()
 * @locked_page - see ufs_inode_getfrag()
 */
static struct buffer_head *
ufs_inode_getblock(struct inode *inode, struct buffer_head *bh,
331
		  u64 fragment, sector_t new_fragment, int *err,
E
Evgeniy Dushistov 已提交
332
		  long *phys, int *new, struct page *locked_page)
L
Linus Torvalds 已提交
333
{
E
Evgeniy Dushistov 已提交
334 335
	struct super_block *sb = inode->i_sb;
	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
L
Linus Torvalds 已提交
336
	struct buffer_head * result;
337 338 339
	unsigned blockoff;
	u64 tmp, goal, block;
	void *p;
L
Linus Torvalds 已提交
340 341 342 343

	block = ufs_fragstoblks (fragment);
	blockoff = ufs_fragnum (fragment);

344 345 346
	UFSD("ENTER, ino %lu, fragment %llu, new_fragment %llu, metadata %d\n",
	     inode->i_ino, (unsigned long long)fragment,
	     (unsigned long long)new_fragment, !phys);
L
Linus Torvalds 已提交
347 348 349 350 351 352 353 354 355 356

	result = NULL;
	if (!bh)
		goto out;
	if (!buffer_uptodate(bh)) {
		ll_rw_block (READ, 1, &bh);
		wait_on_buffer (bh);
		if (!buffer_uptodate(bh))
			goto out;
	}
357 358 359 360
	if (uspi->fs_magic == UFS2_MAGIC)
		p = (__fs64 *)bh->b_data + block;
	else
		p = (__fs32 *)bh->b_data + block;
L
Linus Torvalds 已提交
361
repeat:
362
	tmp = ufs_data_ptr_to_cpu(sb, p);
L
Linus Torvalds 已提交
363
	if (tmp) {
E
Evgeniy Dushistov 已提交
364
		if (!phys) {
L
Linus Torvalds 已提交
365
			result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
366
			if (tmp == ufs_data_ptr_to_cpu(sb, p))
L
Linus Torvalds 已提交
367 368 369 370
				goto out;
			brelse (result);
			goto repeat;
		} else {
371
			*phys = uspi->s_sbbase + tmp + blockoff;
L
Linus Torvalds 已提交
372 373 374 375
			goto out;
		}
	}

376 377 378
	if (block && (uspi->fs_magic == UFS2_MAGIC ?
		      (tmp = fs64_to_cpu(sb, ((__fs64 *)bh->b_data)[block-1])) :
		      (tmp = fs32_to_cpu(sb, ((__fs32 *)bh->b_data)[block-1]))))
L
Linus Torvalds 已提交
379 380 381
		goal = tmp + uspi->s_fpb;
	else
		goal = bh->b_blocknr + uspi->s_fpb;
382 383
	tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal,
				uspi->s_fpb, err, locked_page);
L
Linus Torvalds 已提交
384
	if (!tmp) {
385
		if (ufs_data_ptr_to_cpu(sb, p))
L
Linus Torvalds 已提交
386 387 388 389
			goto repeat;
		goto out;
	}		

390

E
Evgeniy Dushistov 已提交
391
	if (!phys) {
392
		result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
L
Linus Torvalds 已提交
393
	} else {
394
		*phys = uspi->s_sbbase + tmp + blockoff;
L
Linus Torvalds 已提交
395 396 397 398 399 400 401 402
		*new = 1;
	}

	mark_buffer_dirty(bh);
	if (IS_SYNC(inode))
		sync_dirty_buffer(bh);
	inode->i_ctime = CURRENT_TIME_SEC;
	mark_inode_dirty(inode);
403
	UFSD("result %llu\n", (unsigned long long)tmp + blockoff);
L
Linus Torvalds 已提交
404 405
out:
	brelse (bh);
E
Evgeniy Dushistov 已提交
406
	UFSD("EXIT\n");
L
Linus Torvalds 已提交
407 408 409
	return result;
}

E
Evgeniy Dushistov 已提交
410
/**
A
Alessio Igor Bogani 已提交
411
 * ufs_getfrag_block() - `get_block_t' function, interface between UFS and
E
Evgeniy Dushistov 已提交
412
 * readpage, writepage and so on
L
Linus Torvalds 已提交
413 414
 */

E
Evgeniy Dushistov 已提交
415
int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
L
Linus Torvalds 已提交
416 417
{
	struct super_block * sb = inode->i_sb;
A
Arnd Bergmann 已提交
418 419
	struct ufs_sb_info * sbi = UFS_SB(sb);
	struct ufs_sb_private_info * uspi = sbi->s_uspi;
L
Linus Torvalds 已提交
420 421 422 423
	struct buffer_head * bh;
	int ret, err, new;
	unsigned long ptr,phys;
	u64 phys64 = 0;
A
Arnd Bergmann 已提交
424
	bool needs_lock = (sbi->mutex_owner != current);
L
Linus Torvalds 已提交
425 426
	
	if (!create) {
A
Arnd Bergmann 已提交
427
		phys64 = ufs_frag_map(inode, fragment, needs_lock);
A
Andrew Morton 已提交
428
		UFSD("phys64 = %llu\n", (unsigned long long)phys64);
L
Linus Torvalds 已提交
429 430 431 432 433 434 435 436 437 438 439 440
		if (phys64)
			map_bh(bh_result, sb, phys64);
		return 0;
	}

        /* This code entered only while writing ....? */

	err = -EIO;
	new = 0;
	ret = 0;
	bh = NULL;

A
Arnd Bergmann 已提交
441 442
	if (needs_lock)
		lock_ufs(sb);
L
Linus Torvalds 已提交
443

E
Evgeniy Dushistov 已提交
444
	UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment);
L
Linus Torvalds 已提交
445 446 447 448 449 450 451 452 453 454 455 456 457
	if (fragment >
	    ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb)
	     << uspi->s_fpbshift))
		goto abort_too_big;

	err = 0;
	ptr = fragment;
	  
	/*
	 * ok, these macros clean the logic up a bit and make
	 * it much more readable:
	 */
#define GET_INODE_DATABLOCK(x) \
458 459
	ufs_inode_getfrag(inode, x, fragment, 1, &err, &phys, &new,\
			  bh_result->b_page)
L
Linus Torvalds 已提交
460
#define GET_INODE_PTR(x) \
461 462
	ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, NULL, NULL,\
			  bh_result->b_page)
L
Linus Torvalds 已提交
463
#define GET_INDIRECT_DATABLOCK(x) \
E
Evgeniy Dushistov 已提交
464
	ufs_inode_getblock(inode, bh, x, fragment,	\
465
			  &err, &phys, &new, bh_result->b_page)
L
Linus Torvalds 已提交
466
#define GET_INDIRECT_PTR(x) \
E
Evgeniy Dushistov 已提交
467
	ufs_inode_getblock(inode, bh, x, fragment,	\
468
			  &err, NULL, NULL, NULL)
L
Linus Torvalds 已提交
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503

	if (ptr < UFS_NDIR_FRAGMENT) {
		bh = GET_INODE_DATABLOCK(ptr);
		goto out;
	}
	ptr -= UFS_NDIR_FRAGMENT;
	if (ptr < (1 << (uspi->s_apbshift + uspi->s_fpbshift))) {
		bh = GET_INODE_PTR(UFS_IND_FRAGMENT + (ptr >> uspi->s_apbshift));
		goto get_indirect;
	}
	ptr -= 1 << (uspi->s_apbshift + uspi->s_fpbshift);
	if (ptr < (1 << (uspi->s_2apbshift + uspi->s_fpbshift))) {
		bh = GET_INODE_PTR(UFS_DIND_FRAGMENT + (ptr >> uspi->s_2apbshift));
		goto get_double;
	}
	ptr -= 1 << (uspi->s_2apbshift + uspi->s_fpbshift);
	bh = GET_INODE_PTR(UFS_TIND_FRAGMENT + (ptr >> uspi->s_3apbshift));
	bh = GET_INDIRECT_PTR((ptr >> uspi->s_2apbshift) & uspi->s_apbmask);
get_double:
	bh = GET_INDIRECT_PTR((ptr >> uspi->s_apbshift) & uspi->s_apbmask);
get_indirect:
	bh = GET_INDIRECT_DATABLOCK(ptr & uspi->s_apbmask);

#undef GET_INODE_DATABLOCK
#undef GET_INODE_PTR
#undef GET_INDIRECT_DATABLOCK
#undef GET_INDIRECT_PTR

out:
	if (err)
		goto abort;
	if (new)
		set_buffer_new(bh_result);
	map_bh(bh_result, sb, phys);
abort:
A
Arnd Bergmann 已提交
504 505 506
	if (needs_lock)
		unlock_ufs(sb);

L
Linus Torvalds 已提交
507 508 509 510 511 512 513 514 515 516 517
	return err;

abort_too_big:
	ufs_warning(sb, "ufs_get_block", "block > big");
	goto abort;
}

static int ufs_writepage(struct page *page, struct writeback_control *wbc)
{
	return block_write_full_page(page,ufs_getfrag_block,wbc);
}
N
Nick Piggin 已提交
518

L
Linus Torvalds 已提交
519 520 521 522
static int ufs_readpage(struct file *file, struct page *page)
{
	return block_read_full_page(page,ufs_getfrag_block);
}
N
Nick Piggin 已提交
523

524
int ufs_prepare_chunk(struct page *page, loff_t pos, unsigned len)
L
Linus Torvalds 已提交
525
{
526
	return __block_write_begin(page, pos, len, ufs_getfrag_block);
L
Linus Torvalds 已提交
527
}
N
Nick Piggin 已提交
528 529 530 531 532

static int ufs_write_begin(struct file *file, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned flags,
			struct page **pagep, void **fsdata)
{
533 534 535
	int ret;

	ret = block_write_begin(mapping, pos, len, flags, pagep,
536
				ufs_getfrag_block);
537 538 539 540 541 542 543
	if (unlikely(ret)) {
		loff_t isize = mapping->host->i_size;
		if (pos + len > isize)
			vmtruncate(mapping->host, isize);
	}

	return ret;
N
Nick Piggin 已提交
544 545
}

L
Linus Torvalds 已提交
546 547 548 549
static sector_t ufs_bmap(struct address_space *mapping, sector_t block)
{
	return generic_block_bmap(mapping,block,ufs_getfrag_block);
}
N
Nick Piggin 已提交
550

551
const struct address_space_operations ufs_aops = {
L
Linus Torvalds 已提交
552 553
	.readpage = ufs_readpage,
	.writepage = ufs_writepage,
N
Nick Piggin 已提交
554 555
	.write_begin = ufs_write_begin,
	.write_end = generic_write_end,
L
Linus Torvalds 已提交
556 557 558
	.bmap = ufs_bmap
};

559 560 561 562 563 564 565 566 567 568 569 570 571 572
static void ufs_set_inode_ops(struct inode *inode)
{
	if (S_ISREG(inode->i_mode)) {
		inode->i_op = &ufs_file_inode_operations;
		inode->i_fop = &ufs_file_operations;
		inode->i_mapping->a_ops = &ufs_aops;
	} else if (S_ISDIR(inode->i_mode)) {
		inode->i_op = &ufs_dir_inode_operations;
		inode->i_fop = &ufs_dir_operations;
		inode->i_mapping->a_ops = &ufs_aops;
	} else if (S_ISLNK(inode->i_mode)) {
		if (!inode->i_blocks)
			inode->i_op = &ufs_fast_symlink_inode_operations;
		else {
573
			inode->i_op = &ufs_symlink_inode_operations;
574 575 576 577 578 579 580
			inode->i_mapping->a_ops = &ufs_aops;
		}
	} else
		init_special_inode(inode, inode->i_mode,
				   ufs_get_inode_dev(inode->i_sb, UFS_I(inode)));
}

581
static int ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode)
L
Linus Torvalds 已提交
582 583
{
	struct ufs_inode_info *ufsi = UFS_I(inode);
584
	struct super_block *sb = inode->i_sb;
A
Al Viro 已提交
585
	umode_t mode;
L
Linus Torvalds 已提交
586 587 588 589 590

	/*
	 * Copy data to the in-core inode.
	 */
	inode->i_mode = mode = fs16_to_cpu(sb, ufs_inode->ui_mode);
M
Miklos Szeredi 已提交
591
	set_nlink(inode, fs16_to_cpu(sb, ufs_inode->ui_nlink));
592
	if (inode->i_nlink == 0) {
L
Linus Torvalds 已提交
593
		ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino);
594 595
		return -1;
	}
L
Linus Torvalds 已提交
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
	
	/*
	 * Linux now has 32-bit uid and gid, so we can support EFT.
	 */
	inode->i_uid = ufs_get_inode_uid(sb, ufs_inode);
	inode->i_gid = ufs_get_inode_gid(sb, ufs_inode);

	inode->i_size = fs64_to_cpu(sb, ufs_inode->ui_size);
	inode->i_atime.tv_sec = fs32_to_cpu(sb, ufs_inode->ui_atime.tv_sec);
	inode->i_ctime.tv_sec = fs32_to_cpu(sb, ufs_inode->ui_ctime.tv_sec);
	inode->i_mtime.tv_sec = fs32_to_cpu(sb, ufs_inode->ui_mtime.tv_sec);
	inode->i_mtime.tv_nsec = 0;
	inode->i_atime.tv_nsec = 0;
	inode->i_ctime.tv_nsec = 0;
	inode->i_blocks = fs32_to_cpu(sb, ufs_inode->ui_blocks);
611
	inode->i_generation = fs32_to_cpu(sb, ufs_inode->ui_gen);
L
Linus Torvalds 已提交
612 613 614
	ufsi->i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags);
	ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
	ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag);
615

L
Linus Torvalds 已提交
616 617
	
	if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) {
618 619
		memcpy(ufsi->i_u1.i_data, &ufs_inode->ui_u2.ui_addr,
		       sizeof(ufs_inode->ui_u2.ui_addr));
620
	} else {
621
		memcpy(ufsi->i_u1.i_symlink, ufs_inode->ui_u2.ui_symlink,
622 623
		       sizeof(ufs_inode->ui_u2.ui_symlink) - 1);
		ufsi->i_u1.i_symlink[sizeof(ufs_inode->ui_u2.ui_symlink) - 1] = 0;
L
Linus Torvalds 已提交
624
	}
625
	return 0;
626
}
L
Linus Torvalds 已提交
627

628
static int ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode)
629 630 631
{
	struct ufs_inode_info *ufsi = UFS_I(inode);
	struct super_block *sb = inode->i_sb;
A
Al Viro 已提交
632
	umode_t mode;
L
Linus Torvalds 已提交
633

E
Evgeniy Dushistov 已提交
634
	UFSD("Reading ufs2 inode, ino %lu\n", inode->i_ino);
L
Linus Torvalds 已提交
635 636 637 638
	/*
	 * Copy data to the in-core inode.
	 */
	inode->i_mode = mode = fs16_to_cpu(sb, ufs2_inode->ui_mode);
M
Miklos Szeredi 已提交
639
	set_nlink(inode, fs16_to_cpu(sb, ufs2_inode->ui_nlink));
640
	if (inode->i_nlink == 0) {
L
Linus Torvalds 已提交
641
		ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino);
642 643
		return -1;
	}
L
Linus Torvalds 已提交
644 645 646 647 648 649 650 651

        /*
         * Linux now has 32-bit uid and gid, so we can support EFT.
         */
	inode->i_uid = fs32_to_cpu(sb, ufs2_inode->ui_uid);
	inode->i_gid = fs32_to_cpu(sb, ufs2_inode->ui_gid);

	inode->i_size = fs64_to_cpu(sb, ufs2_inode->ui_size);
652 653 654 655 656 657
	inode->i_atime.tv_sec = fs64_to_cpu(sb, ufs2_inode->ui_atime);
	inode->i_ctime.tv_sec = fs64_to_cpu(sb, ufs2_inode->ui_ctime);
	inode->i_mtime.tv_sec = fs64_to_cpu(sb, ufs2_inode->ui_mtime);
	inode->i_atime.tv_nsec = fs32_to_cpu(sb, ufs2_inode->ui_atimensec);
	inode->i_ctime.tv_nsec = fs32_to_cpu(sb, ufs2_inode->ui_ctimensec);
	inode->i_mtime.tv_nsec = fs32_to_cpu(sb, ufs2_inode->ui_mtimensec);
L
Linus Torvalds 已提交
658
	inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks);
659
	inode->i_generation = fs32_to_cpu(sb, ufs2_inode->ui_gen);
L
Linus Torvalds 已提交
660 661 662 663 664 665 666
	ufsi->i_flags = fs32_to_cpu(sb, ufs2_inode->ui_flags);
	/*
	ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow);
	ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag);
	*/

	if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) {
667 668
		memcpy(ufsi->i_u1.u2_i_data, &ufs2_inode->ui_u2.ui_addr,
		       sizeof(ufs2_inode->ui_u2.ui_addr));
669
	} else {
670
		memcpy(ufsi->i_u1.i_symlink, ufs2_inode->ui_u2.ui_symlink,
671 672
		       sizeof(ufs2_inode->ui_u2.ui_symlink) - 1);
		ufsi->i_u1.i_symlink[sizeof(ufs2_inode->ui_u2.ui_symlink) - 1] = 0;
L
Linus Torvalds 已提交
673
	}
674
	return 0;
675 676
}

677
struct inode *ufs_iget(struct super_block *sb, unsigned long ino)
678
{
679 680
	struct ufs_inode_info *ufsi;
	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
681
	struct buffer_head * bh;
682
	struct inode *inode;
683
	int err;
684

685
	UFSD("ENTER, ino %lu\n", ino);
686

687
	if (ino < UFS_ROOTINO || ino > (uspi->s_ncg * uspi->s_ipg)) {
688
		ufs_warning(sb, "ufs_read_inode", "bad inode number (%lu)\n",
689 690
			    ino);
		return ERR_PTR(-EIO);
691 692
	}

693 694 695 696 697 698 699 700
	inode = iget_locked(sb, ino);
	if (!inode)
		return ERR_PTR(-ENOMEM);
	if (!(inode->i_state & I_NEW))
		return inode;

	ufsi = UFS_I(inode);

701 702 703 704 705 706 707 708 709
	bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino));
	if (!bh) {
		ufs_warning(sb, "ufs_read_inode", "unable to read inode %lu\n",
			    inode->i_ino);
		goto bad_inode;
	}
	if ((UFS_SB(sb)->s_flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) {
		struct ufs2_inode *ufs2_inode = (struct ufs2_inode *)bh->b_data;

710 711
		err = ufs2_read_inode(inode,
				      ufs2_inode + ufs_inotofsbo(inode->i_ino));
712 713 714
	} else {
		struct ufs_inode *ufs_inode = (struct ufs_inode *)bh->b_data;

715 716
		err = ufs1_read_inode(inode,
				      ufs_inode + ufs_inotofsbo(inode->i_ino));
717 718
	}

719 720
	if (err)
		goto bad_inode;
721 722 723 724
	inode->i_version++;
	ufsi->i_lastfrag =
		(inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
	ufsi->i_dir_start_lookup = 0;
L
Linus Torvalds 已提交
725 726
	ufsi->i_osync = 0;

727
	ufs_set_inode_ops(inode);
L
Linus Torvalds 已提交
728 729 730

	brelse(bh);

E
Evgeniy Dushistov 已提交
731
	UFSD("EXIT\n");
732 733
	unlock_new_inode(inode);
	return inode;
734 735

bad_inode:
736 737
	iget_failed(inode);
	return ERR_PTR(-EIO);
L
Linus Torvalds 已提交
738 739
}

740
static void ufs1_update_inode(struct inode *inode, struct ufs_inode *ufs_inode)
L
Linus Torvalds 已提交
741
{
742 743
	struct super_block *sb = inode->i_sb;
 	struct ufs_inode_info *ufsi = UFS_I(inode);
L
Linus Torvalds 已提交
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759

	ufs_inode->ui_mode = cpu_to_fs16(sb, inode->i_mode);
	ufs_inode->ui_nlink = cpu_to_fs16(sb, inode->i_nlink);

	ufs_set_inode_uid(sb, ufs_inode, inode->i_uid);
	ufs_set_inode_gid(sb, ufs_inode, inode->i_gid);
		
	ufs_inode->ui_size = cpu_to_fs64(sb, inode->i_size);
	ufs_inode->ui_atime.tv_sec = cpu_to_fs32(sb, inode->i_atime.tv_sec);
	ufs_inode->ui_atime.tv_usec = 0;
	ufs_inode->ui_ctime.tv_sec = cpu_to_fs32(sb, inode->i_ctime.tv_sec);
	ufs_inode->ui_ctime.tv_usec = 0;
	ufs_inode->ui_mtime.tv_sec = cpu_to_fs32(sb, inode->i_mtime.tv_sec);
	ufs_inode->ui_mtime.tv_usec = 0;
	ufs_inode->ui_blocks = cpu_to_fs32(sb, inode->i_blocks);
	ufs_inode->ui_flags = cpu_to_fs32(sb, ufsi->i_flags);
760
	ufs_inode->ui_gen = cpu_to_fs32(sb, inode->i_generation);
L
Linus Torvalds 已提交
761

762
	if ((UFS_SB(sb)->s_flags & UFS_UID_MASK) == UFS_UID_EFT) {
L
Linus Torvalds 已提交
763 764 765 766 767 768 769 770
		ufs_inode->ui_u3.ui_sun.ui_shadow = cpu_to_fs32(sb, ufsi->i_shadow);
		ufs_inode->ui_u3.ui_sun.ui_oeftflag = cpu_to_fs32(sb, ufsi->i_oeftflag);
	}

	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
		/* ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, inode->i_rdev); */
		ufs_inode->ui_u2.ui_addr.ui_db[0] = ufsi->i_u1.i_data[0];
	} else if (inode->i_blocks) {
771 772
		memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.i_data,
		       sizeof(ufs_inode->ui_u2.ui_addr));
L
Linus Torvalds 已提交
773 774
	}
	else {
775 776
		memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink,
		       sizeof(ufs_inode->ui_u2.ui_symlink));
L
Linus Torvalds 已提交
777 778 779 780
	}

	if (!inode->i_nlink)
		memset (ufs_inode, 0, sizeof(struct ufs_inode));
781 782 783 784 785 786 787 788 789 790 791 792 793 794 795
}

static void ufs2_update_inode(struct inode *inode, struct ufs2_inode *ufs_inode)
{
	struct super_block *sb = inode->i_sb;
 	struct ufs_inode_info *ufsi = UFS_I(inode);

	UFSD("ENTER\n");
	ufs_inode->ui_mode = cpu_to_fs16(sb, inode->i_mode);
	ufs_inode->ui_nlink = cpu_to_fs16(sb, inode->i_nlink);

	ufs_inode->ui_uid = cpu_to_fs32(sb, inode->i_uid);
	ufs_inode->ui_gid = cpu_to_fs32(sb, inode->i_gid);

	ufs_inode->ui_size = cpu_to_fs64(sb, inode->i_size);
796 797 798 799 800 801
	ufs_inode->ui_atime = cpu_to_fs64(sb, inode->i_atime.tv_sec);
	ufs_inode->ui_atimensec = cpu_to_fs32(sb, inode->i_atime.tv_nsec);
	ufs_inode->ui_ctime = cpu_to_fs64(sb, inode->i_ctime.tv_sec);
	ufs_inode->ui_ctimensec = cpu_to_fs32(sb, inode->i_ctime.tv_nsec);
	ufs_inode->ui_mtime = cpu_to_fs64(sb, inode->i_mtime.tv_sec);
	ufs_inode->ui_mtimensec = cpu_to_fs32(sb, inode->i_mtime.tv_nsec);
802 803 804 805 806 807 808 809 810

	ufs_inode->ui_blocks = cpu_to_fs64(sb, inode->i_blocks);
	ufs_inode->ui_flags = cpu_to_fs32(sb, ufsi->i_flags);
	ufs_inode->ui_gen = cpu_to_fs32(sb, inode->i_generation);

	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
		/* ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, inode->i_rdev); */
		ufs_inode->ui_u2.ui_addr.ui_db[0] = ufsi->i_u1.u2_i_data[0];
	} else if (inode->i_blocks) {
811 812
		memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.u2_i_data,
		       sizeof(ufs_inode->ui_u2.ui_addr));
813
	} else {
814 815
		memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink,
		       sizeof(ufs_inode->ui_u2.ui_symlink));
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 841 842 843 844 845 846 847 848 849 850 851
 	}

	if (!inode->i_nlink)
		memset (ufs_inode, 0, sizeof(struct ufs2_inode));
	UFSD("EXIT\n");
}

static int ufs_update_inode(struct inode * inode, int do_sync)
{
	struct super_block *sb = inode->i_sb;
	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
	struct buffer_head * bh;

	UFSD("ENTER, ino %lu\n", inode->i_ino);

	if (inode->i_ino < UFS_ROOTINO ||
	    inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) {
		ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino);
		return -1;
	}

	bh = sb_bread(sb, ufs_inotofsba(inode->i_ino));
	if (!bh) {
		ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino);
		return -1;
	}
	if (uspi->fs_magic == UFS2_MAGIC) {
		struct ufs2_inode *ufs2_inode = (struct ufs2_inode *)bh->b_data;

		ufs2_update_inode(inode,
				  ufs2_inode + ufs_inotofsbo(inode->i_ino));
	} else {
		struct ufs_inode *ufs_inode = (struct ufs_inode *) bh->b_data;

		ufs1_update_inode(inode, ufs_inode + ufs_inotofsbo(inode->i_ino));
	}
L
Linus Torvalds 已提交
852 853 854 855 856 857
		
	mark_buffer_dirty(bh);
	if (do_sync)
		sync_dirty_buffer(bh);
	brelse (bh);
	
E
Evgeniy Dushistov 已提交
858
	UFSD("EXIT\n");
L
Linus Torvalds 已提交
859 860 861
	return 0;
}

862
int ufs_write_inode(struct inode *inode, struct writeback_control *wbc)
L
Linus Torvalds 已提交
863 864
{
	int ret;
A
Arnd Bergmann 已提交
865
	lock_ufs(inode->i_sb);
866
	ret = ufs_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
A
Arnd Bergmann 已提交
867
	unlock_ufs(inode->i_sb);
L
Linus Torvalds 已提交
868 869 870 871 872 873 874 875
	return ret;
}

int ufs_sync_inode (struct inode *inode)
{
	return ufs_update_inode (inode, 1);
}

A
Al Viro 已提交
876
void ufs_evict_inode(struct inode * inode)
L
Linus Torvalds 已提交
877
{
A
Al Viro 已提交
878 879 880 881
	int want_delete = 0;

	if (!inode->i_nlink && !is_bad_inode(inode))
		want_delete = 1;
882

883
	truncate_inode_pages(&inode->i_data, 0);
A
Al Viro 已提交
884 885 886
	if (want_delete) {
		loff_t old_i_size;
		/*UFS_I(inode)->i_dtime = CURRENT_TIME;*/
A
Arnd Bergmann 已提交
887
		lock_ufs(inode->i_sb);
A
Al Viro 已提交
888 889 890 891 892 893
		mark_inode_dirty(inode);
		ufs_update_inode(inode, IS_SYNC(inode));
		old_i_size = inode->i_size;
		inode->i_size = 0;
		if (inode->i_blocks && ufs_truncate(inode, old_i_size))
			ufs_warning(inode->i_sb, __func__, "ufs_truncate failed\n");
A
Arnd Bergmann 已提交
894
		unlock_ufs(inode->i_sb);
A
Al Viro 已提交
895 896 897
	}

	invalidate_inode_buffers(inode);
898
	clear_inode(inode);
A
Al Viro 已提交
899 900

	if (want_delete) {
A
Arnd Bergmann 已提交
901
		lock_ufs(inode->i_sb);
A
Al Viro 已提交
902
		ufs_free_inode (inode);
A
Arnd Bergmann 已提交
903
		unlock_ufs(inode->i_sb);
A
Al Viro 已提交
904
	}
L
Linus Torvalds 已提交
905
}