inode.c 35.6 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"

44
static int ufs_block_to_path(struct inode *inode, sector_t i_block, unsigned offsets[4])
L
Linus Torvalds 已提交
45 46 47 48 49 50 51 52 53 54
{
	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 已提交
55
	UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks);
R
Roel Kluin 已提交
56
	if (i_block < direct_blocks) {
L
Linus Torvalds 已提交
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
		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;
}

76 77 78 79 80 81 82 83 84 85 86 87 88 89 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
typedef struct {
	void	*p;
	union {
		__fs32	key32;
		__fs64	key64;
	};
	struct buffer_head *bh;
} Indirect;

static inline int grow_chain32(struct ufs_inode_info *ufsi,
			       struct buffer_head *bh, __fs32 *v,
			       Indirect *from, Indirect *to)
{
	Indirect *p;
	unsigned seq;
	to->bh = bh;
	do {
		seq = read_seqbegin(&ufsi->meta_lock);
		to->key32 = *(__fs32 *)(to->p = v);
		for (p = from; p <= to && p->key32 == *(__fs32 *)p->p; p++)
			;
	} while (read_seqretry(&ufsi->meta_lock, seq));
	return (p > to);
}

static inline int grow_chain64(struct ufs_inode_info *ufsi,
			       struct buffer_head *bh, __fs64 *v,
			       Indirect *from, Indirect *to)
{
	Indirect *p;
	unsigned seq;
	to->bh = bh;
	do {
		seq = read_seqbegin(&ufsi->meta_lock);
		to->key64 = *(__fs64 *)(to->p = v);
		for (p = from; p <= to && p->key64 == *(__fs64 *)p->p; p++)
			;
	} while (read_seqretry(&ufsi->meta_lock, seq));
	return (p > to);
}

L
Linus Torvalds 已提交
117 118
/*
 * Returns the location of the fragment from
L
Lucas De Marchi 已提交
119
 * the beginning of the filesystem.
L
Linus Torvalds 已提交
120 121
 */

122
static u64 ufs_frag_map(struct inode *inode, sector_t frag)
L
Linus Torvalds 已提交
123 124 125 126 127 128
{
	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;
A
Al Viro 已提交
129
	unsigned offsets[4], *p;
130
	Indirect chain[4], *q = chain;
L
Linus Torvalds 已提交
131 132
	int depth = ufs_block_to_path(inode, frag >> uspi->s_fpbshift, offsets);
	unsigned flags = UFS_SB(sb)->s_flags;
133
	u64 res = 0;
L
Linus Torvalds 已提交
134

E
Evgeniy Dushistov 已提交
135
	UFSD(": frag = %llu  depth = %d\n", (unsigned long long)frag, depth);
A
Andrew Morton 已提交
136 137 138
	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 已提交
139 140

	if (depth == 0)
141
		goto no_block;
L
Linus Torvalds 已提交
142

143
again:
L
Linus Torvalds 已提交
144 145 146 147 148
	p = offsets;

	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
		goto ufs2;

149 150 151 152
	if (!grow_chain32(ufsi, NULL, &ufsi->i_u1.i_data[*p++], chain, q))
		goto changed;
	if (!q->key32)
		goto no_block;
L
Linus Torvalds 已提交
153
	while (--depth) {
154
		__fs32 *ptr;
L
Linus Torvalds 已提交
155
		struct buffer_head *bh;
156
		unsigned n = *p++;
L
Linus Torvalds 已提交
157

158 159
		bh = sb_bread(sb, uspi->s_sbbase +
				  fs32_to_cpu(sb, q->key32) + (n>>shift));
L
Linus Torvalds 已提交
160
		if (!bh)
161 162 163 164 165 166
			goto no_block;
		ptr = (__fs32 *)bh->b_data + (n & mask);
		if (!grow_chain32(ufsi, bh, ptr, chain, ++q))
			goto changed;
		if (!q->key32)
			goto no_block;
L
Linus Torvalds 已提交
167
	}
168 169
	res = fs32_to_cpu(sb, q->key32);
	goto found;
L
Linus Torvalds 已提交
170

171 172 173 174 175
ufs2:
	if (!grow_chain64(ufsi, NULL, &ufsi->i_u1.u2_i_data[*p++], chain, q))
		goto changed;
	if (!q->key64)
		goto no_block;
L
Linus Torvalds 已提交
176 177

	while (--depth) {
178
		__fs64 *ptr;
L
Linus Torvalds 已提交
179
		struct buffer_head *bh;
180
		unsigned n = *p++;
L
Linus Torvalds 已提交
181

182 183
		bh = sb_bread(sb, uspi->s_sbbase +
				  fs64_to_cpu(sb, q->key64) + (n>>shift));
L
Linus Torvalds 已提交
184
		if (!bh)
185 186 187 188 189 190 191 192 193 194 195 196 197 198
			goto no_block;
		ptr = (__fs64 *)bh->b_data + (n & mask);
		if (!grow_chain64(ufsi, bh, ptr, chain, ++q))
			goto changed;
		if (!q->key64)
			goto no_block;
	}
	res = fs64_to_cpu(sb, q->key64);
found:
	res += uspi->s_sbbase + (frag & uspi->s_fpbmask);
no_block:
	while (q > chain) {
		brelse(q->bh);
		q--;
L
Linus Torvalds 已提交
199
	}
200
	return res;
L
Linus Torvalds 已提交
201

202 203 204 205 206 207
changed:
	while (q > chain) {
		brelse(q->bh);
		q--;
	}
	goto again;
L
Linus Torvalds 已提交
208 209
}

