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 37
/*
 *  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 <asm/system.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>
38
#include <linux/writeback.h>
L
Linus Torvalds 已提交
39

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

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

L
Linus Torvalds 已提交
47 48 49 50 51 52 53 54 55 56 57
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 已提交
58
	UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks);
R
Roel Kluin 已提交
59
	if (i_block < direct_blocks) {
L
Linus Torvalds 已提交
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
		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 已提交
81
 * the beginning of the filesystem.
L
Linus Torvalds 已提交
82 83
 */

A
Arnd Bergmann 已提交
84
static u64 ufs_frag_map(struct inode *inode, sector_t frag, bool needs_lock)
L
Linus Torvalds 已提交
85 86 87 88 89 90 91 92 93 94 95 96 97 98
{
	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 已提交
99
	UFSD(": frag = %llu  depth = %d\n", (unsigned long long)frag, depth);
A
Andrew Morton 已提交
100 101 102
	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 已提交
103 104 105 106 107 108

	if (depth == 0)
		return 0;

	p = offsets;

A
Arnd Bergmann 已提交
109 110
	if (needs_lock)
		lock_ufs(sb);
L
Linus Torvalds 已提交
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 154
	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 已提交
155 156
	if (needs_lock)
		unlock_ufs(sb);
L
Linus Torvalds 已提交
157 158 159
	return ret;
}

E
Evgeniy Dushistov 已提交
160 161 162 163 164 165 166 167 168 169 170 171 172 173
/**
 * 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 *
174
ufs_inode_getfrag(struct inode *inode, u64 fragment,
E
Evgeniy Dushistov 已提交
175 176
		  sector_t new_fragment, unsigned int required, int *err,
		  long *phys, int *new, struct page *locked_page)
L
Linus Torvalds 已提交
177 178
{
	struct ufs_inode_info *ufsi = UFS_I(inode);
E
Evgeniy Dushistov 已提交
179 180
	struct super_block *sb = inode->i_sb;
	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
L
Linus Torvalds 已提交
181
	struct buffer_head * result;
182 183 184
	unsigned blockoff, lastblockoff;
	u64 tmp, goal, lastfrag, block, lastblock;
	void *p, *p2;
L
Linus Torvalds 已提交
185

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

        /* 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);
197 198
	p = ufs_get_direct_data_ptr(uspi, ufsi, block);

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

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

L
Linus Torvalds 已提交
204 205
	lastfrag = ufsi->i_lastfrag;
	if (tmp && fragment < lastfrag) {
E
Evgeniy Dushistov 已提交
206
		if (!phys) {
L
Linus Torvalds 已提交
207
			result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
208 209 210
			if (tmp == ufs_data_ptr_to_cpu(sb, p)) {
				UFSD("EXIT, result %llu\n",
				     (unsigned long long)tmp + blockoff);
L
Linus Torvalds 已提交
211 212 213 214 215
				return result;
			}
			brelse (result);
			goto repeat;
		} else {
216
			*phys = uspi->s_sbbase + tmp + blockoff;
L
Linus Torvalds 已提交
217 218 219 220 221 222 223 224 225 226 227 228 229 230
			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) {
231 232 233 234 235
			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 已提交
236 237 238 239 240 241 242 243 244
			if (!tmp) {
				if (lastfrag != ufsi->i_lastfrag)
					goto repeat;
				else
					return NULL;
			}
			lastfrag = ufsi->i_lastfrag;
			
		}
245 246 247
		tmp = ufs_data_ptr_to_cpu(sb,
					 ufs_get_direct_data_ptr(uspi, ufsi,
								 lastblock));
248 249
		if (tmp)
			goal = tmp + uspi->s_fpb;
L
Linus Torvalds 已提交
250
		tmp = ufs_new_fragments (inode, p, fragment - blockoff, 
251
					 goal, required + blockoff,
252 253
					 err,
					 phys != NULL ? locked_page : NULL);
254
	} else if (lastblock == block) {
L
Linus Torvalds 已提交
255 256 257
	/*
	 * We will extend last allocated block
	 */
