Blame view

fs/ufs/inode.c 32.6 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
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
  /*
   *  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>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
  
  #include <linux/errno.h>
  #include <linux/fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
  #include <linux/time.h>
  #include <linux/stat.h>
  #include <linux/string.h>
  #include <linux/mm.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
  #include <linux/buffer_head.h>
a9185b41a   Christoph Hellwig   pass writeback_co...
37
  #include <linux/writeback.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38

e54205988   Mike Frysinger   drop linux/ufs_fs...
39
  #include "ufs_fs.h"
bcd6d4ecf   Christoph Hellwig   ufs: move non-lay...
40
  #include "ufs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
  #include "swab.h"
  #include "util.h"
4e3911f3d   Al Viro   ufs: the offsets ...
43
  static int ufs_block_to_path(struct inode *inode, sector_t i_block, unsigned offsets[4])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
48
49
50
51
  {
  	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;
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
52
53
  	UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld 
  ",ptrs,double_blocks);
37044c86b   Roel Kluin   ufs: sector_t can...
54
  	if (i_block < direct_blocks) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
  		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;
  }
724bb09fd   Al Viro   ufs: don't use lo...
73
74
75
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
  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);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
113
114
  /*
   * Returns the location of the fragment from
25985edce   Lucas De Marchi   Fix common misspe...
115
   * the beginning of the filesystem.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116
   */
4b7068c8b   Al Viro   ufs: move calcula...
117
  static u64 ufs_frag_map(struct inode *inode, unsigned offsets[4], int depth)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