E
Evgeniy Dushistov 已提交
210 211
/**
 * ufs_inode_getfrag() - allocate new fragment(s)
212 213
 * @inode: pointer to inode
 * @fragment: number of `fragment' which hold pointer
E
Evgeniy Dushistov 已提交
214
 *   to new allocated fragment(s)
215 216 217 218
 * @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,
E
Evgeniy Dushistov 已提交
219
 *   NULL if we allocate not data(indirect blocks for example).
220 221
 * @new: we set it if we allocate new block
 * @locked_page: for ufs_new_fragments()
E
Evgeniy Dushistov 已提交
222 223
 */
static struct buffer_head *
224
ufs_inode_getfrag(struct inode *inode, u64 fragment,
E
Evgeniy Dushistov 已提交
225 226
		  sector_t new_fragment, unsigned int required, int *err,
		  long *phys, int *new, struct page *locked_page)
L
Linus Torvalds 已提交
227 228
{
	struct ufs_inode_info *ufsi = UFS_I(inode);
E
Evgeniy Dushistov 已提交
229 230
	struct super_block *sb = inode->i_sb;
	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
L
Linus Torvalds 已提交
231
	struct buffer_head * result;
232 233 234
	unsigned blockoff, lastblockoff;
	u64 tmp, goal, lastfrag, block, lastblock;
	void *p, *p2;
L
Linus Torvalds 已提交
235

236 237
	UFSD("ENTER, ino %lu, fragment %llu, new_fragment %llu, required %u, "
	     "metadata %d\n", inode->i_ino, (unsigned long long)fragment,
E
Evgeniy Dushistov 已提交
238
	     (unsigned long long)new_fragment, required, !phys);
L
Linus Torvalds 已提交
239 240 241 242 243 244 245 246

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

L
Linus Torvalds 已提交
249 250 251
	goal = 0;

repeat:
252 253
	tmp = ufs_data_ptr_to_cpu(sb, p);

L
Linus Torvalds 已提交
254 255
	lastfrag = ufsi->i_lastfrag;
	if (tmp && fragment < lastfrag) {
E
Evgeniy Dushistov 已提交
256
		if (!phys) {
L
Linus Torvalds 已提交
257
			result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
258 259 260
			if (tmp == ufs_data_ptr_to_cpu(sb, p)) {
				UFSD("EXIT, result %llu\n",
				     (unsigned long long)tmp + blockoff);
L
Linus Torvalds 已提交
261 262 263 264 265
				return result;
			}
			brelse (result);
			goto repeat;
		} else {
266
			*phys = uspi->s_sbbase + tmp + blockoff;
L
Linus Torvalds 已提交
267 268 269 270 271 272 273 274 275 276 277 278 279 280
			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) {
281 282 283 284 285
			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 已提交
286 287 288 289 290 291 292
			if (!tmp) {
				if (lastfrag != ufsi->i_lastfrag)
					goto repeat;
				else
					return NULL;
			}
			lastfrag = ufsi->i_lastfrag;
A
Al Viro 已提交
293

L
Linus Torvalds 已提交
294
		}
295 296 297
		tmp = ufs_data_ptr_to_cpu(sb,
					 ufs_get_direct_data_ptr(uspi, ufsi,
								 lastblock));
298 299
		if (tmp)
			goal = tmp + uspi->s_fpb;
A
Al Viro 已提交
300
		tmp = ufs_new_fragments (inode, p, fragment - blockoff,
301
					 goal, required + blockoff,
302 303
					 err,
					 phys != NULL ? locked_page : NULL);
304
	} else if (lastblock == block) {
L
Linus Torvalds 已提交
305 306 307
	/*
	 * We will extend last allocated block
	 */
308 309 310 311
		tmp = ufs_new_fragments(inode, p, fragment -
					(blockoff - lastblockoff),
					ufs_data_ptr_to_cpu(sb, p),
					required +  (blockoff - lastblockoff),
312
					err, phys != NULL ? locked_page : NULL);
313
	} else /* (lastblock > block) */ {
L
Linus Torvalds 已提交
314 315 316
	/*
	 * We will allocate new block before last allocated block
	 */
317
		if (block) {
318 319
			tmp = ufs_data_ptr_to_cpu(sb,
						 ufs_get_direct_data_ptr(uspi, ufsi, block - 1));
320 321 322
			if (tmp)
				goal = tmp + uspi->s_fpb;
		}
323
		tmp = ufs_new_fragments(inode, p, fragment - blockoff,
324 325
					goal, uspi->s_fpb, err,
					phys != NULL ? locked_page : NULL);
L
Linus Torvalds 已提交
326 327
	}
	if (!tmp) {
328
		if ((!blockoff && ufs_data_ptr_to_cpu(sb, p)) ||
L
Linus Torvalds 已提交
329 330 331 332 333 334
		    (blockoff && lastfrag != ufsi->i_lastfrag))
			goto repeat;
		*err = -ENOSPC;
		return NULL;
	}

E
Evgeniy Dushistov 已提交
335
	if (!phys) {
336
		result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
L
Linus Torvalds 已提交
337
	} else {
338
		*phys = uspi->s_sbbase + tmp + blockoff;
L
Linus Torvalds 已提交
339 340 341 342 343 344 345 346 347
		result = NULL;
		*err = 0;
		*new = 1;
	}

	inode->i_ctime = CURRENT_TIME_SEC;
	if (IS_SYNC(inode))
		ufs_sync_inode (inode);
	mark_inode_dirty(inode);
348
	UFSD("EXIT, result %llu\n", (unsigned long long)tmp + blockoff);
L
Linus Torvalds 已提交
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366
	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 已提交
367 368
/**
 * ufs_inode_getblock() - allocate new block
369 370 371
 * @inode: pointer to inode
 * @bh: pointer to block which hold "pointer" to new allocated block
 * @fragment: number of `fragment' which hold pointer
E
Evgeniy Dushistov 已提交
372
 *   to new allocated block
373
 * @new_fragment: number of new allocated fragment
E
Evgeniy Dushistov 已提交
374
 *  (block will hold this fragment and also uspi->s_fpb-1)
375 376 377 378
 * @err: see ufs_inode_getfrag()
 * @phys: see ufs_inode_getfrag()
 * @new: see ufs_inode_getfrag()
 * @locked_page: see ufs_inode_getfrag()
E
Evgeniy Dushistov 已提交
379 380 381
 */
static struct buffer_head *
ufs_inode_getblock(struct inode *inode, struct buffer_head *bh,
382
		  u64 fragment, sector_t new_fragment, int *err,
E
Evgeniy Dushistov 已提交
383
		  long *phys, int *new, struct page *locked_page)
L
Linus Torvalds 已提交
384
{
E
Evgeniy Dushistov 已提交
385 386
	struct super_block *sb = inode->i_sb;
	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
L
Linus Torvalds 已提交
387
	struct buffer_head * result;
388 389 390
	unsigned blockoff;
	u64 tmp, goal, block;
	void *p;
L
Linus Torvalds 已提交
391 392 393 394

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

395 396 397
	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 已提交
398 399 400 401 402 403 404 405 406 407

	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;
	}
408 409 410 411
	if (uspi->fs_magic == UFS2_MAGIC)
		p = (__fs64 *)bh->b_data + block;
	else
		p = (__fs32 *)bh->b_data + block;
L
Linus Torvalds 已提交
412
repeat:
413
	tmp = ufs_data_ptr_to_cpu(sb, p);
L
Linus Torvalds 已提交
414
	if (tmp) {
E
Evgeniy Dushistov 已提交
415
		if (!phys) {
L
Linus Torvalds 已提交
416
			result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
417
			if (tmp == ufs_data_ptr_to_cpu(sb, p))
L
Linus Torvalds 已提交
418 419 420 421
				goto out;
			brelse (result);
			goto repeat;
		} else {
422
			*phys = uspi->s_sbbase + tmp + blockoff;
L
Linus Torvalds 已提交
423 424 425 426
			goto out;
		}
	}

427 428 429
	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 已提交
430 431 432
		goal = tmp + uspi->s_fpb;
	else
		goal = bh->b_blocknr + uspi->s_fpb;
433 434
	tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal,
				uspi->s_fpb, err, locked_page);
