Blame view

fs/ufs/balloc.c 27.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
  /*
   *  linux/fs/ufs/balloc.c
   *
   * Copyright (C) 1998
   * Daniel Pirkl <daniel.pirkl@email.cz>
   * Charles University, Faculty of Mathematics and Physics
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
7
8
   *
   * UFS2 write support Evgeniy Dushistov <dushistov@mail.ru>, 2007
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
10
11
   */
  
  #include <linux/fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
13
14
  #include <linux/stat.h>
  #include <linux/time.h>
  #include <linux/string.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
  #include <linux/buffer_head.h>
16f7e0fe2   Randy Dunlap   [PATCH] capable/c...
16
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
17
18
  #include <linux/bitops.h>
  #include <asm/byteorder.h>
e54205988   Mike Frysinger   drop linux/ufs_fs...
19
  #include "ufs_fs.h"
bcd6d4ecf   Christoph Hellwig   ufs: move non-lay...
20
  #include "ufs.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
21
22
  #include "swab.h"
  #include "util.h"
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
23
24
25
26
27
28
  #define INVBLOCK ((u64)-1L)
  
  static u64 ufs_add_fragments(struct inode *, u64, unsigned, unsigned, int *);
  static u64 ufs_alloc_fragments(struct inode *, unsigned, u64, unsigned, int *);
  static u64 ufs_alloccg_block(struct inode *, struct ufs_cg_private_info *, u64, int *);
  static u64 ufs_bitmap_search (struct super_block *, struct ufs_cg_private_info *, u64, unsigned);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
29
30
31
32
33
34
  static unsigned char ufs_fragtable_8fpb[], ufs_fragtable_other[];
  static void ufs_clusteracct(struct super_block *, struct ufs_cg_private_info *, unsigned, int);
  
  /*
   * Free 'count' fragments from fragment number 'fragment'
   */
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
35
  void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
36
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
37
38
39
40
41
  	struct super_block * sb;
  	struct ufs_sb_private_info * uspi;
  	struct ufs_super_block_first * usb1;
  	struct ufs_cg_private_info * ucpi;
  	struct ufs_cylinder_group * ucg;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
42
43
  	unsigned cgno, bit, end_bit, bbase, blkmap, i;
  	u64 blkno;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
  	
  	sb = inode->i_sb;
  	uspi = UFS_SB(sb)->s_uspi;
7b4ee73e2   Evgeniy   [PATCH] ufs cleanup
47
  	usb1 = ubh_get_usb_first(uspi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  	
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
49
50
51
  	UFSD("ENTER, fragment %llu, count %u
  ",
  	     (unsigned long long)fragment, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
53
54
55
56
57
  	
  	if (ufs_fragnum(fragment) + count > uspi->s_fpg)
  		ufs_error (sb, "ufs_free_fragments", "internal error");
  	
  	lock_super(sb);
  	
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
58
59
  	cgno = ufs_dtog(uspi, fragment);
  	bit = ufs_dtogd(uspi, fragment);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
60
61
62
63
64
65
66
67
  	if (cgno >= uspi->s_ncg) {
  		ufs_panic (sb, "ufs_free_fragments", "freeing blocks are outside device");
  		goto failed;
  	}
  		
  	ucpi = ufs_load_cylinder (sb, cgno);
  	if (!ucpi) 
  		goto failed;
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
68
  	ucg = ubh_get_ucg (UCPI_UBH(ucpi));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
69
70
71
72
73
74
75
  	if (!ufs_cg_chkmagic(sb, ucg)) {
  		ufs_panic (sb, "ufs_free_fragments", "internal error, bad magic number on cg %u", cgno);
  		goto failed;
  	}
  
  	end_bit = bit + count;
  	bbase = ufs_blknum (bit);
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
76
  	blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77
78
  	ufs_fragacct (sb, blkmap, ucg->cg_frsum, -1);
  	for (i = bit; i < end_bit; i++) {
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
79
80
  		if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, i))
  			ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, i);
7b4ee73e2   Evgeniy   [PATCH] ufs cleanup
81
82
83
  		else 
  			ufs_error (sb, "ufs_free_fragments",
  				   "bit already cleared for fragment %u", i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
84
85
  	}
  	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
86
  	fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
ee3ffd6c1   Evgeniy Dushistov   [PATCH] ufs: make...
87
  	uspi->cs_total.cs_nffree += count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
  	fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
89
  	blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
90
91
92
93
94
95
  	ufs_fragacct(sb, blkmap, ucg->cg_frsum, 1);
  
  	/*
  	 * Trying to reassemble free fragments into block
  	 */
  	blkno = ufs_fragstoblks (bbase);
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
96
  	if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
97
  		fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb);
ee3ffd6c1   Evgeniy Dushistov   [PATCH] ufs: make...
98
  		uspi->cs_total.cs_nffree -= uspi->s_fpb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
99
100
101
102
  		fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, uspi->s_fpb);
  		if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
  			ufs_clusteracct (sb, ucpi, blkno, 1);
  		fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
ee3ffd6c1   Evgeniy Dushistov   [PATCH] ufs: make...
103
  		uspi->cs_total.cs_nbfree++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
  		fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
105
106
107
108
109
110
111
  		if (uspi->fs_magic != UFS2_MAGIC) {
  			unsigned cylno = ufs_cbtocylno (bbase);
  
  			fs16_add(sb, &ubh_cg_blks(ucpi, cylno,
  						  ufs_cbtorpos(bbase)), 1);
  			fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
  	}
  	
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
114
115
  	ubh_mark_buffer_dirty (USPI_UBH(uspi));
  	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