120
121
122
123
  {
  	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;
724bb09fd   Al Viro   ufs: don't use lo...
124
  	Indirect chain[4], *q = chain;
4b7068c8b   Al Viro   ufs: move calcula...
125
  	unsigned *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
  	unsigned flags = UFS_SB(sb)->s_flags;
724bb09fd   Al Viro   ufs: don't use lo...
127
  	u64 res = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
128

7256d819e   Andrew Morton   [PATCH] ufs: prin...
129
130
131
132
  	UFSD(": uspi->s_fpbshift = %d ,uspi->s_apbmask = %x, mask=%llx
  ",
  		uspi->s_fpbshift, uspi->s_apbmask,
  		(unsigned long long)mask);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
133
134
  
  	if (depth == 0)
724bb09fd   Al Viro   ufs: don't use lo...
135
  		goto no_block;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136

724bb09fd   Al Viro   ufs: don't use lo...
137
  again:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
  	p = offsets;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
139
140
  	if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
  		goto ufs2;
724bb09fd   Al Viro   ufs: don't use lo...
141
142
143
144
  	if (!grow_chain32(ufsi, NULL, &ufsi->i_u1.i_data[*p++], chain, q))
  		goto changed;
  	if (!q->key32)
  		goto no_block;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
  	while (--depth) {
724bb09fd   Al Viro   ufs: don't use lo...
146
  		__fs32 *ptr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
147
  		struct buffer_head *bh;
4e3911f3d   Al Viro   ufs: the offsets ...
148
  		unsigned n = *p++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149

724bb09fd   Al Viro   ufs: don't use lo...
150
151
  		bh = sb_bread(sb, uspi->s_sbbase +
  				  fs32_to_cpu(sb, q->key32) + (n>>shift));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
  		if (!bh)
724bb09fd   Al Viro   ufs: don't use lo...
153
154
155
156
157
158
  			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;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
  	}
724bb09fd   Al Viro   ufs: don't use lo...
160
161
  	res = fs32_to_cpu(sb, q->key32);
  	goto found;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
162

724bb09fd   Al Viro   ufs: don't use lo...
163
164
165
166
167
  ufs2:
  	if (!grow_chain64(ufsi, NULL, &ufsi->i_u1.u2_i_data[*p++], chain, q))
  		goto changed;
  	if (!q->key64)
  		goto no_block;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
  
  	while (--depth) {
724bb09fd   Al Viro   ufs: don't use lo...
170
  		__fs64 *ptr;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  		struct buffer_head *bh;
4e3911f3d   Al Viro   ufs: the offsets ...
172
  		unsigned n = *p++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173

724bb09fd   Al Viro   ufs: don't use lo...
174
175
  		bh = sb_bread(sb, uspi->s_sbbase +
  				  fs64_to_cpu(sb, q->key64) + (n>>shift));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
176
  		if (!bh)
724bb09fd   Al Viro   ufs: don't use lo...
177
178
179
180
181
182
183
184
185
  			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:
4b7068c8b   Al Viro   ufs: move calcula...
186
  	res += uspi->s_sbbase;
724bb09fd   Al Viro   ufs: don't use lo...
187
188
189
190
  no_block:
  	while (q > chain) {
  		brelse(q->bh);
  		q--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
191
  	}
724bb09fd   Al Viro   ufs: don't use lo...
192
  	return res;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193

724bb09fd   Al Viro   ufs: don't use lo...
194
195
196
197
198
199
  changed:
  	while (q > chain) {
  		brelse(q->bh);
  		q--;
  	}
  	goto again;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
200
  }
0f3c1294b   Al Viro   ufs_inode_getfrag...
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
  /*
   * Unpacking tails: we have a file with partial final block and
   * we had been asked to extend it.  If the fragment being written
   * is within the same block, we need to extend the tail just to cover
   * that fragment.  Otherwise the tail is extended to full block.
   *
   * Note that we might need to create a _new_ tail, but that will
   * be handled elsewhere; this is strictly for resizing old
   * ones.
   */
  static bool
  ufs_extend_tail(struct inode *inode, u64 writes_to,
  		  int *err, struct page *locked_page)
  {
  	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;
  	unsigned lastfrag = ufsi->i_lastfrag;	/* it's a short file, so unsigned is enough */
  	unsigned block = ufs_fragstoblks(lastfrag);
  	unsigned new_size;
  	void *p;
  	u64 tmp;
  
  	if (writes_to < (lastfrag | uspi->s_fpbmask))
  		new_size = (writes_to & uspi->s_fpbmask) + 1;
  	else
  		new_size = uspi->s_fpb;
  
  	p = ufs_get_direct_data_ptr(uspi, ufsi, block);
  	tmp = ufs_new_fragments(inode, p, lastfrag, ufs_data_ptr_to_cpu(sb, p),
  				new_size, err, locked_page);
  	return tmp != 0;
  }
022a6dc5f   Evgeniy Dushistov   [PATCH] ufs: zero...
234
235
  /**
   * ufs_inode_getfrag() - allocate new fragment(s)
edc023caf   Fabian Frederick   fs/ufs/inode.c: k...
236
   * @inode: pointer to inode
5336970be   Al Viro   ufs_inode_getfrag...
237
   * @index: number of block pointer within the inode's array.
edc023caf   Fabian Frederick   fs/ufs/inode.c: k...
238
   * @new_fragment: number of new allocated fragment(s)
edc023caf   Fabian Frederick   fs/ufs/inode.c: k...
239
   * @err: we set it if something wrong
edc023caf   Fabian Frederick   fs/ufs/inode.c: k...
240
241
   * @new: we set it if we allocate new block
   * @locked_page: for ufs_new_fragments()
022a6dc5f   Evgeniy Dushistov   [PATCH] ufs: zero...
242
   */
177848a01   Al Viro   ufs_inode_get{fra...
243
  static u64
5336970be   Al Viro   ufs_inode_getfrag...
244
245
  ufs_inode_getfrag(struct inode *inode, unsigned index,
  		  sector_t new_fragment, int *err,
4e317ce73   Al Viro   ufs_inode_get{fra...
246
  		  int *new, struct page *locked_page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
  {
  	struct ufs_inode_info *ufsi = UFS_I(inode);
022a6dc5f   Evgeniy Dushistov   [PATCH] ufs: zero...
249
250
  	struct super_block *sb = inode->i_sb;
  	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
5336970be   Al Viro   ufs_inode_getfrag...
251
  	u64 tmp, goal, lastfrag;
0f3c1294b   Al Viro   ufs_inode_getfrag...
252
253
  	unsigned nfrags = uspi->s_fpb;
  	void *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
256
257
258
          /* TODO : to be done for write support
          if ( (flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2)
               goto ufs2;
           */
5336970be   Al Viro   ufs_inode_getfrag...
259
  	p = ufs_get_direct_data_ptr(uspi, ufsi, index);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
260
  	tmp = ufs_data_ptr_to_cpu(sb, p);
0f3c1294b   Al Viro   ufs_inode_getfrag...
261
262
  	if (tmp)
  		goto out;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
263

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
264
  	lastfrag = ufsi->i_lastfrag;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
265

0f3c1294b   Al Viro   ufs_inode_getfrag...
266
267
268
269
270
  	/* will that be a new tail? */
  	if (new_fragment < UFS_NDIR_FRAGMENT && new_fragment >= lastfrag)
  		nfrags = (new_fragment & uspi->s_fpbmask) + 1;
  
  	goal = 0;
5336970be   Al Viro   ufs_inode_getfrag...
271
  	if (index) {
0f3c1294b   Al Viro   ufs_inode_getfrag...
272
  		goal = ufs_data_ptr_to_cpu(sb,
5336970be   Al Viro   ufs_inode_getfrag...
273
  				 ufs_get_direct_data_ptr(uspi, ufsi, index - 1));
0f3c1294b   Al Viro   ufs_inode_getfrag...
274
275
  		if (goal)
  			goal += uspi->s_fpb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  	}
5336970be   Al Viro   ufs_inode_getfrag...
277
  	tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment),
4e317ce73   Al Viro   ufs_inode_get{fra...
278
  				goal, uspi->s_fpb, err, locked_page);
0f3c1294b   Al Viro   ufs_inode_getfrag...
279

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
280
  	if (!tmp) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
  		*err = -ENOSPC;
177848a01   Al Viro   ufs_inode_get{fra...
282
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
283
  	}
4e317ce73   Al Viro   ufs_inode_get{fra...
284
  	if (new)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  		*new = 1;
02027d42c   Deepa Dinamani   fs: Replace CURRE...
286
  	inode->i_ctime = current_time(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
289
  	if (IS_SYNC(inode))
  		ufs_sync_inode (inode);
  	mark_inode_dirty(inode);
bbb3eb9d3   Al Viro   ufs_inode_get{fra...
290
  out:
177848a01   Al Viro   ufs_inode_get{fra...
291
  	return tmp + uspi->s_sbbase;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
  
       /* 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;
  
       */
  }
022a6dc5f   Evgeniy Dushistov   [PATCH] ufs: zero...
308
309
  /**
   * ufs_inode_getblock() - allocate new block
edc023caf   Fabian Frederick   fs/ufs/inode.c: k...
310
   * @inode: pointer to inode
619cfac09   Al Viro   ufs_inode_getbloc...
311
312
   * @ind_block: block number of the indirect block
   * @index: number of pointer within the indirect block
edc023caf   Fabian Frederick   fs/ufs/inode.c: k...
313
   * @new_fragment: number of new allocated fragment
022a6dc5f   Evgeniy Dushistov   [PATCH] ufs: zero...
314
   *  (block will hold this fragment and also uspi->s_fpb-1)
edc023caf   Fabian Frederick   fs/ufs/inode.c: k...
315
   * @err: see ufs_inode_getfrag()
edc023caf   Fabian Frederick   fs/ufs/inode.c: k...
316
317
   * @new: see ufs_inode_getfrag()
   * @locked_page: see ufs_inode_getfrag()
022a6dc5f   Evgeniy Dushistov   [PATCH] ufs: zero...
318
   */
177848a01   Al Viro   ufs_inode_get{fra...
319
  static u64
619cfac09   Al Viro   ufs_inode_getbloc...
320
  ufs_inode_getblock(struct inode *inode, u64 ind_block,
721435a76   Al Viro   ufs_inode_getbloc...
321
  		  unsigned index, sector_t new_fragment, int *err,
4e317ce73   Al Viro   ufs_inode_get{fra...
322
  		  int *new, struct page *locked_page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
323
  {
022a6dc5f   Evgeniy Dushistov   [PATCH] ufs: zero...
324
325
  	struct super_block *sb = inode->i_sb;
  	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
619cfac09   Al Viro   ufs_inode_getbloc...
326
  	int shift = uspi->s_apbshift - uspi->s_fpbshift;
721435a76   Al Viro   ufs_inode_getbloc...
327
  	u64 tmp = 0, goal;
619cfac09   Al Viro   ufs_inode_getbloc...
328
  	struct buffer_head *bh;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
329
  	void *p;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
330

619cfac09   Al Viro   ufs_inode_getbloc...
331
332
333
334
  	if (!ind_block)
  		return 0;
  
  	bh = sb_bread(sb, ind_block + (index >> shift));
5fbfb238f   Al Viro   ufs_inode_getbloc...
335
336
  	if (unlikely(!bh)) {
  		*err = -EIO;
619cfac09   Al Viro   ufs_inode_getbloc...
337
  		return 0;
5fbfb238f   Al Viro   ufs_inode_getbloc...
338
  	}
619cfac09   Al Viro   ufs_inode_getbloc...
339
340
  
  	index &= uspi->s_apbmask >> uspi->s_fpbshift;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
341
  	if (uspi->fs_magic == UFS2_MAGIC)
721435a76   Al Viro   ufs_inode_getbloc...
342
  		p = (__fs64 *)bh->b_data + index;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
343
  	else
721435a76   Al Viro   ufs_inode_getbloc...
344
  		p = (__fs32 *)bh->b_data + index;
5a39c2556   Al Viro   ufs_inode_get{fra...
345

54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
346
  	tmp = ufs_data_ptr_to_cpu(sb, p);
bbb3eb9d3   Al Viro   ufs_inode_get{fra...
347
  	if (tmp)
5a39c2556   Al Viro   ufs_inode_get{fra...
348
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
349

721435a76   Al Viro   ufs_inode_getbloc...
350
351
352
  	if (index && (uspi->fs_magic == UFS2_MAGIC ?
  		      (tmp = fs64_to_cpu(sb, ((__fs64 *)bh->b_data)[index-1])) :
  		      (tmp = fs32_to_cpu(sb, ((__fs32 *)bh->b_data)[index-1]))))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
  		goal = tmp + uspi->s_fpb;
  	else
  		goal = bh->b_blocknr + uspi->s_fpb;
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
356
357
  	tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal,
  				uspi->s_fpb, err, locked_page);
5a39c2556   Al Viro   ufs_inode_get{fra...
358
  	if (!tmp)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
359
  		goto out;
c9a27b5dc   Evgeniy Dushistov   [PATCH] ufs: righ...
360

bbb3eb9d3   Al Viro   ufs_inode_get{fra...
361
  	if (new)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
  		*new = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
364
365
366
  
  	mark_buffer_dirty(bh);
  	if (IS_SYNC(inode))
  		sync_dirty_buffer(bh);
02027d42c   Deepa Dinamani   fs: Replace CURRE...
367
  	inode->i_ctime = current_time(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
368
369
370
  	mark_inode_dirty(inode);
  out:
  	brelse (bh);
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
371
372
  	UFSD("EXIT
  ");
177848a01   Al Viro   ufs_inode_get{fra...
373
374
375
  	if (tmp)
  		tmp += uspi->s_sbbase;
  	return tmp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
376
  }
022a6dc5f   Evgeniy Dushistov   [PATCH] ufs: zero...
377
  /**
7422caa5a   Alessio Igor Bogani   ufs: Fix a typo
378
   * ufs_getfrag_block() - `get_block_t' function, interface between UFS and
022a6dc5f   Evgeniy Dushistov   [PATCH] ufs: zero...
379
   * readpage, writepage and so on
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
380
   */
010d331fc   Al Viro   ufs: move truncat...
381
  static int ufs_getfrag_block(struct inode *inode, sector_t fragment, struct buffer_head *bh_result, int create)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
  {
0385f1f9e   Al Viro   ufs_getfrag_block...
383
384
385
  	struct super_block *sb = inode->i_sb;
  	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
  	int err = 0, new = 0;
4b7068c8b   Al Viro   ufs: move calcula...
386
387
  	unsigned offsets[4];
  	int depth = ufs_block_to_path(inode, fragment >> uspi->s_fpbshift, offsets);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
388
  	u64 phys64 = 0;
177848a01   Al Viro   ufs_inode_get{fra...
389
  	unsigned frag = fragment & uspi->s_fpbmask;
010d331fc   Al Viro   ufs: move truncat...
390

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
  	if (!create) {
4b7068c8b   Al Viro   ufs: move calcula...
392
  		phys64 = ufs_frag_map(inode, offsets, depth);
0385f1f9e   Al Viro   ufs_getfrag_block...
393
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
394
395
396
  	}
  
          /* This code entered only while writing ....? */
724bb09fd   Al Viro   ufs: don't use lo...
397
  	mutex_lock(&UFS_I(inode)->truncate_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
398

abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
399
400
  	UFSD("ENTER, ino %lu, fragment %llu
  ", inode->i_ino, (unsigned long long)fragment);
0385f1f9e   Al Viro   ufs_getfrag_block...
401
402
403
404
405
  	if (unlikely(!depth)) {
  		ufs_warning(sb, "ufs_get_block", "block > big");
  		err = -EIO;
  		goto out;
  	}
0f3c1294b   Al Viro   ufs_inode_getfrag...
406
407
408
409
410
411
412
  
  	if (UFS_I(inode)->i_lastfrag < UFS_NDIR_FRAGMENT) {
  		unsigned lastfrag = UFS_I(inode)->i_lastfrag;
  		unsigned tailfrags = lastfrag & uspi->s_fpbmask;
  		if (tailfrags && fragment >= lastfrag) {
  			if (!ufs_extend_tail(inode, fragment,
  					     &err, bh_result->b_page))
0385f1f9e   Al Viro   ufs_getfrag_block...
413
  				goto out;
0f3c1294b   Al Viro   ufs_inode_getfrag...
414
415
  		}
  	}
71dd42846   Al Viro   ufs: use the bran...
416
  	if (depth == 1) {
5336970be   Al Viro   ufs_inode_getfrag...
417
  		phys64 = ufs_inode_getfrag(inode, offsets[0], fragment,
4e317ce73   Al Viro   ufs_inode_get{fra...
418
  					   &err, &new, bh_result->b_page);
4eeff4c93   Al Viro   ufs_getfrag_block...
419
420
  	} else {
  		int i;
5336970be   Al Viro   ufs_inode_getfrag...
421
  		phys64 = ufs_inode_getfrag(inode, offsets[0], fragment,
4e317ce73   Al Viro   ufs_inode_get{fra...
422
  					   &err, NULL, NULL);
4eeff4c93   Al Viro   ufs_getfrag_block...
423
424
  		for (i = 1; i < depth - 1; i++)
  			phys64 = ufs_inode_getblock(inode, phys64, offsets[i],
4e317ce73   Al Viro   ufs_inode_get{fra...
425
  						fragment, &err, NULL, NULL);
4eeff4c93   Al Viro   ufs_getfrag_block...
426
  		phys64 = ufs_inode_getblock(inode, phys64, offsets[depth - 1],
4e317ce73   Al Viro   ufs_inode_get{fra...
427
  					fragment, &err, &new, bh_result->b_page);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  	}
0385f1f9e   Al Viro   ufs_getfrag_block...
429
  out:
177848a01   Al Viro   ufs_inode_get{fra...
430
431
  	if (phys64) {
  		phys64 += frag;
0385f1f9e   Al Viro   ufs_getfrag_block...
432
433
434
  		map_bh(bh_result, sb, phys64);
  		if (new)
  			set_buffer_new(bh_result);
177848a01   Al Viro   ufs_inode_get{fra...
435
  	}
724bb09fd   Al Viro   ufs: don't use lo...
436
  	mutex_unlock(&UFS_I(inode)->truncate_mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
  	return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
438
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
439
440
441
442
  static int ufs_writepage(struct page *page, struct writeback_control *wbc)
  {
  	return block_write_full_page(page,ufs_getfrag_block,wbc);
  }
82b9d1d0d   Nick Piggin   ufs: convert to n...
443

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
444
445
446
447
  static int ufs_readpage(struct file *file, struct page *page)
  {
  	return block_read_full_page(page,ufs_getfrag_block);
  }
82b9d1d0d   Nick Piggin   ufs: convert to n...
448

f4e420dc4   Christoph Hellwig   clean up write_be...
449
  int ufs_prepare_chunk(struct page *page, loff_t pos, unsigned len)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
  {
6e1db88d5   Christoph Hellwig   introduce __block...
451
  	return __block_write_begin(page, pos, len, ufs_getfrag_block);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
452
  }
82b9d1d0d   Nick Piggin   ufs: convert to n...
453

010d331fc   Al Viro   ufs: move truncat...
454
  static void ufs_truncate_blocks(struct inode *);
83f6e3710   Marco Stornelli   ufs: drop vmtruncate
455
456
457
  static void ufs_write_failed(struct address_space *mapping, loff_t to)
  {
  	struct inode *inode = mapping->host;
3b7a3a05e   Al Viro   ufs: free excessi...
458
  	if (to > inode->i_size) {
7caef2676   Kirill A. Shutemov   truncate: drop 'o...
459
  		truncate_pagecache(inode, inode->i_size);
3b7a3a05e   Al Viro   ufs: free excessi...
460
461
  		ufs_truncate_blocks(inode);
  	}
83f6e3710   Marco Stornelli   ufs: drop vmtruncate
462
  }
82b9d1d0d   Nick Piggin   ufs: convert to n...
463
464
465
466
  static int ufs_write_begin(struct file *file, struct address_space *mapping,
  			loff_t pos, unsigned len, unsigned flags,
  			struct page **pagep, void **fsdata)
  {
155130a4f   Christoph Hellwig   get rid of block_...
467
468
469
  	int ret;
  
  	ret = block_write_begin(mapping, pos, len, flags, pagep,
f4e420dc4   Christoph Hellwig   clean up write_be...
470
  				ufs_getfrag_block);
83f6e3710   Marco Stornelli   ufs: drop vmtruncate
471
472
  	if (unlikely(ret))
  		ufs_write_failed(mapping, pos + len);
155130a4f   Christoph Hellwig   get rid of block_...
473
474
  
  	return ret;
82b9d1d0d   Nick Piggin   ufs: convert to n...
475
  }
3b7a3a05e   Al Viro   ufs: free excessi...
476
477
478
479
480
481
482
483
484
485
486
  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;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
487
488
489
490
  static sector_t ufs_bmap(struct address_space *mapping, sector_t block)
  {
  	return generic_block_bmap(mapping,block,ufs_getfrag_block);
  }
82b9d1d0d   Nick Piggin   ufs: convert to n...
491

f5e54d6e5   Christoph Hellwig   [PATCH] mark addr...
492
  const struct address_space_operations ufs_aops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
493
494
  	.readpage = ufs_readpage,
  	.writepage = ufs_writepage,
82b9d1d0d   Nick Piggin   ufs: convert to n...
495
  	.write_begin = ufs_write_begin,
3b7a3a05e   Al Viro   ufs: free excessi...
496
  	.write_end = ufs_write_end,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
497
498
  	.bmap = ufs_bmap
  };
826843a34   Evgeniy Dushistov   [PATCH] ufs: dire...
499
500
501
502
503
504
505
506
507
508
509
  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)) {
4b8061a67   Al Viro   ufs: switch to si...
510
  		if (!inode->i_blocks) {
4b8061a67   Al Viro   ufs: switch to si...
511
  			inode->i_link = (char *)UFS_I(inode)->i_u1.i_symlink;
9cdce3c07   Al Viro   ufs: get rid of -...
512
  			inode->i_op = &simple_symlink_inode_operations;
4b8061a67   Al Viro   ufs: switch to si...
513
  		} else {
826843a34   Evgeniy Dushistov   [PATCH] ufs: dire...
514
  			inode->i_mapping->a_ops = &ufs_aops;
9cdce3c07   Al Viro   ufs: get rid of -...
515
  			inode->i_op = &page_symlink_inode_operations;
21fc61c73   Al Viro   don't put symlink...
516
  			inode_nohighmem(inode);
826843a34   Evgeniy Dushistov   [PATCH] ufs: dire...
517
518
519
520
521
  		}
  	} else
  		init_special_inode(inode, inode->i_mode,
  				   ufs_get_inode_dev(inode->i_sb, UFS_I(inode)));
  }
07a0cfec3   Evgeniy Dushistov   ufs proper handli...
522
  static int ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
  {
  	struct ufs_inode_info *ufsi = UFS_I(inode);
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
525
  	struct super_block *sb = inode->i_sb;
6a9a06d9c   Al Viro   ufs: propagate um...
526
  	umode_t mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
527
528
529
530
531
  
  	/*
  	 * Copy data to the in-core inode.
  	 */
  	inode->i_mode = mode = fs16_to_cpu(sb, ufs_inode->ui_mode);
bfe868486   Miklos Szeredi   filesystems: add ...
532
  	set_nlink(inode, fs16_to_cpu(sb, ufs_inode->ui_nlink));
07a0cfec3   Evgeniy Dushistov   ufs proper handli...
533
  	if (inode->i_nlink == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
534
535
  		ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink
  ", inode->i_ino);
07a0cfec3   Evgeniy Dushistov   ufs proper handli...
536
537
  		return -1;
  	}
010d331fc   Al Viro   ufs: move truncat...
538

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
539
540
541
  	/*
  	 * Linux now has 32-bit uid and gid, so we can support EFT.
  	 */
722354658   Eric W. Biederman   userns: Convert t...
542
543
  	i_uid_write(inode, ufs_get_inode_uid(sb, ufs_inode));
  	i_gid_write(inode, ufs_get_inode_gid(sb, ufs_inode));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
544
545
546
547
548
549
550
551
552
  
  	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);
3313e2926   Evgeniy Dushistov   [PATCH] ufs2 writ...
553
  	inode->i_generation = fs32_to_cpu(sb, ufs_inode->ui_gen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
  	ufsi->i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
555
556
  	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);
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
557

010d331fc   Al Viro   ufs: move truncat...
558

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
559
  	if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) {
f33219b7a   Duane Griffin   ufs: don't trunca...
560
561
  		memcpy(ufsi->i_u1.i_data, &ufs_inode->ui_u2.ui_addr,
  		       sizeof(ufs_inode->ui_u2.ui_addr));
dd187a260   Evgeniy Dushistov   [PATCH] ufs: litt...
562
  	} else {
f33219b7a   Duane Griffin   ufs: don't trunca...
563
  		memcpy(ufsi->i_u1.i_symlink, ufs_inode->ui_u2.ui_symlink,
b12903f13   Duane Griffin   ufs: ensure fast ...
564
565
  		       sizeof(ufs_inode->ui_u2.ui_symlink) - 1);
  		ufsi->i_u1.i_symlink[sizeof(ufs_inode->ui_u2.ui_symlink) - 1] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  	}
07a0cfec3   Evgeniy Dushistov   ufs proper handli...
567
  	return 0;
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
568
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569

07a0cfec3   Evgeniy Dushistov   ufs proper handli...
570
  static int ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode)
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
571
572
573
  {
  	struct ufs_inode_info *ufsi = UFS_I(inode);
  	struct super_block *sb = inode->i_sb;
6a9a06d9c   Al Viro   ufs: propagate um...
574
  	umode_t mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
575

abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
576
577
  	UFSD("Reading ufs2 inode, ino %lu
  ", inode->i_ino);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
578
579
580
581
  	/*
  	 * Copy data to the in-core inode.
  	 */
  	inode->i_mode = mode = fs16_to_cpu(sb, ufs2_inode->ui_mode);
bfe868486   Miklos Szeredi   filesystems: add ...
582
  	set_nlink(inode, fs16_to_cpu(sb, ufs2_inode->ui_nlink));
07a0cfec3   Evgeniy Dushistov   ufs proper handli...
583
  	if (inode->i_nlink == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
585
  		ufs_error (sb, "ufs_read_inode", "inode %lu has zero nlink
  ", inode->i_ino);
07a0cfec3   Evgeniy Dushistov   ufs proper handli...
586
587
  		return -1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
588
589
590
591
  
          /*
           * Linux now has 32-bit uid and gid, so we can support EFT.
           */
722354658   Eric W. Biederman   userns: Convert t...
592
593
  	i_uid_write(inode, fs32_to_cpu(sb, ufs2_inode->ui_uid));
  	i_gid_write(inode, fs32_to_cpu(sb, ufs2_inode->ui_gid));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
  
  	inode->i_size = fs64_to_cpu(sb, ufs2_inode->ui_size);
2189850f4   Evgeniy Dushistov   [PATCH] ufs2: mor...
596
597
598
599
600
601
  	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);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
602
  	inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks);
3313e2926   Evgeniy Dushistov   [PATCH] ufs2 writ...
603
  	inode->i_generation = fs32_to_cpu(sb, ufs2_inode->ui_gen);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604
  	ufsi->i_flags = fs32_to_cpu(sb, ufs2_inode->ui_flags);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
605
606
607
608
  	/*
  	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);
  	*/
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
609
610
  
  	if (S_ISCHR(mode) || S_ISBLK(mode) || inode->i_blocks) {
f33219b7a   Duane Griffin   ufs: don't trunca...
611
612
  		memcpy(ufsi->i_u1.u2_i_data, &ufs2_inode->ui_u2.ui_addr,
  		       sizeof(ufs2_inode->ui_u2.ui_addr));
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
613
  	} else {
f33219b7a   Duane Griffin   ufs: don't trunca...
614
  		memcpy(ufsi->i_u1.i_symlink, ufs2_inode->ui_u2.ui_symlink,
b12903f13   Duane Griffin   ufs: ensure fast ...
615
616
  		       sizeof(ufs2_inode->ui_u2.ui_symlink) - 1);
  		ufsi->i_u1.i_symlink[sizeof(ufs2_inode->ui_u2.ui_symlink) - 1] = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
617
  	}
07a0cfec3   Evgeniy Dushistov   ufs proper handli...
618
  	return 0;
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
619
  }
b55c460da   David Howells   iget: stop UFS fr...
620
  struct inode *ufs_iget(struct super_block *sb, unsigned long ino)
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
621
  {
b55c460da   David Howells   iget: stop UFS fr...
622
623
  	struct ufs_inode_info *ufsi;
  	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
624
  	struct buffer_head * bh;
b55c460da   David Howells   iget: stop UFS fr...
625
  	struct inode *inode;
07a0cfec3   Evgeniy Dushistov   ufs proper handli...
626
  	int err;
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
627

b55c460da   David Howells   iget: stop UFS fr...
628
629
  	UFSD("ENTER, ino %lu
  ", ino);
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
630

b55c460da   David Howells   iget: stop UFS fr...
631
  	if (ino < UFS_ROOTINO || ino > (uspi->s_ncg * uspi->s_ipg)) {
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
632
633
  		ufs_warning(sb, "ufs_read_inode", "bad inode number (%lu)
  ",
b55c460da   David Howells   iget: stop UFS fr...
634
635
  			    ino);
  		return ERR_PTR(-EIO);
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
636
  	}
b55c460da   David Howells   iget: stop UFS fr...
637
638
639
640
641
642
643
  	inode = iget_locked(sb, ino);
  	if (!inode)
  		return ERR_PTR(-ENOMEM);
  	if (!(inode->i_state & I_NEW))
  		return inode;
  
  	ufsi = UFS_I(inode);
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
644
645
646
647
648
649
650
651
652
  	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
  ",
  			    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;
07a0cfec3   Evgeniy Dushistov   ufs proper handli...
653
654
  		err = ufs2_read_inode(inode,
  				      ufs2_inode + ufs_inotofsbo(inode->i_ino));
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
655
656
  	} else {
  		struct ufs_inode *ufs_inode = (struct ufs_inode *)bh->b_data;
07a0cfec3   Evgeniy Dushistov   ufs proper handli...
657
658
  		err = ufs1_read_inode(inode,
  				      ufs_inode + ufs_inotofsbo(inode->i_ino));
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
659
  	}
07a0cfec3   Evgeniy Dushistov   ufs proper handli...
660
661
  	if (err)
  		goto bad_inode;
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
662
663
664
665
  	inode->i_version++;
  	ufsi->i_lastfrag =
  		(inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift;
  	ufsi->i_dir_start_lookup = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
666
  	ufsi->i_osync = 0;
826843a34   Evgeniy Dushistov   [PATCH] ufs: dire...
667
  	ufs_set_inode_ops(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
668
669
  
  	brelse(bh);
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
670
671
  	UFSD("EXIT
  ");
b55c460da   David Howells   iget: stop UFS fr...
672
673
  	unlock_new_inode(inode);
  	return inode;
05f225dc8   Evgeniy Dushistov   [PATCH] ufs: ufs_...
674
675
  
  bad_inode:
b55c460da   David Howells   iget: stop UFS fr...
676
677
  	iget_failed(inode);
  	return ERR_PTR(-EIO);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
678
  }
3313e2926   Evgeniy Dushistov   [PATCH] ufs2 writ...
679
  static void ufs1_update_inode(struct inode *inode, struct ufs_inode *ufs_inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680
  {
3313e2926   Evgeniy Dushistov   [PATCH] ufs2 writ...
681
682
  	struct super_block *sb = inode->i_sb;
   	struct ufs_inode_info *ufsi = UFS_I(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
683
684
685
  
  	ufs_inode->ui_mode = cpu_to_fs16(sb, inode->i_mode);
  	ufs_inode->ui_nlink = cpu_to_fs16(sb, inode->i_nlink);
722354658   Eric W. Biederman   userns: Convert t...
686
687
  	ufs_set_inode_uid(sb, ufs_inode, i_uid_read(inode));
  	ufs_set_inode_gid(sb, ufs_inode, i_gid_read(inode));
010d331fc   Al Viro   ufs: move truncat...
688

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
690
691
692
693
694
695
696
697
  	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);
3313e2926   Evgeniy Dushistov   [PATCH] ufs2 writ...
698
  	ufs_inode->ui_gen = cpu_to_fs32(sb, inode->i_generation);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
699

3313e2926   Evgeniy Dushistov   [PATCH] ufs2 writ...
700
  	if ((UFS_SB(sb)->s_flags & UFS_UID_MASK) == UFS_UID_EFT) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
701
702
703
704
705
706
707
708
  		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) {
f33219b7a   Duane Griffin   ufs: don't trunca...
709
710
  		memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.i_data,
  		       sizeof(ufs_inode->ui_u2.ui_addr));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
712
  	}
  	else {
f33219b7a   Duane Griffin   ufs: don't trunca...
713
714
  		memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink,
  		       sizeof(ufs_inode->ui_u2.ui_symlink));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
715
716
717
718
  	}
  
  	if (!inode->i_nlink)
  		memset (ufs_inode, 0, sizeof(struct ufs_inode));
3313e2926   Evgeniy Dushistov   [PATCH] ufs2 writ...
719
720
721
722
723
724
  }
  
  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);
3313e2926   Evgeniy Dushistov   [PATCH] ufs2 writ...
725
726
727
728
729
  
  	UFSD("ENTER
  ");
  	ufs_inode->ui_mode = cpu_to_fs16(sb, inode->i_mode);
  	ufs_inode->ui_nlink = cpu_to_fs16(sb, inode->i_nlink);
722354658   Eric W. Biederman   userns: Convert t...
730
731
  	ufs_inode->ui_uid = cpu_to_fs32(sb, i_uid_read(inode));
  	ufs_inode->ui_gid = cpu_to_fs32(sb, i_gid_read(inode));
3313e2926   Evgeniy Dushistov   [PATCH] ufs2 writ...
732
733
  
  	ufs_inode->ui_size = cpu_to_fs64(sb, inode->i_size);
2189850f4   Evgeniy Dushistov   [PATCH] ufs2: mor...
734
735
736
737
738
739
  	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);
3313e2926   Evgeniy Dushistov   [PATCH] ufs2 writ...
740
741
742
743
744
745
746
747
748
  
  	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) {
f33219b7a   Duane Griffin   ufs: don't trunca...
749
750
  		memcpy(&ufs_inode->ui_u2.ui_addr, ufsi->i_u1.u2_i_data,
  		       sizeof(ufs_inode->ui_u2.ui_addr));
3313e2926   Evgeniy Dushistov   [PATCH] ufs2 writ...
751
  	} else {
f33219b7a   Duane Griffin   ufs: don't trunca...
752
753
  		memcpy(&ufs_inode->ui_u2.ui_symlink, ufsi->i_u1.i_symlink,
  		       sizeof(ufs_inode->ui_u2.ui_symlink));
3313e2926   Evgeniy Dushistov   [PATCH] ufs2 writ...
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
   	}
  
  	if (!inode->i_nlink)
  		memset (ufs_inode, 0, sizeof(struct ufs2_inode));
  	UFSD("EXIT
  ");
  }
  
  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
  ", 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)
  ", 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
  ", 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));
  	}
010d331fc   Al Viro   ufs: move truncat...
794

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
795
796
797
798
  	mark_buffer_dirty(bh);
  	if (do_sync)
  		sync_dirty_buffer(bh);
  	brelse (bh);
010d331fc   Al Viro   ufs: move truncat...
799

abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
800
801
  	UFSD("EXIT
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
802
803
  	return 0;
  }
a9185b41a   Christoph Hellwig   pass writeback_co...
804
  int ufs_write_inode(struct inode *inode, struct writeback_control *wbc)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
805
  {
f3e0f3da1   Al Viro   ufs: kill more lo...
806
  	return ufs_update_inode(inode, wbc->sync_mode == WB_SYNC_ALL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
807
808
809
810
811
812
  }
  
  int ufs_sync_inode (struct inode *inode)
  {
  	return ufs_update_inode (inode, 1);
  }
58e8268c7   Al Viro   switch ufs to ->e...
813
  void ufs_evict_inode(struct inode * inode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
814
  {
58e8268c7   Al Viro   switch ufs to ->e...
815
816
817
818
  	int want_delete = 0;
  
  	if (!inode->i_nlink && !is_bad_inode(inode))
  		want_delete = 1;
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
819

91b0abe36   Johannes Weiner   mm + fs: store sh...
820
  	truncate_inode_pages_final(&inode->i_data);
58e8268c7   Al Viro   switch ufs to ->e...
821
  	if (want_delete) {
58e8268c7   Al Viro   switch ufs to ->e...
822
  		inode->i_size = 0;
d622f167b   Al Viro   ufs: switch ufs_e...
823
824
  		if (inode->i_blocks)
  			ufs_truncate_blocks(inode);
58e8268c7   Al Viro   switch ufs to ->e...
825
826
827
  	}
  
  	invalidate_inode_buffers(inode);
dbd5768f8   Jan Kara   vfs: Rename end_w...
828
  	clear_inode(inode);
58e8268c7   Al Viro   switch ufs to ->e...
829

f3e0f3da1   Al Viro   ufs: kill more lo...
830
  	if (want_delete)
9ef7db7f3   Alexey Khoroshilov   ufs: fix deadlock...
831
  		ufs_free_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
832
  }
010d331fc   Al Viro   ufs: move truncat...
833

a138b4b68   Al Viro   ufs: unify the lo...
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
  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;
  }
010d331fc   Al Viro   ufs: move truncat...
849
850
851
852
853
854
855
856
857
858
  #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;
a138b4b68   Al Viro   ufs: unify the lo...
859
  	struct to_free ctx = {.inode = inode};
010d331fc   Al Viro   ufs: move truncat...
860
861
862
863
864
865
866
  	unsigned i, tmp;
  
  	UFSD("ENTER: ino %lu
  ", inode->i_ino);
  
  	sb = inode->i_sb;
  	uspi = UFS_SB(sb)->s_uspi;
010d331fc   Al Viro   ufs: move truncat...
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
  	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
  ", 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);
010d331fc   Al Viro   ufs: move truncat...
901
902
903
904
905
906
907
908
909
910
911
912
913
  
  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);
a138b4b68   Al Viro   ufs: unify the lo...
914
  		free_data(&ctx, tmp, uspi->s_fpb);
010d331fc   Al Viro   ufs: move truncat...
915
  	}
a138b4b68   Al Viro   ufs: unify the lo...
916
  	free_data(&ctx, 0, 0);
010d331fc   Al Viro   ufs: move truncat...
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
  
  	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);
010d331fc   Al Viro   ufs: move truncat...
934
935
936
937
938
   next3:
  
  	UFSD("EXIT: ino %lu
  ", inode->i_ino);
  }
163073db5   Al Viro   free_full_branch(...
939
  static void free_full_branch(struct inode *inode, u64 ind_block, int depth)
6d1ebbca2   Al Viro   split ufs_truncat...
940
941
942
  {
  	struct super_block *sb = inode->i_sb;
  	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
163073db5   Al Viro   free_full_branch(...
943
  	struct ufs_buffer_head *ubh = ubh_bread(sb, ind_block, uspi->s_bsize);
6d1ebbca2   Al Viro   split ufs_truncat...
944
  	unsigned i;
163073db5   Al Viro   free_full_branch(...
945
  	if (!ubh)
6d1ebbca2   Al Viro   split ufs_truncat...
946
  		return;
6d1ebbca2   Al Viro   split ufs_truncat...
947
948
  
  	if (--depth) {
163073db5   Al Viro   free_full_branch(...
949
950
951
  		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);
cc7231e30   Al Viro   free_full_branch(...
952
  			if (block)
163073db5   Al Viro   free_full_branch(...
953
  				free_full_branch(inode, block, depth);
6d1ebbca2   Al Viro   split ufs_truncat...
954
955
956
957
958
  		}
  	} else {
  		struct to_free ctx = {.inode = inode};
  
  		for (i = 0; i < uspi->s_apb; i++) {
163073db5   Al Viro   free_full_branch(...
959
960
  			void *p = ubh_get_data_ptr(uspi, ubh, i);
  			u64 block = ufs_data_ptr_to_cpu(sb, p);
cc7231e30   Al Viro   free_full_branch(...
961
  			if (block)
163073db5   Al Viro   free_full_branch(...
962
  				free_data(&ctx, block, uspi->s_fpb);
6d1ebbca2   Al Viro   split ufs_truncat...
963
964
965
  		}
  		free_data(&ctx, 0, 0);
  	}
6d1ebbca2   Al Viro   split ufs_truncat...
966
967
  
  	ubh_bforget(ubh);
163073db5   Al Viro   free_full_branch(...
968
  	ufs_free_blocks(inode, ind_block, uspi->s_fpb);
6d1ebbca2   Al Viro   split ufs_truncat...
969
  }
7b4e4f7f8   Al Viro   ufs_trunc_branch(...
970
  static void free_branch_tail(struct inode *inode, unsigned from, struct ufs_buffer_head *ubh, int depth)
010d331fc   Al Viro   ufs: move truncat...
971
  {
7bad5939f   Al Viro   ufs_trunc_dindire...
972
973
  	struct super_block *sb = inode->i_sb;
  	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
7bad5939f   Al Viro   ufs_trunc_dindire...
974
  	unsigned i;
010d331fc   Al Viro   ufs: move truncat...
975

9e0fbbde2   Al Viro   unify ufs_trunc_....
976
  	if (--depth) {
7b4e4f7f8   Al Viro   ufs_trunc_branch(...
977
  		for (i = from; i < uspi->s_apb ; i++) {
163073db5   Al Viro   free_full_branch(...
978
979
980
981
982
983
984
985
986
  			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);
  			}
a96574233   Al Viro   ufs_trunc_branch(...
987
  		}
9e0fbbde2   Al Viro   unify ufs_trunc_....
988
  	} else {
a138b4b68   Al Viro   ufs: unify the lo...
989
  		struct to_free ctx = {.inode = inode};
9e0fbbde2   Al Viro   unify ufs_trunc_....
990
991
  
  		for (i = from; i < uspi->s_apb; i++) {
163073db5   Al Viro   free_full_branch(...
992
993
994
995
996
997
998
999
  			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);
163073db5   Al Viro   free_full_branch(...
1000
  			}
9e0fbbde2   Al Viro   unify ufs_trunc_....
1001
  		}
a138b4b68   Al Viro   ufs: unify the lo...
1002
  		free_data(&ctx, 0, 0);
010d331fc   Al Viro   ufs: move truncat...
1003
  	}
9e0fbbde2   Al Viro   unify ufs_trunc_....
1004
1005
1006
  	if (IS_SYNC(inode) && ubh_buffer_dirty(ubh))
  		ubh_sync_block(ubh);
  	ubh_brelse(ubh);
010d331fc   Al Viro   ufs: move truncat...
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
  }
  
  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 >>
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
1029
  				       (PAGE_SHIFT - inode->i_blkbits));
010d331fc   Al Viro   ufs: move truncat...
1030
1031
1032
1033
         if (IS_ERR(lastpage)) {
                 err = -EIO;
                 goto out;
         }
09cbfeaf1   Kirill A. Shutemov   mm, fs: get rid o...
1034
         end = lastfrag & ((1 << (PAGE_SHIFT - inode->i_blkbits)) - 1);
010d331fc   Al Viro   ufs: move truncat...
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
         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;
7bad5939f   Al Viro   ufs_trunc_dindire...
1083
  	unsigned offsets[4];
31cd043e1   Al Viro   ufs: beginning of...
1084
  	int depth = ufs_block_to_path(inode, DIRECT_BLOCK, offsets);
6775e24d9   Al Viro   ufs_trunc_..indir...
1085
  	int depth2;
42432739b   Al Viro   __ufs_trunc_block...
1086
  	unsigned i;
7b4e4f7f8   Al Viro   ufs_trunc_branch(...
1087
1088
1089
  	struct ufs_buffer_head *ubh[3];
  	void *p;
  	u64 block;
6775e24d9   Al Viro   ufs_trunc_..indir...
1090
1091
1092
1093
1094
1095
1096
1097
  
  	if (!depth)
  		return;
  
  	/* find the last non-zero in offsets[] */
  	for (depth2 = depth - 1; depth2; depth2--)
  		if (offsets[depth2])
  			break;
010d331fc   Al Viro   ufs: move truncat...
1098
1099
  
  	mutex_lock(&ufsi->truncate_mutex);
42432739b   Al Viro   __ufs_trunc_block...
1100
  	if (depth == 1) {
31cd043e1   Al Viro   ufs: beginning of...
1101
  		ufs_trunc_direct(inode);
42432739b   Al Viro   __ufs_trunc_block...
1102
1103
  		offsets[0] = UFS_IND_BLOCK;
  	} else {
7b4e4f7f8   Al Viro   ufs_trunc_branch(...
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
  		/* 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]);
  		}
f53bd1421   Al Viro   __ufs_truncate_bl...
1120
  		while (i--)
7b4e4f7f8   Al Viro   ufs_trunc_branch(...
1121
  			free_branch_tail(inode, offsets[i + 1], ubh[i], depth - i - 1);
42432739b   Al Viro   __ufs_trunc_block...
1122
1123
  	}
  	for (i = offsets[0]; i <= UFS_TIND_BLOCK; i++) {
163073db5   Al Viro   free_full_branch(...
1124
1125
1126
1127
1128
1129
1130
1131
  		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);
  		}
31cd043e1   Al Viro   ufs: beginning of...
1132
  	}
010d331fc   Al Viro   ufs: move truncat...
1133
  	ufsi->i_lastfrag = DIRECT_FRAGMENT;
b6eede0ec   Al Viro   move marking inod...
1134
  	mark_inode_dirty(inode);
010d331fc   Al Viro   ufs: move truncat...
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
  	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
  ",
  	     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);
02027d42c   Deepa Dinamani   fs: Replace CURRE...
1163
  	inode->i_mtime = inode->i_ctime = current_time(inode);
010d331fc   Al Viro   ufs: move truncat...
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
  	mark_inode_dirty(inode);
  out:
  	UFSD("EXIT: err %d
  ", 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;
31051c85b   Jan Kara   fs: Give dentry t...
1186
  	error = setattr_prepare(dentry, attr);
010d331fc   Al Viro   ufs: move truncat...
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
  	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,
  };