L
Linus Torvalds 已提交
435
	if (!tmp) {
436
		if (ufs_data_ptr_to_cpu(sb, p))
L
Linus Torvalds 已提交
437 438
			goto repeat;
		goto out;
A
Al Viro 已提交
439
	}
L
Linus Torvalds 已提交
440

441

E
Evgeniy Dushistov 已提交
442
	if (!phys) {
443
		result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff);
L
Linus Torvalds 已提交
444
	} else {
445
		*phys = uspi->s_sbbase + tmp + blockoff;
L
Linus Torvalds 已提交
446 447 448 449 450 451 452 453
		*new = 1;
	}

	mark_buffer_dirty(bh);
	if (IS_SYNC(inode))
		sync_dirty_buffer(bh);
	inode->i_ctime = CURRENT_TIME_SEC;
	mark_inode_dirty(inode);
454
	UFSD("result %llu\n", (unsigned long long)tmp + blockoff);
L
Linus Torvalds 已提交
455 456
out:
	brelse (bh);
E
Evgeniy Dushistov 已提交
457
	UFSD("EXIT\n");
L
Linus Torvalds 已提交
458 459 460
	return result;
}

E
Evgeniy Dushistov 已提交
461
/**
A
Alessio Igor Bogani 已提交
462
 * ufs_getfrag_block() - `get_block_t' function, interface between UFS and
E
Evgeniy Dushistov 已提交
463
 * readpage, writepage and so on
L
Linus Torvalds 已提交
464 465
 */

A
Al Viro 已提交
466
static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
L
Linus Torvalds 已提交
467 468
{
	struct super_block * sb = inode->i_sb;
A
Arnd Bergmann 已提交
469 470
	struct ufs_sb_info * sbi = UFS_SB(sb);
	struct ufs_sb_private_info * uspi = sbi->s_uspi;
L
Linus Torvalds 已提交
471 472 473 474
	struct buffer_head * bh;
	int ret, err, new;
	unsigned long ptr,phys;
	u64 phys64 = 0;
A
Al Viro 已提交
475

L
Linus Torvalds 已提交
476
	if (!create) {
477
		phys64 = ufs_frag_map(inode, fragment);
A
Andrew Morton 已提交
478
		UFSD("phys64 = %llu\n", (unsigned long long)phys64);
L
Linus Torvalds 已提交
479 480 481 482 483 484 485 486 487 488 489 490
		if (phys64)
			map_bh(bh_result, sb, phys64);
		return 0;
	}

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

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

491
	mutex_lock(&UFS_I(inode)->truncate_mutex);
L
Linus Torvalds 已提交
492

E
Evgeniy Dushistov 已提交
493
	UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment);
L
Linus Torvalds 已提交
494 495 496 497 498 499 500
	if (fragment >
	    ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb)
	     << uspi->s_fpbshift))
		goto abort_too_big;

	err = 0;
	ptr = fragment;