258 259 260 261
		tmp = ufs_new_fragments(inode, p, fragment -
					(blockoff - lastblockoff),
					ufs_data_ptr_to_cpu(sb, p),
					required +  (blockoff - lastblockoff),
262
					err, phys != NULL ? locked_page : NULL);
263
	} else /* (lastblock > block) */ {
L
Linus Torvalds 已提交
264 265 266
	/*
	 * We will allocate new block before last allocated block
	 */
267
		if (block) {
268 269
			tmp = ufs_data_ptr_to_cpu(sb,
						 ufs_get_direct_data_ptr(uspi, ufsi, block - 1));
270 271 272
			if (tmp)
				goal = tmp + uspi->s_fpb;
		}
273
		tmp = ufs_new_fragments(inode, p, fragment - blockoff,
274 275
					goal, uspi->s_fpb, err,
					phys != NULL ? locked_page : NULL);
L
Linus Torvalds 已提交
276 277
	}
	if (!tmp) {
278
		if ((!blockoff && ufs_data_ptr_to_cpu(sb, p)) ||
L
Linus Torvalds 已提交
279 280 281 282 283 284
		    (blockoff && lastfrag != ufsi->i_lastfrag))
			goto repeat;
		*err = -ENOSPC;
		return NULL;
	}

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

	inode->i_ctime = CURRENT_TIME_SEC;
	if (IS_SYNC(inode))
		ufs_sync_inode (inode);
	mark_inode_dirty(inode);
298
	UFSD("EXIT, result %llu\n", (unsigned long long)tmp + blockoff);
L
Linus Torvalds 已提交
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
	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 已提交
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331
/**
 * 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,
332
		  u64 fragment, sector_t new_fragment, int *err,
E
Evgeniy Dushistov 已提交
333
		  long *phys, int *new, struct page *locked_page)
L
Linus Torvalds 已提交
334
{
E
Evgeniy Dushistov 已提交
335 336
	struct super_block *sb = inode->i_sb;
	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
L
Linus Torvalds 已提交
337
	struct buffer_head * result;
338 339 340
	unsigned blockoff;
	u64 tmp, goal, block;
	void *p;
L
Linus Torvalds 已提交
341 342 343 344

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

345 346 347
	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 已提交
348 349 350 351 352 353 354 355 356 357

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

377 378 379
	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 已提交
380 381 382
		goal = tmp + uspi->s_fpb;
	else
		goal = bh->b_blocknr + uspi->s_fpb;
383 384
	tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal,
				uspi->s_fpb, err, locked_page);
L
Linus Torvalds 已提交
385
	if (!tmp) {
386
		if (ufs_data_ptr_to_cpu(sb, p))
L
Linus Torvalds 已提交
387 388 389 390
			goto repeat;
		goto out;
	}		

391

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

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

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

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

E
Evgeniy Dushistov 已提交
445
	UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment);
L
Linus Torvalds 已提交
446 447 448 449 450 451 452 453 454 455 456 457 458
	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) \
459 460
	ufs_inode_getfrag(inode, x, fragment, 1, &err, &phys, &new,\
			  bh_result->b_page)
L
Linus Torvalds 已提交
461
#define GET_INODE_PTR(x) \
462 463
	ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, NULL, NULL,\
			  bh_result->b_page)
L
Linus Torvalds 已提交
464
#define GET_INDIRECT_DATABLOCK(x) \
E
Evgeniy Dushistov 已提交
465
	ufs_inode_getblock(inode, bh, x, fragment,	\
466
			  &err, &phys, &new, bh_result->b_page)
L
Linus Torvalds 已提交
467
#define GET_INDIRECT_PTR(x) \
E
Evgeniy Dushistov 已提交
468
	ufs_inode_getblock(inode, bh, x, fragment,	\
469
			  &err, NULL, NULL, NULL)
L
Linus Torvalds 已提交
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 504

	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 已提交
505 506 507
	if (needs_lock)
		unlock_ufs(sb);

L
Linus Torvalds 已提交
508 509 510 511 512 513 514 515 516 517 518
	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 已提交
519

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

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

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

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

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

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

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

560 561 562 563 564 565 566 567 568 569 570 571 572 573
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 {
574
			inode->i_op = &ufs_symlink_inode_operations;
575 576 577 578 579 580 581
			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)));
}

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

	/*
	 * Copy data to the in-core inode.
	 */
	inode->i_mode = mode = fs16_to_cpu(sb, ufs_inode->ui_mode);