9cb569d60   Christoph Hellwig   remove SWRITE* I/...
116
117
  	if (sb->s_flags & MS_SYNCHRONOUS)
  		ubh_sync_block(UCPI_UBH(ucpi));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
119
120
  	sb->s_dirt = 1;
  	
  	unlock_super (sb);
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
121
122
  	UFSD("EXIT
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
125
126
  	return;
  
  failed:
  	unlock_super (sb);
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
127
128
  	UFSD("EXIT (FAILED)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
129
130
131
132
133
134
  	return;
  }
  
  /*
   * Free 'count' fragments from fragment number 'fragment' (free whole blocks)
   */
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
135
  void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count)
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
136
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
138
139
140
141
  	struct super_block * sb;
  	struct ufs_sb_private_info * uspi;
  	struct ufs_super_block_first * usb1;
  	struct ufs_cg_private_info * ucpi;
  	struct ufs_cylinder_group * ucg;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
142
143
  	unsigned overflow, cgno, bit, end_bit, i;
  	u64 blkno;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
144
145
146
  	
  	sb = inode->i_sb;
  	uspi = UFS_SB(sb)->s_uspi;
7b4ee73e2   Evgeniy   [PATCH] ufs cleanup
147
  	usb1 = ubh_get_usb_first(uspi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148

54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
149
150
151
  	UFSD("ENTER, fragment %llu, count %u
  ",
  	     (unsigned long long)fragment, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
  	
  	if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) {
  		ufs_error (sb, "ufs_free_blocks", "internal error, "
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
155
156
157
  			   "fragment %llu, count %u
  ",
  			   (unsigned long long)fragment, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
160
161
162
163
164
  		goto failed;
  	}
  
  	lock_super(sb);
  	
  do_more:
  	overflow = 0;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
165
166
  	cgno = ufs_dtog(uspi, fragment);
  	bit = ufs_dtogd(uspi, fragment);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
  	if (cgno >= uspi->s_ncg) {
  		ufs_panic (sb, "ufs_free_blocks", "freeing blocks are outside device");
2e006393b   Evgeniy Dushistov   [PATCH] ufs: unlo...
169
  		goto failed_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
173
174
175
176
177
178
179
  	}
  	end_bit = bit + count;
  	if (end_bit > uspi->s_fpg) {
  		overflow = bit + count - uspi->s_fpg;
  		count -= overflow;
  		end_bit -= overflow;
  	}
  
  	ucpi = ufs_load_cylinder (sb, cgno);
  	if (!ucpi) 
2e006393b   Evgeniy Dushistov   [PATCH] ufs: unlo...
180
  		goto failed_unlock;
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
181
  	ucg = ubh_get_ucg (UCPI_UBH(ucpi));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
  	if (!ufs_cg_chkmagic(sb, ucg)) {
  		ufs_panic (sb, "ufs_free_blocks", "internal error, bad magic number on cg %u", cgno);
2e006393b   Evgeniy Dushistov   [PATCH] ufs: unlo...
184
  		goto failed_unlock;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
185
186
187
188
  	}
  
  	for (i = bit; i < end_bit; i += uspi->s_fpb) {
  		blkno = ufs_fragstoblks(i);
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
189
  		if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
190
191
  			ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
  		}
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
192
  		ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
193
194
  		if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
  			ufs_clusteracct (sb, ucpi, blkno, 1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
195
196
  
  		fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
ee3ffd6c1   Evgeniy Dushistov   [PATCH] ufs: make...
197
  		uspi->cs_total.cs_nbfree++;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
198
  		fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
199
200
201
202
203
204
205
206
  
  		if (uspi->fs_magic != UFS2_MAGIC) {
  			unsigned cylno = ufs_cbtocylno(i);
  
  			fs16_add(sb, &ubh_cg_blks(ucpi, cylno,
  						  ufs_cbtorpos(i)), 1);
  			fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
  	}
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
208
209
  	ubh_mark_buffer_dirty (USPI_UBH(uspi));
  	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
9cb569d60   Christoph Hellwig   remove SWRITE* I/...
210
211
  	if (sb->s_flags & MS_SYNCHRONOUS)
  		ubh_sync_block(UCPI_UBH(ucpi));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
212
213
214
215
216
217
218
219
220
  
  	if (overflow) {
  		fragment += count;
  		count = overflow;
  		goto do_more;
  	}
  
  	sb->s_dirt = 1;
  	unlock_super (sb);
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
221
222
  	UFSD("EXIT
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
  	return;
2e006393b   Evgeniy Dushistov   [PATCH] ufs: unlo...
224
  failed_unlock:
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
  	unlock_super (sb);
2e006393b   Evgeniy Dushistov   [PATCH] ufs: unlo...
226
  failed:
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
227
228
  	UFSD("EXIT (FAILED)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
230
  	return;
  }
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
231
232
233
234
235
236
237
238
239
240
  /*
   * Modify inode page cache in such way:
   * have - blocks with b_blocknr equal to oldb...oldb+count-1
   * get - blocks with b_blocknr equal to newb...newb+count-1
   * also we suppose that oldb...oldb+count-1 blocks
   * situated at the end of file.
   *
   * We can come here from ufs_writepage or ufs_prepare_write,
   * locked_page is argument of these functions, so we already lock it.
   */
5431bf97c   Evgeniy Dushistov   [PATCH] ufs: prep...
241
242
243
  static void ufs_change_blocknr(struct inode *inode, sector_t beg,
  			       unsigned int count, sector_t oldb,
  			       sector_t newb, struct page *locked_page)
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
244
  {
5431bf97c   Evgeniy Dushistov   [PATCH] ufs: prep...
245
246
247
  	const unsigned blks_per_page =
  		1 << (PAGE_CACHE_SHIFT - inode->i_blkbits);
  	const unsigned mask = blks_per_page - 1;
efee2b812   Evgeniy Dushistov   [PATCH] ufs: real...
248
  	struct address_space * const mapping = inode->i_mapping;
5431bf97c   Evgeniy Dushistov   [PATCH] ufs: prep...
249
250
251
  	pgoff_t index, cur_index, last_index;
  	unsigned pos, j, lblock;
  	sector_t end, i;
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
252
253
  	struct page *page;
  	struct buffer_head *head, *bh;
5431bf97c   Evgeniy Dushistov   [PATCH] ufs: prep...
254
255
256
257
  	UFSD("ENTER, ino %lu, count %u, oldb %llu, newb %llu
  ",
  	      inode->i_ino, count,
  	     (unsigned long long)oldb, (unsigned long long)newb);
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
258

a685e26ff   Evgeniy Dushistov   [PATCH] ufs: allo...
259
  	BUG_ON(!locked_page);
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
260
  	BUG_ON(!PageLocked(locked_page));
a685e26ff   Evgeniy Dushistov   [PATCH] ufs: allo...
261
  	cur_index = locked_page->index;
5431bf97c   Evgeniy Dushistov   [PATCH] ufs: prep...
262
263
264
265
  	end = count + beg;
  	last_index = end >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
  	for (i = beg; i < end; i = (i | mask) + 1) {
  		index = i >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
266
267
268
  
  		if (likely(cur_index != index)) {
  			page = ufs_get_locked_page(mapping, index);
5431bf97c   Evgeniy Dushistov   [PATCH] ufs: prep...
269
270
271
  			if (!page)/* it was truncated */
  				continue;
  			if (IS_ERR(page)) {/* or EIO */
9746077a7   Harvey Harrison   ufs: replace rema...
272
  				ufs_error(inode->i_sb, __func__,
5431bf97c   Evgeniy Dushistov   [PATCH] ufs: prep...
273
274
275
  					  "read of page %llu failed
  ",
  					  (unsigned long long)index);
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
276
  				continue;
5431bf97c   Evgeniy Dushistov   [PATCH] ufs: prep...
277
  			}
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
278
279
  		} else
  			page = locked_page;
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
280
281
  		head = page_buffers(page);
  		bh = head;
5431bf97c   Evgeniy Dushistov   [PATCH] ufs: prep...
282
  		pos = i & mask;
efee2b812   Evgeniy Dushistov   [PATCH] ufs: real...
283
284
  		for (j = 0; j < pos; ++j)
  			bh = bh->b_this_page;
5431bf97c   Evgeniy Dushistov   [PATCH] ufs: prep...
285
286
287
288
289
290
  
  
  		if (unlikely(index == last_index))
  			lblock = end & mask;
  		else
  			lblock = blks_per_page;
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
291
  		do {
5431bf97c   Evgeniy Dushistov   [PATCH] ufs: prep...
292
293
294
295
296
297
298
299
300
301
  			if (j >= lblock)
  				break;
  			pos = (i - beg) + j;
  
  			if (!buffer_mapped(bh))
  					map_bh(bh, inode->i_sb, oldb + pos);
  			if (!buffer_uptodate(bh)) {
  				ll_rw_block(READ, 1, &bh);
  				wait_on_buffer(bh);
  				if (!buffer_uptodate(bh)) {
9746077a7   Harvey Harrison   ufs: replace rema...
302
  					ufs_error(inode->i_sb, __func__,
5431bf97c   Evgeniy Dushistov   [PATCH] ufs: prep...
303
304
305
  						  "read of block failed
  ");
  					break;
efee2b812   Evgeniy Dushistov   [PATCH] ufs: real...
306
  				}
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
307
  			}
5431bf97c   Evgeniy Dushistov   [PATCH] ufs: prep...
308
309
  			UFSD(" change from %llu to %llu, pos %u
  ",
9df130392   Andrew Morton   fs/ufs/balloc.c: ...
310
311
  			     (unsigned long long)(pos + oldb),
  			     (unsigned long long)(pos + newb), pos);
5431bf97c   Evgeniy Dushistov   [PATCH] ufs: prep...
312
313
314
315
316
317
  
  			bh->b_blocknr = newb + pos;
  			unmap_underlying_metadata(bh->b_bdev,
  						  bh->b_blocknr);
  			mark_buffer_dirty(bh);
  			++j;
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
318
319
  			bh = bh->b_this_page;
  		} while (bh != head);
10e5dce07   Evgeniy Dushistov   [PATCH] ufs: trun...
320
321
  		if (likely(cur_index != index))
  			ufs_put_locked_page(page);
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
322
   	}
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
323
324
  	UFSD("EXIT
  ");
6ef4d6bf8   Evgeniy Dushistov   [PATCH] ufs: chan...
325
  }
d63b70902   Evgeniy Dushistov   [PATCH] fix garba...
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
  static void ufs_clear_frags(struct inode *inode, sector_t beg, unsigned int n,
  			    int sync)
  {
  	struct buffer_head *bh;
  	sector_t end = beg + n;
  
  	for (; beg < end; ++beg) {
  		bh = sb_getblk(inode->i_sb, beg);
  		lock_buffer(bh);
  		memset(bh->b_data, 0, inode->i_sb->s_blocksize);
  		set_buffer_uptodate(bh);
  		mark_buffer_dirty(bh);
  		unlock_buffer(bh);
  		if (IS_SYNC(inode) || sync)
  			sync_dirty_buffer(bh);
  		brelse(bh);
  	}
  }
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
344
345
346
  u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,
  			   u64 goal, unsigned count, int *err,
  			   struct page *locked_page)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
347
348
349
350
  {
  	struct super_block * sb;
  	struct ufs_sb_private_info * uspi;
  	struct ufs_super_block_first * usb1;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
351
352
  	unsigned cgno, oldcount, newcount;
  	u64 tmp, request, result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
  	
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
354
355
356
357
  	UFSD("ENTER, ino %lu, fragment %llu, goal %llu, count %u
  ",
  	     inode->i_ino, (unsigned long long)fragment,
  	     (unsigned long long)goal, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
358
359
360
  	
  	sb = inode->i_sb;
  	uspi = UFS_SB(sb)->s_uspi;
7b4ee73e2   Evgeniy   [PATCH] ufs cleanup
361
  	usb1 = ubh_get_usb_first(uspi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
362
363
364
  	*err = -ENOSPC;
  
  	lock_super (sb);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
365
  	tmp = ufs_data_ptr_to_cpu(sb, p);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
366
  	if (count + ufs_fragnum(fragment) > uspi->s_fpb) {
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
367
368
369
  		ufs_warning(sb, "ufs_new_fragments", "internal warning"
  			    " fragment %llu, count %u",
  			    (unsigned long long)fragment, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
370
371
372
373
374
375
376
377
378
379
  		count = uspi->s_fpb - ufs_fragnum(fragment); 
  	}
  	oldcount = ufs_fragnum (fragment);
  	newcount = oldcount + count;
  
  	/*
  	 * Somebody else has just allocated our fragments
  	 */
  	if (oldcount) {
  		if (!tmp) {
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
380
381
382
383
384
385
386
  			ufs_error(sb, "ufs_new_fragments", "internal error, "
  				  "fragment %llu, tmp %llu
  ",
  				  (unsigned long long)fragment,
  				  (unsigned long long)tmp);
  			unlock_super(sb);
  			return INVBLOCK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
387
388
  		}
  		if (fragment < UFS_I(inode)->i_lastfrag) {
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
389
390
  			UFSD("EXIT (ALREADY ALLOCATED)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
391
392
393
394
395
396
  			unlock_super (sb);
  			return 0;
  		}
  	}
  	else {
  		if (tmp) {
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
397
398
  			UFSD("EXIT (ALREADY ALLOCATED)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
399
400
401
402
403
404
405
406
  			unlock_super(sb);
  			return 0;
  		}
  	}
  
  	/*
  	 * There is not enough space for user on the device
  	 */
ee3ffd6c1   Evgeniy Dushistov   [PATCH] ufs: make...
407
  	if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(uspi, UFS_MINFREE) <= 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
408
  		unlock_super (sb);
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
409
410
  		UFSD("EXIT (FAILED)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
411
412
413
414
415
416
417
418
  		return 0;
  	}
  
  	if (goal >= uspi->s_size) 
  		goal = 0;
  	if (goal == 0) 
  		cgno = ufs_inotocg (inode->i_ino);
  	else
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
419
  		cgno = ufs_dtog(uspi, goal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
420
421
422
423
424
425
426
  	 
  	/*
  	 * allocate new fragment
  	 */
  	if (oldcount == 0) {
  		result = ufs_alloc_fragments (inode, cgno, goal, count, err);
  		if (result) {
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
427
  			ufs_cpu_to_data_ptr(sb, p, result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
  			*err = 0;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
429
  			UFS_I(inode)->i_lastfrag =
1d5827235   Dan Carpenter   ufs: fix truncate...
430
  				max(UFS_I(inode)->i_lastfrag, fragment + count);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
431
432
  			ufs_clear_frags(inode, result + oldcount,
  					newcount - oldcount, locked_page != NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
433
434
  		}
  		unlock_super(sb);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
435
436
  		UFSD("EXIT, result %llu
  ", (unsigned long long)result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
437
438
439
440
441
442
443
444
445
  		return result;
  	}
  
  	/*
  	 * resize block
  	 */
  	result = ufs_add_fragments (inode, tmp, oldcount, newcount, err);
  	if (result) {
  		*err = 0;
1d5827235   Dan Carpenter   ufs: fix truncate...
446
447
  		UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag,
  						fragment + count);
d63b70902   Evgeniy Dushistov   [PATCH] fix garba...
448
449
  		ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
  				locked_page != NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
  		unlock_super(sb);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
451
452
  		UFSD("EXIT, result %llu
  ", (unsigned long long)result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
453
454
455
456
457
458
459
460
461
  		return result;
  	}
  
  	/*
  	 * allocate new block and move data
  	 */
  	switch (fs32_to_cpu(sb, usb1->fs_optim)) {
  	    case UFS_OPTSPACE:
  		request = newcount;
ee3ffd6c1   Evgeniy Dushistov   [PATCH] ufs: make...
462
463
  		if (uspi->s_minfree < 5 || uspi->cs_total.cs_nffree
  		    > uspi->s_dsize * uspi->s_minfree / (2 * 100))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
464
465
466
467
468
469
470
471
  			break;
  		usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
  		break;
  	    default:
  		usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
  	
  	    case UFS_OPTTIME:
  		request = uspi->s_fpb;
ee3ffd6c1   Evgeniy Dushistov   [PATCH] ufs: make...
472
  		if (uspi->cs_total.cs_nffree < uspi->s_dsize *
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
473
474
475
476
477
478
479
  		    (uspi->s_minfree - 2) / 100)
  			break;
  		usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
  		break;
  	}
  	result = ufs_alloc_fragments (inode, cgno, goal, request, err);
  	if (result) {
efee2b812   Evgeniy Dushistov   [PATCH] ufs: real...
480
481
  		ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
  				locked_page != NULL);
4b25a37e2   Evgeniy Dushistov   [PATCH] ufs: zero...
482
483
484
  		ufs_change_blocknr(inode, fragment - oldcount, oldcount,
  				   uspi->s_sbbase + tmp,
  				   uspi->s_sbbase + result, locked_page);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
485
  		ufs_cpu_to_data_ptr(sb, p, result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
486
  		*err = 0;
1d5827235   Dan Carpenter   ufs: fix truncate...
487
488
  		UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag,
  						fragment + count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
489
490
491
492
  		unlock_super(sb);
  		if (newcount < request)
  			ufs_free_fragments (inode, result + newcount, request - newcount);
  		ufs_free_fragments (inode, tmp, oldcount);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
493
494
  		UFSD("EXIT, result %llu
  ", (unsigned long long)result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
496
497
498
  		return result;
  	}
  
  	unlock_super(sb);
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
499
500
  	UFSD("EXIT (FAILED)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
501
502
  	return 0;
  }		
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
503
504
  static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
  			     unsigned oldcount, unsigned newcount, int *err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
505
506
507
508
509
510
511
512
  {
  	struct super_block * sb;
  	struct ufs_sb_private_info * uspi;
  	struct ufs_super_block_first * usb1;
  	struct ufs_cg_private_info * ucpi;
  	struct ufs_cylinder_group * ucg;
  	unsigned cgno, fragno, fragoff, count, fragsize, i;
  	
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
513
514
515
  	UFSD("ENTER, fragment %llu, oldcount %u, newcount %u
  ",
  	     (unsigned long long)fragment, oldcount, newcount);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
516
517
518
  	
  	sb = inode->i_sb;
  	uspi = UFS_SB(sb)->s_uspi;
7b4ee73e2   Evgeniy   [PATCH] ufs cleanup
519
  	usb1 = ubh_get_usb_first (uspi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
520
521
  	count = newcount - oldcount;
  	
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
522
  	cgno = ufs_dtog(uspi, fragment);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
526
527
528
529
  	if (fs32_to_cpu(sb, UFS_SB(sb)->fs_cs(cgno).cs_nffree) < count)
  		return 0;
  	if ((ufs_fragnum (fragment) + newcount) > uspi->s_fpb)
  		return 0;
  	ucpi = ufs_load_cylinder (sb, cgno);
  	if (!ucpi)
  		return 0;
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
530
  	ucg = ubh_get_ucg (UCPI_UBH(ucpi));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
532
533
534
535
  	if (!ufs_cg_chkmagic(sb, ucg)) {
  		ufs_panic (sb, "ufs_add_fragments",
  			"internal error, bad magic number on cg %u", cgno);
  		return 0;
  	}
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
536
  	fragno = ufs_dtogd(uspi, fragment);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
537
538
  	fragoff = ufs_fragnum (fragno);
  	for (i = oldcount; i < newcount; i++)
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
539
  		if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
542
543
544
545
  			return 0;
  	/*
  	 * Block can be extended
  	 */
  	ucg->cg_time = cpu_to_fs32(sb, get_seconds());
  	for (i = newcount; i < (uspi->s_fpb - fragoff); i++)
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
546
  		if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
547
548
549
550
551
552
553
554
555
  			break;
  	fragsize = i - oldcount;
  	if (!fs32_to_cpu(sb, ucg->cg_frsum[fragsize]))
  		ufs_panic (sb, "ufs_add_fragments",
  			"internal error or corrupted bitmap on cg %u", cgno);
  	fs32_sub(sb, &ucg->cg_frsum[fragsize], 1);
  	if (fragsize != count)
  		fs32_add(sb, &ucg->cg_frsum[fragsize - count], 1);
  	for (i = oldcount; i < newcount; i++)
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
556
  		ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
557
558
559
  
  	fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
  	fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
ee3ffd6c1   Evgeniy Dushistov   [PATCH] ufs: make...
560
  	uspi->cs_total.cs_nffree -= count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
561
  	
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
562
563
  	ubh_mark_buffer_dirty (USPI_UBH(uspi));
  	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
9cb569d60   Christoph Hellwig   remove SWRITE* I/...
564
565
  	if (sb->s_flags & MS_SYNCHRONOUS)
  		ubh_sync_block(UCPI_UBH(ucpi));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
566
  	sb->s_dirt = 1;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
567
568
  	UFSD("EXIT, fragment %llu
  ", (unsigned long long)fragment);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
569
570
571
572
573
574
575
576
577
578
579
  	
  	return fragment;
  }
  
  #define UFS_TEST_FREE_SPACE_CG \
  	ucg = (struct ufs_cylinder_group *) UFS_SB(sb)->s_ucg[cgno]->b_data; \
  	if (fs32_to_cpu(sb, ucg->cg_cs.cs_nbfree)) \
  		goto cg_found; \
  	for (k = count; k < uspi->s_fpb; k++) \
  		if (fs32_to_cpu(sb, ucg->cg_frsum[k])) \
  			goto cg_found; 
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
580
581
  static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno,
  			       u64 goal, unsigned count, int *err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
582
583
584
585
586
587
  {
  	struct super_block * sb;
  	struct ufs_sb_private_info * uspi;
  	struct ufs_super_block_first * usb1;
  	struct ufs_cg_private_info * ucpi;
  	struct ufs_cylinder_group * ucg;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
588
589
  	unsigned oldcg, i, j, k, allocsize;
  	u64 result;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
590
  	
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
591
592
593
  	UFSD("ENTER, ino %lu, cgno %u, goal %llu, count %u
  ",
  	     inode->i_ino, cgno, (unsigned long long)goal, count);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
594
595
596
  
  	sb = inode->i_sb;
  	uspi = UFS_SB(sb)->s_uspi;
7b4ee73e2   Evgeniy   [PATCH] ufs cleanup
597
  	usb1 = ubh_get_usb_first(uspi);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
  	oldcg = cgno;
  	
  	/*
  	 * 1. searching on preferred cylinder group
  	 */
  	UFS_TEST_FREE_SPACE_CG
  
  	/*
  	 * 2. quadratic rehash
  	 */
  	for (j = 1; j < uspi->s_ncg; j *= 2) {
  		cgno += j;
  		if (cgno >= uspi->s_ncg) 
  			cgno -= uspi->s_ncg;
  		UFS_TEST_FREE_SPACE_CG
  	}
  
  	/*
  	 * 3. brute force search
  	 * We start at i = 2 ( 0 is checked at 1.step, 1 at 2.step )
  	 */
  	cgno = (oldcg + 1) % uspi->s_ncg;
  	for (j = 2; j < uspi->s_ncg; j++) {
  		cgno++;
  		if (cgno >= uspi->s_ncg)
  			cgno = 0;
  		UFS_TEST_FREE_SPACE_CG
  	}
  	
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
627
628
  	UFSD("EXIT (FAILED)
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
630
631
632
633
634
  	return 0;
  
  cg_found:
  	ucpi = ufs_load_cylinder (sb, cgno);
  	if (!ucpi)
  		return 0;
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
635
  	ucg = ubh_get_ucg (UCPI_UBH(ucpi));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
636
637
638
639
640
641
642
  	if (!ufs_cg_chkmagic(sb, ucg)) 
  		ufs_panic (sb, "ufs_alloc_fragments",
  			"internal error, bad magic number on cg %u", cgno);
  	ucg->cg_time = cpu_to_fs32(sb, get_seconds());
  
  	if (count == uspi->s_fpb) {
  		result = ufs_alloccg_block (inode, ucpi, goal, err);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
643
  		if (result == INVBLOCK)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
644
645
646
647
648
649
650
651
652
653
  			return 0;
  		goto succed;
  	}
  
  	for (allocsize = count; allocsize < uspi->s_fpb; allocsize++)
  		if (fs32_to_cpu(sb, ucg->cg_frsum[allocsize]) != 0)
  			break;
  	
  	if (allocsize == uspi->s_fpb) {
  		result = ufs_alloccg_block (inode, ucpi, goal, err);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
654
  		if (result == INVBLOCK)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
655
  			return 0;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
656
  		goal = ufs_dtogd(uspi, result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
657
  		for (i = count; i < uspi->s_fpb; i++)
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
658
  			ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
659
  		i = uspi->s_fpb - count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
660
661
  
  		fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
ee3ffd6c1   Evgeniy Dushistov   [PATCH] ufs: make...
662
  		uspi->cs_total.cs_nffree += i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
663
664
665
666
667
668
  		fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i);
  		fs32_add(sb, &ucg->cg_frsum[i], 1);
  		goto succed;
  	}
  
  	result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
669
  	if (result == INVBLOCK)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
670
  		return 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
671
  	for (i = 0; i < count; i++)
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
672
  		ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
673
674
  	
  	fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
ee3ffd6c1   Evgeniy Dushistov   [PATCH] ufs: make...
675
  	uspi->cs_total.cs_nffree -= count;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
676
677
678
679
680
681
682
  	fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
  	fs32_sub(sb, &ucg->cg_frsum[allocsize], 1);
  
  	if (count != allocsize)
  		fs32_add(sb, &ucg->cg_frsum[allocsize - count], 1);
  
  succed:
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
683
684
  	ubh_mark_buffer_dirty (USPI_UBH(uspi));
  	ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
9cb569d60   Christoph Hellwig   remove SWRITE* I/...
685
686
  	if (sb->s_flags & MS_SYNCHRONOUS)
  		ubh_sync_block(UCPI_UBH(ucpi));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687
688
689
  	sb->s_dirt = 1;
  
  	result += cgno * uspi->s_fpg;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
690
691
  	UFSD("EXIT3, result %llu
  ", (unsigned long long)result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
692
693
  	return result;
  }
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
694
695
696
  static u64 ufs_alloccg_block(struct inode *inode,
  			     struct ufs_cg_private_info *ucpi,
  			     u64 goal, int *err)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
697
698
699
700
701
  {
  	struct super_block * sb;
  	struct ufs_sb_private_info * uspi;
  	struct ufs_super_block_first * usb1;
  	struct ufs_cylinder_group * ucg;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
702
  	u64 result, blkno;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
703

54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
704
705
  	UFSD("ENTER, goal %llu
  ", (unsigned long long)goal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
706
707
708
  
  	sb = inode->i_sb;
  	uspi = UFS_SB(sb)->s_uspi;
7b4ee73e2   Evgeniy   [PATCH] ufs cleanup
709
  	usb1 = ubh_get_usb_first(uspi);
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
710
  	ucg = ubh_get_ucg(UCPI_UBH(ucpi));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
711
712
713
714
715
716
  
  	if (goal == 0) {
  		goal = ucpi->c_rotor;
  		goto norot;
  	}
  	goal = ufs_blknum (goal);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
717
  	goal = ufs_dtogd(uspi, goal);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
718
719
720
721
  	
  	/*
  	 * If the requested block is available, use it.
  	 */
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
722
  	if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, ufs_fragstoblks(goal))) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
723
724
725
726
727
728
  		result = goal;
  		goto gotit;
  	}
  	
  norot:	
  	result = ufs_bitmap_search (sb, ucpi, goal, uspi->s_fpb);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
729
730
  	if (result == INVBLOCK)
  		return INVBLOCK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
731
732
733
  	ucpi->c_rotor = result;
  gotit:
  	blkno = ufs_fragstoblks(result);
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
734
  	ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
735
736
  	if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
  		ufs_clusteracct (sb, ucpi, blkno, -1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
737
738
  
  	fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1);
ee3ffd6c1   Evgeniy Dushistov   [PATCH] ufs: make...
739
  	uspi->cs_total.cs_nbfree--;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
740
  	fs32_sub(sb, &UFS_SB(sb)->fs_cs(ucpi->c_cgx).cs_nbfree, 1);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
741
742
743
744
745
746
747
748
  
  	if (uspi->fs_magic != UFS2_MAGIC) {
  		unsigned cylno = ufs_cbtocylno((unsigned)result);
  
  		fs16_sub(sb, &ubh_cg_blks(ucpi, cylno,
  					  ufs_cbtorpos((unsigned)result)), 1);
  		fs32_sub(sb, &ubh_cg_blktot(ucpi, cylno), 1);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
749
  	
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
750
751
  	UFSD("EXIT, result %llu
  ", (unsigned long long)result);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
752
753
754
  
  	return result;
  }
3e41f597b   Evgeniy Dushistov   [PATCH] ufs: not ...
755
756
757
758
  static unsigned ubh_scanc(struct ufs_sb_private_info *uspi,
  			  struct ufs_buffer_head *ubh,
  			  unsigned begin, unsigned size,
  			  unsigned char *table, unsigned char mask)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
759
  {
3e41f597b   Evgeniy Dushistov   [PATCH] ufs: not ...
760
761
  	unsigned rest, offset;
  	unsigned char *cp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
762
  	
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
763

3e41f597b   Evgeniy Dushistov   [PATCH] ufs: not ...
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
  	offset = begin & ~uspi->s_fmask;
  	begin >>= uspi->s_fshift;
  	for (;;) {
  		if ((offset + size) < uspi->s_fsize)
  			rest = size;
  		else
  			rest = uspi->s_fsize - offset;
  		size -= rest;
  		cp = ubh->bh[begin]->b_data + offset;
  		while ((table[*cp++] & mask) == 0 && --rest)
  			;
  		if (rest || !size)
  			break;
  		begin++;
  		offset = 0;
  	}
  	return (size + rest);
  }
  
  /*
   * Find a block of the specified size in the specified cylinder group.
   * @sp: pointer to super block
   * @ucpi: pointer to cylinder group info
   * @goal: near which block we want find new one
   * @count: specified size
   */
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
790
791
792
  static u64 ufs_bitmap_search(struct super_block *sb,
  			     struct ufs_cg_private_info *ucpi,
  			     u64 goal, unsigned count)
3e41f597b   Evgeniy Dushistov   [PATCH] ufs: not ...
793
794
795
796
797
798
799
800
801
802
803
804
805
806
  {
  	/*
  	 * Bit patterns for identifying fragments in the block map
  	 * used as ((map & mask_arr) == want_arr)
  	 */
  	static const int mask_arr[9] = {
  		0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
  	};
  	static const int want_arr[9] = {
  		0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
  	};
  	struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
  	struct ufs_super_block_first *usb1;
  	struct ufs_cylinder_group *ucg;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
807
  	unsigned start, length, loc;
3e41f597b   Evgeniy Dushistov   [PATCH] ufs: not ...
808
  	unsigned pos, want, blockmap, mask, end;
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
809
  	u64 result;
3e41f597b   Evgeniy Dushistov   [PATCH] ufs: not ...
810

54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
811
812
813
  	UFSD("ENTER, cg %u, goal %llu, count %u
  ", ucpi->c_cgx,
  	     (unsigned long long)goal, count);
3e41f597b   Evgeniy Dushistov   [PATCH] ufs: not ...
814

7b4ee73e2   Evgeniy   [PATCH] ufs cleanup
815
  	usb1 = ubh_get_usb_first (uspi);
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
816
  	ucg = ubh_get_ucg(UCPI_UBH(ucpi));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
817
818
  
  	if (goal)
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
819
  		start = ufs_dtogd(uspi, goal) >> 3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
820
821
822
823
  	else
  		start = ucpi->c_frotor >> 3;
  		
  	length = ((uspi->s_fpg + 7) >> 3) - start;
3e41f597b   Evgeniy Dushistov   [PATCH] ufs: not ...
824
  	loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff + start, length,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
825
826
  		(uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
  		1 << (count - 1 + (uspi->s_fpb & 7))); 
3e41f597b   Evgeniy Dushistov   [PATCH] ufs: not ...
827
  	if (loc == 0) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
828
  		length = start + 1;
3e41f597b   Evgeniy Dushistov   [PATCH] ufs: not ...
829
830
831
832
833
834
835
836
837
838
839
  		loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, length,
  				(uspi->s_fpb == 8) ? ufs_fragtable_8fpb :
  				ufs_fragtable_other,
  				1 << (count - 1 + (uspi->s_fpb & 7)));
  		if (loc == 0) {
  			ufs_error(sb, "ufs_bitmap_search",
  				  "bitmap corrupted on cg %u, start %u,"
  				  " length %u, count %u, freeoff %u
  ",
  				  ucpi->c_cgx, start, length, count,
  				  ucpi->c_freeoff);
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
840
  			return INVBLOCK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
841
842
843
  		}
  		start = 0;
  	}
3e41f597b   Evgeniy Dushistov   [PATCH] ufs: not ...
844
  	result = (start + length - loc) << 3;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
845
846
847
848
849
  	ucpi->c_frotor = result;
  
  	/*
  	 * found the byte in the map
  	 */
3e41f597b   Evgeniy Dushistov   [PATCH] ufs: not ...
850
851
852
853
854
855
856
857
  
  	for (end = result + 8; result < end; result += uspi->s_fpb) {
  		blockmap = ubh_blkmap(UCPI_UBH(ucpi), ucpi->c_freeoff, result);
  		blockmap <<= 1;
  		mask = mask_arr[count];
  		want = want_arr[count];
  		for (pos = 0; pos <= uspi->s_fpb - count; pos++) {
  			if ((blockmap & mask) == want) {
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
858
859
860
  				UFSD("EXIT, result %llu
  ",
  				     (unsigned long long)result);
3e41f597b   Evgeniy Dushistov   [PATCH] ufs: not ...
861
862
863
864
865
866
867
868
869
870
  				return result + pos;
   			}
  			mask <<= 1;
  			want <<= 1;
   		}
   	}
  
  	ufs_error(sb, "ufs_bitmap_search", "block not in map on cg %u
  ",
  		  ucpi->c_cgx);
abf5d15fd   Evgeniy Dushistov   [PATCH] ufs: easy...
871
872
  	UFSD("EXIT (FAILED)
  ");
54fb996ac   Evgeniy Dushistov   [PATCH] ufs2 writ...
873
  	return INVBLOCK;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
874
875
876
877
878
879
880
881
882
883
884
885
886
  }
  
  static void ufs_clusteracct(struct super_block * sb,
  	struct ufs_cg_private_info * ucpi, unsigned blkno, int cnt)
  {
  	struct ufs_sb_private_info * uspi;
  	int i, start, end, forw, back;
  	
  	uspi = UFS_SB(sb)->s_uspi;
  	if (uspi->s_contigsumsize <= 0)
  		return;
  
  	if (cnt > 0)
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
887
  		ubh_setbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
888
  	else
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
889
  		ubh_clrbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
890
891
892
893
894
895
896
897
  
  	/*
  	 * Find the size of the cluster going forward.
  	 */
  	start = blkno + 1;
  	end = start + uspi->s_contigsumsize;
  	if ( end >= ucpi->c_nclusterblks)
  		end = ucpi->c_nclusterblks;
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
898
  	i = ubh_find_next_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, end, start);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
899
900
901
902
903
904
905
906
907
908
909
  	if (i > end)
  		i = end;
  	forw = i - start;
  	
  	/*
  	 * Find the size of the cluster going backward.
  	 */
  	start = blkno - 1;
  	end = start - uspi->s_contigsumsize;
  	if (end < 0 ) 
  		end = -1;
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
910
  	i = ubh_find_last_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, start, end);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
911
912
913
914
915
916
917
918
919
920
921
  	if ( i < end) 
  		i = end;
  	back = start - i;
  	
  	/*
  	 * Account for old cluster and the possibly new forward and
  	 * back clusters.
  	 */
  	i = back + forw + 1;
  	if (i > uspi->s_contigsumsize)
  		i = uspi->s_contigsumsize;
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
922
  	fs32_add(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (i << 2)), cnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
923
  	if (back > 0)
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
924
  		fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (back << 2)), cnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
925
  	if (forw > 0)
9695ef16e   Evgeniy Dushistov   [PATCH] ufs: wron...
926
  		fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (forw << 2)), cnt);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
  }
  
  
  static unsigned char ufs_fragtable_8fpb[] = {
  	0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
  	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
  	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
  	0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20,
  	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,	
  	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
  	0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
  	0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x08, 0x09, 0x09, 0x0A, 0x10, 0x11, 0x20, 0x40,
  	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
  	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
  	0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
  	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21,
  	0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
  	0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0A, 0x12,
  	0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0C,
  	0x08, 0x09, 0x09, 0x0A, 0x09, 0x09, 0x0A, 0x0C, 0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80,
  };
  
  static unsigned char ufs_fragtable_other[] = {
  	0x00, 0x16, 0x16, 0x2A, 0x16, 0x16, 0x26, 0x4E, 0x16, 0x16, 0x16, 0x3E, 0x2A, 0x3E, 0x4E, 0x8A,
  	0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
  	0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
  	0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
  	0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
  	0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
  	0x26, 0x36, 0x36, 0x2E, 0x36, 0x36, 0x26, 0x6E, 0x36, 0x36, 0x36, 0x3E, 0x2E, 0x3E, 0x6E, 0xAE,
  	0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
  	0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
  	0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
  	0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
  	0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
  	0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
  	0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E,	0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
  	0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
  	0x8A, 0x9E, 0x9E, 0xAA, 0x9E, 0x9E, 0xAE, 0xCE, 0x9E, 0x9E, 0x9E, 0xBE, 0xAA, 0xBE, 0xCE, 0x8A,
  };