A
Al Viro 已提交
501

L
Linus Torvalds 已提交
502 503 504 505 506
	/*
	 * ok, these macros clean the logic up a bit and make
	 * it much more readable:
	 */
#define GET_INODE_DATABLOCK(x) \
507 508
	ufs_inode_getfrag(inode, x, fragment, 1, &err, &phys, &new,\
			  bh_result->b_page)
L
Linus Torvalds 已提交
509
#define GET_INODE_PTR(x) \
510 511
	ufs_inode_getfrag(inode, x, fragment, uspi->s_fpb, &err, NULL, NULL,\
			  bh_result->b_page)
L
Linus Torvalds 已提交
512
#define GET_INDIRECT_DATABLOCK(x) \
E
Evgeniy Dushistov 已提交
513
	ufs_inode_getblock(inode, bh, x, fragment,	\
514
			  &err, &phys, &new, bh_result->b_page)
L
Linus Torvalds 已提交
515
#define GET_INDIRECT_PTR(x) \
E
Evgeniy Dushistov 已提交
516
	ufs_inode_getblock(inode, bh, x, fragment,	\
517
			  &err, NULL, NULL, NULL)
L
Linus Torvalds 已提交
518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552

	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:
553
	mutex_unlock(&UFS_I(inode)->truncate_mutex);
A
Arnd Bergmann 已提交
554

L
Linus Torvalds 已提交
555 556 557 558 559 560 561 562 563 564 565
	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 已提交
566

L
Linus Torvalds 已提交
567 568 569 570
static int ufs_readpage(struct file *file, struct page *page)
{
	return block_read_full_page(page,ufs_getfrag_block);
}
N
Nick Piggin 已提交
571

572
int ufs_prepare_chunk(struct page *page, loff_t pos, unsigned len)
L
Linus Torvalds 已提交
573
{
574
	return __block_write_begin(page, pos, len, ufs_getfrag_block);
L
Linus Torvalds 已提交
575
}
N
Nick Piggin 已提交
576

A
Al Viro 已提交
577 578
static void ufs_truncate_blocks(struct inode *);

M
Marco Stornelli 已提交
579 580 581 582
static void ufs_write_failed(struct address_space *mapping, loff_t to)
{
	struct inode *inode = mapping->host;

583
	if (to > inode->i_size) {
584
		truncate_pagecache(inode, inode->i_size);
585 586
		ufs_truncate_blocks(inode);
	}
M
Marco Stornelli 已提交
587 588
}

N
Nick Piggin 已提交
589 590 591 592
static int ufs_write_begin(struct file *file, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned flags,
			struct page **pagep, void **fsdata)
{
593 594 595
	int ret;

	ret = block_write_begin(mapping, pos, len, flags, pagep,
596
				ufs_getfrag_block);
M
Marco Stornelli 已提交
597 598
	if (unlikely(ret))
		ufs_write_failed(mapping, pos + len);
599 600

	return ret;
N
Nick Piggin 已提交
601 602
}

603 604 605 606 607 608 609 610 611 612 613 614
static int ufs_write_end(struct file *file, struct address_space *mapping,
			loff_t pos, unsigned len, unsigned copied,
			struct page *page, void *fsdata)
{
	int ret;

	ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
	if (ret < len)
		ufs_write_failed(mapping, pos + len);
	return ret;
}

L
Linus Torvalds 已提交
615 616 617 618
static sector_t ufs_bmap(struct address_space *mapping, sector_t block)
{
	return generic_block_bmap(mapping,block,ufs_getfrag_block);
}
N
Nick Piggin 已提交
619

620
const struct address_space_operations ufs_aops = {
L
Linus Torvalds 已提交
621 622
	.readpage = ufs_readpage,
	.writepage = ufs_writepage,
N
Nick Piggin 已提交
623
	.write_begin = ufs_write_begin,
624
	.write_end = ufs_write_end,
L
Linus Torvalds 已提交
625 626 627
	.bmap = ufs_bmap
};

628 629 630 631 632 633 634 635 636 637 638
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)) {
A
Al Viro 已提交
639
		if (!inode->i_blocks) {
640
			inode->i_op = &ufs_fast_symlink_inode_operations;
A
Al Viro 已提交
641 642
			inode->i_link = (char *)UFS_I(inode)->i_u1.i_symlink;
		} else {
643
			inode->i_op = &ufs_symlink_inode_operations;
644 645 646 647 648 649 650
			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)));
}

651
static int ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode)
L
Linus Torvalds 已提交
652 653
{
	struct ufs_inode_info *ufsi = UFS_I(inode);
654
	struct super_block *sb = inode->i_sb;
A
Al Viro 已提交
655
	umode_t mode;
L
Linus Torvalds 已提交
656 657 658 659 660

	/*
	 * Copy data to the in-core inode.
	 */
	inode->i_mode = mode = fs16_to_cpu(sb, ufs_inode->ui_mode);
M
Miklos Szeredi 已提交
661
	set_nlink(inode, fs16_to_cpu(sb, ufs_inode->ui_nlink));
662
	if (inode->i_nlink == 0) {
L
Linus Torvalds 已提交
663
		ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino);
664 665
		return -1;
	}
A
Al Viro 已提交
666

L
Linus Torvalds 已提交
667 668 669
	/*
	 * Linux now has 32-bit uid and gid, so we can support EFT.
	 */
670 671
	i_uid_write(inode, ufs_get_inode_uid(sb, ufs_inode));
	i_gid_write(inode, ufs_get_inode_gid(sb, ufs_inode));