M
Miklos Szeredi 已提交
592
	set_nlink(inode, fs16_to_cpu(sb, ufs_inode->ui_nlink));
593
	if (inode->i_nlink == 0) {
L
Linus Torvalds 已提交
594
		ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino);
595 596
		return -1;
	}
L
Linus Torvalds 已提交
597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
	
	/*
	 * 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);
612
	inode->i_generation = fs32_to_cpu(sb, ufs_inode->ui_gen);
L
Linus Torvalds 已提交
613 614 615
	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);
616

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

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

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

        /*
         * 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);
653 654 655 656 657 658
	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 已提交
659
	inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks);
660
	inode->i_generation = fs32_to_cpu(sb, ufs2_inode->ui_gen);
L
Linus Torvalds 已提交
661 662 663 664 665 666 667
	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) {
668 669
		memcpy(ufsi->i_u1.u2_i_data, &ufs2_inode->ui_u2.ui_addr,
		       sizeof(ufs2_inode->ui_u2.ui_addr));
670
	} else {
671
		memcpy(ufsi->i_u1.i_symlink, ufs2_inode->ui_u2.ui_symlink,
672 673
		       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 已提交
674
	}
675
	return 0;
676 677
}

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

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

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

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

	ufsi = UFS_I(inode);

702 703 704 705 706 707 708 709 710
	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;

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

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

720 721
	if (err)
		goto bad_inode;
722 723 724 725
	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 已提交
726 727
	ufsi->i_osync = 0;

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

	brelse(bh);

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

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

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

	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);
761
	ufs_inode->ui_gen = cpu_to_fs32(sb, inode->i_generation);
L
Linus Torvalds 已提交
762

763
	if ((UFS_SB(sb)->s_flags & UFS_UID_MASK) == UFS_UID_EFT) {
L
Linus Torvalds 已提交
764 765 766 767 768 769 770 771
		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) {
772 773
		memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.i_data,
		       sizeof(ufs_inode->ui_u2.ui_addr));
L
Linus Torvalds 已提交
774 775
	}
	else {
776 777
		memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink,
		       sizeof(ufs_inode->ui_u2.ui_symlink));
L
Linus Torvalds 已提交
778 779 780 781
	}

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

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);
797 798 799 800 801 802
	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);
803 804 805 806 807 808 809 810 811

	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) {
812 813
		memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.u2_i_data,
		       sizeof(ufs_inode->ui_u2.ui_addr));
814
	} else {
815 816
		memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink,
		       sizeof(ufs_inode->ui_u2.ui_symlink));
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 852
 	}

	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 已提交
853 854 855 856 857 858
		
	mark_buffer_dirty(bh);
	if (do_sync)
		sync_dirty_buffer(bh);
	brelse (bh);
	
E
Evgeniy Dushistov 已提交
859
	UFSD("EXIT\n");
L
Linus Torvalds 已提交
860 861 862
	return 0;
}

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

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

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

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

884
	truncate_inode_pages(&inode->i_data, 0);
A
Al Viro 已提交
885 886 887
	if (want_delete) {
		loff_t old_i_size;
		/*UFS_I(inode)->i_dtime = CURRENT_TIME;*/
A
Arnd Bergmann 已提交
888
		lock_ufs(inode->i_sb);
A
Al Viro 已提交
889 890 891 892 893 894
		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 已提交
895
		unlock_ufs(inode->i_sb);
A
Al Viro 已提交
896 897 898 899 900 901
	}

	invalidate_inode_buffers(inode);
	end_writeback(inode);

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