L
Linus Torvalds 已提交
672 673 674 675 676 677 678 679 680

	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);
681
	inode->i_generation = fs32_to_cpu(sb, ufs_inode->ui_gen);
L
Linus Torvalds 已提交
682 683 684
	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);
685

A
Al Viro 已提交
686

L
Linus Torvalds 已提交
687
	if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) {
688 689
		memcpy(ufsi->i_u1.i_data, &ufs_inode->ui_u2.ui_addr,
		       sizeof(ufs_inode->ui_u2.ui_addr));
690
	} else {
691
		memcpy(ufsi->i_u1.i_symlink, ufs_inode->ui_u2.ui_symlink,
692 693
		       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 已提交
694
	}
695
	return 0;
696
}
L
Linus Torvalds 已提交
697

698
static int ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode)
699 700 701
{
	struct ufs_inode_info *ufsi = UFS_I(inode);
	struct super_block *sb = inode->i_sb;
A
Al Viro 已提交
702
	umode_t mode;
L
Linus Torvalds 已提交
703

E
Evgeniy Dushistov 已提交
704
	UFSD("Reading ufs2 inode, ino %lu\n", inode->i_ino);
L
Linus Torvalds 已提交
705 706 707 708
	/*
	 * Copy data to the in-core inode.
	 */
	inode->i_mode = mode = fs16_to_cpu(sb, ufs2_inode->ui_mode);
M
Miklos Szeredi 已提交
709
	set_nlink(inode, fs16_to_cpu(sb, ufs2_inode->ui_nlink));
710
	if (inode->i_nlink == 0) {
L
Linus Torvalds 已提交
711
		ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink\n", inode->i_ino);
712 713
		return -1;
	}
L
Linus Torvalds 已提交
714 715 716 717

        /*
         * Linux now has 32-bit uid and gid, so we can support EFT.
         */
718 719
	i_uid_write(inode, fs32_to_cpu(sb, ufs2_inode->ui_uid));
	i_gid_write(inode, fs32_to_cpu(sb, ufs2_inode->ui_gid));
L
Linus Torvalds 已提交
720 721

	inode->i_size = fs64_to_cpu(sb, ufs2_inode->ui_size);
722 723 724 725 726 727
	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 已提交
728
	inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks);
729
	inode->i_generation = fs32_to_cpu(sb, ufs2_inode->ui_gen);
L
Linus Torvalds 已提交
730 731 732 733 734 735 736
	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) {
737 738
		memcpy(ufsi->i_u1.u2_i_data, &ufs2_inode->ui_u2.ui_addr,
		       sizeof(ufs2_inode->ui_u2.ui_addr));
739
	} else {
740
		memcpy(ufsi->i_u1.i_symlink, ufs2_inode->ui_u2.ui_symlink,
741 742
		       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 已提交
743
	}
744
	return 0;
745 746
}

747
struct inode *ufs_iget(struct super_block *sb, unsigned long ino)
748
{
749 750
	struct ufs_inode_info *ufsi;
	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
751
	struct buffer_head * bh;
752
	struct inode *inode;
753
	int err;
754

755
	UFSD("ENTER, ino %lu\n", ino);
756

757
	if (ino < UFS_ROOTINO || ino > (uspi->s_ncg * uspi->s_ipg)) {
758
		ufs_warning(sb, "ufs_read_inode", "bad inode number (%lu)\n",
759 760
			    ino);
		return ERR_PTR(-EIO);
761 762
	}

763 764 765 766 767 768 769 770
	inode = iget_locked(sb, ino);
	if (!inode)
		return ERR_PTR(-ENOMEM);
	if (!(inode->i_state & I_NEW))
		return inode;

	ufsi = UFS_I(inode);

771 772 773 774 775 776 777 778 779
	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;

780 781
		err = ufs2_read_inode(inode,
				      ufs2_inode + ufs_inotofsbo(inode->i_ino));
782 783 784
	} else {
		struct ufs_inode *ufs_inode = (struct ufs_inode *)bh->b_data;

785 786
		err = ufs1_read_inode(inode,
				      ufs_inode + ufs_inotofsbo(inode->i_ino));
787 788
	}

789 790
	if (err)
		goto bad_inode;
791 792 793 794
	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 已提交
795 796
	ufsi->i_osync = 0;

797
	ufs_set_inode_ops(inode);
L
Linus Torvalds 已提交
798 799 800

	brelse(bh);

E
Evgeniy Dushistov 已提交
801
	UFSD("EXIT\n");
802 803
	unlock_new_inode(inode);
	return inode;
804 805

bad_inode:
806 807
	iget_failed(inode);
	return ERR_PTR(-EIO);
L
Linus Torvalds 已提交
808 809
}

810
static void ufs1_update_inode(struct inode *inode, struct ufs_inode *ufs_inode)
L
Linus Torvalds 已提交
811
{
812 813
	struct super_block *sb = inode->i_sb;
 	struct ufs_inode_info *ufsi = UFS_I(inode);
L
Linus Torvalds 已提交
814 815 816 817

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

818 819
	ufs_set_inode_uid(sb, ufs_inode, i_uid_read(inode));
	ufs_set_inode_gid(sb, ufs_inode, i_gid_read(inode));
A
Al Viro 已提交
820

L
Linus Torvalds 已提交
821 822 823 824 825 826 827 828 829
	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);
830
	ufs_inode->ui_gen = cpu_to_fs32(sb, inode->i_generation);
L
Linus Torvalds 已提交
831

832
	if ((UFS_SB(sb)->s_flags & UFS_UID_MASK) == UFS_UID_EFT) {
L
Linus Torvalds 已提交
833 834 835 836 837 838 839 840
		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) {
841 842
		memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.i_data,
		       sizeof(ufs_inode->ui_u2.ui_addr));
L
Linus Torvalds 已提交
843 844
	}
	else {
845 846
		memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink,
		       sizeof(ufs_inode->ui_u2.ui_symlink));
L
Linus Torvalds 已提交
847 848 849 850
	}

	if (!inode->i_nlink)
		memset (ufs_inode, 0, sizeof(struct ufs_inode));
851 852 853 854 855 856 857 858 859 860 861
}

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);

862 863
	ufs_inode->ui_uid = cpu_to_fs32(sb, i_uid_read(inode));
	ufs_inode->ui_gid = cpu_to_fs32(sb, i_gid_read(inode));
864 865

	ufs_inode->ui_size = cpu_to_fs64(sb, inode->i_size);
866 867 868 869 870 871
	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);
872 873 874 875 876 877 878 879 880

	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) {
881 882
		memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.u2_i_data,
		       sizeof(ufs_inode->ui_u2.ui_addr));
883
	} else {
884 885
		memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink,
		       sizeof(ufs_inode->ui_u2.ui_symlink));
886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921
 	}

	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));
	}
A
Al Viro 已提交
922

L
Linus Torvalds 已提交
923 924 925 926
	mark_buffer_dirty(bh);
	if (do_sync)
		sync_dirty_buffer(bh);
	brelse (bh);
A
Al Viro 已提交
927

E
Evgeniy Dushistov 已提交
928
	UFSD("EXIT\n");
L
Linus Torvalds 已提交
929 930 931
	return 0;
}

932
int ufs_write_inode(struct inode *inode, struct writeback_control *wbc)
L
Linus Torvalds 已提交
933
{
A
Al Viro 已提交
934
	return ufs_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
L
Linus Torvalds 已提交
935 936 937 938 939 940 941
}

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

A
Al Viro 已提交
942
void ufs_evict_inode(struct inode * inode)
L
Linus Torvalds 已提交
943
{
A
Al Viro 已提交
944 945 946 947
	int want_delete = 0;

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

949
	truncate_inode_pages_final(&inode->i_data);
A
Al Viro 已提交
950 951
	if (want_delete) {
		inode->i_size = 0;
952 953
		if (inode->i_blocks)
			ufs_truncate_blocks(inode);
A
Al Viro 已提交
954 955 956
	}

	invalidate_inode_buffers(inode);
957
	clear_inode(inode);
A
Al Viro 已提交
958

A
Al Viro 已提交
959
	if (want_delete)
960
		ufs_free_inode(inode);
L
Linus Torvalds 已提交
961
}
A
Al Viro 已提交
962

963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978
struct to_free {
	struct inode *inode;
	u64 to;
	unsigned count;
};

static inline void free_data(struct to_free *ctx, u64 from, unsigned count)
{
	if (ctx->count && ctx->to != from) {
		ufs_free_blocks(ctx->inode, ctx->to - ctx->count, ctx->count);
		ctx->count = 0;
	}
	ctx->count += count;
	ctx->to = from + count;
}

A
Al Viro 已提交
979 980 981 982 983 984 985 986 987 988
#define DIRECT_BLOCK ((inode->i_size + uspi->s_bsize - 1) >> uspi->s_bshift)
#define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift)

static void ufs_trunc_direct(struct inode *inode)
{
	struct ufs_inode_info *ufsi = UFS_I(inode);
	struct super_block * sb;
	struct ufs_sb_private_info * uspi;
	void *p;
	u64 frag1, frag2, frag3, frag4, block1, block2;
989
	struct to_free ctx = {.inode = inode};
A
Al Viro 已提交
990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
	unsigned i, tmp;

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

	sb = inode->i_sb;
	uspi = UFS_SB(sb)->s_uspi;

	frag1 = DIRECT_FRAGMENT;
	frag4 = min_t(u64, UFS_NDIR_FRAGMENT, ufsi->i_lastfrag);
	frag2 = ((frag1 & uspi->s_fpbmask) ? ((frag1 | uspi->s_fpbmask) + 1) : frag1);
	frag3 = frag4 & ~uspi->s_fpbmask;
	block1 = block2 = 0;
	if (frag2 > frag3) {
		frag2 = frag4;
		frag3 = frag4 = 0;
	} else if (frag2 < frag3) {
		block1 = ufs_fragstoblks (frag2);
		block2 = ufs_fragstoblks (frag3);
	}

	UFSD("ino %lu, frag1 %llu, frag2 %llu, block1 %llu, block2 %llu,"
	     " frag3 %llu, frag4 %llu\n", inode->i_ino,
	     (unsigned long long)frag1, (unsigned long long)frag2,
	     (unsigned long long)block1, (unsigned long long)block2,
	     (unsigned long long)frag3, (unsigned long long)frag4);

	if (frag1 >= frag2)
		goto next1;

	/*
	 * Free first free fragments
	 */
	p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag1));
	tmp = ufs_data_ptr_to_cpu(sb, p);
	if (!tmp )
		ufs_panic (sb, "ufs_trunc_direct", "internal error");
	frag2 -= frag1;
	frag1 = ufs_fragnum (frag1);

	ufs_free_fragments(inode, tmp + frag1, frag2);

next1:
	/*
	 * Free whole blocks
	 */
	for (i = block1 ; i < block2; i++) {
		p = ufs_get_direct_data_ptr(uspi, ufsi, i);
		tmp = ufs_data_ptr_to_cpu(sb, p);
		if (!tmp)
			continue;
		write_seqlock(&ufsi->meta_lock);
		ufs_data_ptr_clear(uspi, p);
		write_sequnlock(&ufsi->meta_lock);

1044
		free_data(&ctx, tmp, uspi->s_fpb);
A
Al Viro 已提交
1045 1046
	}

1047
	free_data(&ctx, 0, 0);
A
Al Viro 已提交
1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069

	if (frag3 >= frag4)
		goto next3;

	/*
	 * Free last free fragments
	 */
	p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag3));
	tmp = ufs_data_ptr_to_cpu(sb, p);
	if (!tmp )
		ufs_panic(sb, "ufs_truncate_direct", "internal error");
	frag4 = ufs_fragnum (frag4);
	write_seqlock(&ufsi->meta_lock);
	ufs_data_ptr_clear(uspi, p);
	write_sequnlock(&ufsi->meta_lock);

	ufs_free_fragments (inode, tmp, frag4);
 next3:

	UFSD("EXIT: ino %lu\n", inode->i_ino);
}

1070
static void free_full_branch(struct inode *inode, u64 ind_block, int depth)
1071 1072 1073
{
	struct super_block *sb = inode->i_sb;
	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
1074
	struct ufs_buffer_head *ubh = ubh_bread(sb, ind_block, uspi->s_bsize);
1075 1076
	unsigned i;

1077
	if (!ubh)
1078 1079 1080
		return;

	if (--depth) {
1081 1082 1083
		for (i = 0; i < uspi->s_apb; i++) {
			void *p = ubh_get_data_ptr(uspi, ubh, i);
			u64 block = ufs_data_ptr_to_cpu(sb, p);
1084
			if (block)
1085
				free_full_branch(inode, block, depth);
1086 1087 1088 1089 1090
		}
	} else {
		struct to_free ctx = {.inode = inode};

		for (i = 0; i < uspi->s_apb; i++) {
1091 1092
			void *p = ubh_get_data_ptr(uspi, ubh, i);
			u64 block = ufs_data_ptr_to_cpu(sb, p);
1093
			if (block)
1094
				free_data(&ctx, block, uspi->s_fpb);
1095 1096 1097 1098 1099
		}
		free_data(&ctx, 0, 0);
	}

	ubh_bforget(ubh);
1100
	ufs_free_blocks(inode, ind_block, uspi->s_fpb);
1101 1102
}

A
Al Viro 已提交
1103
static void free_branch_tail(struct inode *inode, unsigned from, struct ufs_buffer_head *ubh, int depth)
A
Al Viro 已提交
1104
{
1105 1106 1107
	struct super_block *sb = inode->i_sb;
	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
	unsigned i;
A
Al Viro 已提交
1108

A
Al Viro 已提交
1109
	if (--depth) {
A
Al Viro 已提交
1110
		for (i = from; i < uspi->s_apb ; i++) {
1111 1112 1113 1114 1115 1116 1117 1118 1119
			void *p = ubh_get_data_ptr(uspi, ubh, i);
			u64 block = ufs_data_ptr_to_cpu(sb, p);
			if (block) {
				write_seqlock(&UFS_I(inode)->meta_lock);
				ufs_data_ptr_clear(uspi, p);
				write_sequnlock(&UFS_I(inode)->meta_lock);
				ubh_mark_buffer_dirty(ubh);
				free_full_branch(inode, block, depth);
			}
1120
		}
A
Al Viro 已提交
1121
	} else {
1122
		struct to_free ctx = {.inode = inode};
A
Al Viro 已提交
1123 1124

		for (i = from; i < uspi->s_apb; i++) {
1125 1126 1127 1128 1129 1130 1131 1132 1133
			void *p = ubh_get_data_ptr(uspi, ubh, i);
			u64 block = ufs_data_ptr_to_cpu(sb, p);
			if (block) {
				write_seqlock(&UFS_I(inode)->meta_lock);
				ufs_data_ptr_clear(uspi, p);
				write_sequnlock(&UFS_I(inode)->meta_lock);
				ubh_mark_buffer_dirty(ubh);
				free_data(&ctx, block, uspi->s_fpb);
			}
A
Al Viro 已提交
1134
		}
1135
		free_data(&ctx, 0, 0);
A
Al Viro 已提交
1136
	}
A
Al Viro 已提交
1137 1138 1139
	if (IS_SYNC(inode) && ubh_buffer_dirty(ubh))
		ubh_sync_block(ubh);
	ubh_brelse(ubh);
A
Al Viro 已提交
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216
}

static int ufs_alloc_lastblock(struct inode *inode, loff_t size)
{
	int err = 0;
	struct super_block *sb = inode->i_sb;
	struct address_space *mapping = inode->i_mapping;
	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
	unsigned i, end;
	sector_t lastfrag;
	struct page *lastpage;
	struct buffer_head *bh;
	u64 phys64;

	lastfrag = (size + uspi->s_fsize - 1) >> uspi->s_fshift;

	if (!lastfrag)
		goto out;

	lastfrag--;

	lastpage = ufs_get_locked_page(mapping, lastfrag >>
				       (PAGE_CACHE_SHIFT - inode->i_blkbits));
       if (IS_ERR(lastpage)) {
               err = -EIO;
               goto out;
       }

       end = lastfrag & ((1 << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - 1);
       bh = page_buffers(lastpage);
       for (i = 0; i < end; ++i)
               bh = bh->b_this_page;


       err = ufs_getfrag_block(inode, lastfrag, bh, 1);

       if (unlikely(err))
	       goto out_unlock;

       if (buffer_new(bh)) {
	       clear_buffer_new(bh);
	       unmap_underlying_metadata(bh->b_bdev,
					 bh->b_blocknr);
	       /*
		* we do not zeroize fragment, because of
		* if it maped to hole, it already contains zeroes
		*/
	       set_buffer_uptodate(bh);
	       mark_buffer_dirty(bh);
	       set_page_dirty(lastpage);
       }

       if (lastfrag >= UFS_IND_FRAGMENT) {
	       end = uspi->s_fpb - ufs_fragnum(lastfrag) - 1;
	       phys64 = bh->b_blocknr + 1;
	       for (i = 0; i < end; ++i) {
		       bh = sb_getblk(sb, i + phys64);
		       lock_buffer(bh);
		       memset(bh->b_data, 0, sb->s_blocksize);
		       set_buffer_uptodate(bh);
		       mark_buffer_dirty(bh);
		       unlock_buffer(bh);
		       sync_dirty_buffer(bh);
		       brelse(bh);
	       }
       }
out_unlock:
       ufs_put_locked_page(lastpage);
out:
       return err;
}

static void __ufs_truncate_blocks(struct inode *inode)
{
	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;
1217
	unsigned offsets[4];
1218
	int depth = ufs_block_to_path(inode, DIRECT_BLOCK, offsets);
1219
	int depth2;
1220
	unsigned i;
A
Al Viro 已提交
1221 1222 1223
	struct ufs_buffer_head *ubh[3];
	void *p;
	u64 block;
1224 1225 1226 1227 1228 1229 1230 1231

	if (!depth)
		return;

	/* find the last non-zero in offsets[] */
	for (depth2 = depth - 1; depth2; depth2--)
		if (offsets[depth2])
			break;
A
Al Viro 已提交
1232 1233

	mutex_lock(&ufsi->truncate_mutex);
1234
	if (depth == 1) {
1235
		ufs_trunc_direct(inode);
1236 1237
		offsets[0] = UFS_IND_BLOCK;
	} else {
A
Al Viro 已提交
1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
		/* get the blocks that should be partially emptied */
		p = ufs_get_direct_data_ptr(uspi, ufsi, offsets[0]);
		for (i = 0; i < depth2; i++) {
			offsets[i]++;	/* next branch is fully freed */
			block = ufs_data_ptr_to_cpu(sb, p);
			if (!block)
				break;
			ubh[i] = ubh_bread(sb, block, uspi->s_bsize);
			if (!ubh[i]) {
				write_seqlock(&ufsi->meta_lock);
				ufs_data_ptr_clear(uspi, p);
				write_sequnlock(&ufsi->meta_lock);
				break;
			}
			p = ubh_get_data_ptr(uspi, ubh[i], offsets[i + 1]);
		}
1254
		while (i--)
A
Al Viro 已提交
1255
			free_branch_tail(inode, offsets[i + 1], ubh[i], depth - i - 1);
1256 1257
	}
	for (i = offsets[0]; i <= UFS_TIND_BLOCK; i++) {
1258 1259 1260 1261 1262 1263 1264 1265
		p = ufs_get_direct_data_ptr(uspi, ufsi, i);
		block = ufs_data_ptr_to_cpu(sb, p);
		if (block) {
			write_seqlock(&ufsi->meta_lock);
			ufs_data_ptr_clear(uspi, p);
			write_sequnlock(&ufsi->meta_lock);
			free_full_branch(inode, block, i - UFS_IND_BLOCK + 1);
		}
1266
	}
A
Al Viro 已提交
1267
	ufsi->i_lastfrag = DIRECT_FRAGMENT;
1268
	mark_inode_dirty(inode);
A
Al Viro 已提交
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336
	mutex_unlock(&ufsi->truncate_mutex);
}

static int ufs_truncate(struct inode *inode, loff_t size)
{
	int err = 0;

	UFSD("ENTER: ino %lu, i_size: %llu, old_i_size: %llu\n",
	     inode->i_ino, (unsigned long long)size,
	     (unsigned long long)i_size_read(inode));

	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
	      S_ISLNK(inode->i_mode)))
		return -EINVAL;
	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
		return -EPERM;

	err = ufs_alloc_lastblock(inode, size);

	if (err)
		goto out;

	block_truncate_page(inode->i_mapping, size, ufs_getfrag_block);

	truncate_setsize(inode, size);

	__ufs_truncate_blocks(inode);
	inode->i_mtime = inode->i_ctime = CURRENT_TIME_SEC;
	mark_inode_dirty(inode);
out:
	UFSD("EXIT: err %d\n", err);
	return err;
}

void ufs_truncate_blocks(struct inode *inode)
{
	if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
	      S_ISLNK(inode->i_mode)))
		return;
	if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
		return;
	__ufs_truncate_blocks(inode);
}

int ufs_setattr(struct dentry *dentry, struct iattr *attr)
{
	struct inode *inode = d_inode(dentry);
	unsigned int ia_valid = attr->ia_valid;
	int error;

	error = inode_change_ok(inode, attr);
	if (error)
		return error;

	if (ia_valid & ATTR_SIZE && attr->ia_size != inode->i_size) {
		error = ufs_truncate(inode, attr->ia_size);
		if (error)
			return error;
	}

	setattr_copy(inode, attr);
	mark_inode_dirty(inode);
	return 0;
}

const struct inode_operations ufs_file_inode_operations = {
	.setattr = ufs_setattr,
};