blob: 638f4c585e89a404f0bb87ee5ddea0bd2cf3fc9f [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * linux/fs/ufs/balloc.c
3 *
4 * Copyright (C) 1998
5 * Daniel Pirkl <daniel.pirkl@email.cz>
6 * Charles University, Faculty of Mathematics and Physics
7 */
8
9#include <linux/fs.h>
10#include <linux/ufs_fs.h>
11#include <linux/stat.h>
12#include <linux/time.h>
13#include <linux/string.h>
14#include <linux/quotaops.h>
15#include <linux/buffer_head.h>
Randy Dunlap16f7e0f2006-01-11 12:17:46 -080016#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/sched.h>
18#include <linux/bitops.h>
19#include <asm/byteorder.h>
20
21#include "swab.h"
22#include "util.h"
23
Linus Torvalds1da177e2005-04-16 15:20:36 -070024static unsigned ufs_add_fragments (struct inode *, unsigned, unsigned, unsigned, int *);
25static unsigned ufs_alloc_fragments (struct inode *, unsigned, unsigned, unsigned, int *);
26static unsigned ufs_alloccg_block (struct inode *, struct ufs_cg_private_info *, unsigned, int *);
27static unsigned ufs_bitmap_search (struct super_block *, struct ufs_cg_private_info *, unsigned, unsigned);
28static unsigned char ufs_fragtable_8fpb[], ufs_fragtable_other[];
29static void ufs_clusteracct(struct super_block *, struct ufs_cg_private_info *, unsigned, int);
30
31/*
32 * Free 'count' fragments from fragment number 'fragment'
33 */
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -070034void ufs_free_fragments(struct inode *inode, unsigned fragment, unsigned count)
35{
Linus Torvalds1da177e2005-04-16 15:20:36 -070036 struct super_block * sb;
37 struct ufs_sb_private_info * uspi;
38 struct ufs_super_block_first * usb1;
39 struct ufs_cg_private_info * ucpi;
40 struct ufs_cylinder_group * ucg;
41 unsigned cgno, bit, end_bit, bbase, blkmap, i, blkno, cylno;
42
43 sb = inode->i_sb;
44 uspi = UFS_SB(sb)->s_uspi;
Evgeniy7b4ee732006-01-14 11:42:06 +030045 usb1 = ubh_get_usb_first(uspi);
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -070047 UFSD("ENTER, fragment %u, count %u\n", fragment, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
49 if (ufs_fragnum(fragment) + count > uspi->s_fpg)
50 ufs_error (sb, "ufs_free_fragments", "internal error");
51
52 lock_super(sb);
53
54 cgno = ufs_dtog(fragment);
55 bit = ufs_dtogd(fragment);
56 if (cgno >= uspi->s_ncg) {
57 ufs_panic (sb, "ufs_free_fragments", "freeing blocks are outside device");
58 goto failed;
59 }
60
61 ucpi = ufs_load_cylinder (sb, cgno);
62 if (!ucpi)
63 goto failed;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070064 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -070065 if (!ufs_cg_chkmagic(sb, ucg)) {
66 ufs_panic (sb, "ufs_free_fragments", "internal error, bad magic number on cg %u", cgno);
67 goto failed;
68 }
69
70 end_bit = bit + count;
71 bbase = ufs_blknum (bit);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070072 blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073 ufs_fragacct (sb, blkmap, ucg->cg_frsum, -1);
74 for (i = bit; i < end_bit; i++) {
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070075 if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, i))
76 ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, i);
Evgeniy7b4ee732006-01-14 11:42:06 +030077 else
78 ufs_error (sb, "ufs_free_fragments",
79 "bit already cleared for fragment %u", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070080 }
81
82 DQUOT_FREE_BLOCK (inode, count);
83
84
85 fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -070086 uspi->cs_total.cs_nffree += count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070088 blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 ufs_fragacct(sb, blkmap, ucg->cg_frsum, 1);
90
91 /*
92 * Trying to reassemble free fragments into block
93 */
94 blkno = ufs_fragstoblks (bbase);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070095 if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070096 fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -070097 uspi->cs_total.cs_nffree -= uspi->s_fpb;
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, uspi->s_fpb);
99 if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
100 ufs_clusteracct (sb, ucpi, blkno, 1);
101 fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700102 uspi->cs_total.cs_nbfree++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
104 cylno = ufs_cbtocylno (bbase);
105 fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(bbase)), 1);
106 fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
107 }
108
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700109 ubh_mark_buffer_dirty (USPI_UBH(uspi));
110 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700111 if (sb->s_flags & MS_SYNCHRONOUS) {
Evgeniy Dushistov098d5af2006-06-25 05:47:31 -0700112 ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700113 ubh_wait_on_buffer (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 }
115 sb->s_dirt = 1;
116
117 unlock_super (sb);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700118 UFSD("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700119 return;
120
121failed:
122 unlock_super (sb);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700123 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 return;
125}
126
127/*
128 * Free 'count' fragments from fragment number 'fragment' (free whole blocks)
129 */
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700130void ufs_free_blocks(struct inode *inode, unsigned fragment, unsigned count)
131{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700132 struct super_block * sb;
133 struct ufs_sb_private_info * uspi;
134 struct ufs_super_block_first * usb1;
135 struct ufs_cg_private_info * ucpi;
136 struct ufs_cylinder_group * ucg;
137 unsigned overflow, cgno, bit, end_bit, blkno, i, cylno;
138
139 sb = inode->i_sb;
140 uspi = UFS_SB(sb)->s_uspi;
Evgeniy7b4ee732006-01-14 11:42:06 +0300141 usb1 = ubh_get_usb_first(uspi);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700143 UFSD("ENTER, fragment %u, count %u\n", fragment, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
145 if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) {
146 ufs_error (sb, "ufs_free_blocks", "internal error, "
147 "fragment %u, count %u\n", fragment, count);
148 goto failed;
149 }
150
151 lock_super(sb);
152
153do_more:
154 overflow = 0;
155 cgno = ufs_dtog (fragment);
156 bit = ufs_dtogd (fragment);
157 if (cgno >= uspi->s_ncg) {
158 ufs_panic (sb, "ufs_free_blocks", "freeing blocks are outside device");
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700159 goto failed_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700160 }
161 end_bit = bit + count;
162 if (end_bit > uspi->s_fpg) {
163 overflow = bit + count - uspi->s_fpg;
164 count -= overflow;
165 end_bit -= overflow;
166 }
167
168 ucpi = ufs_load_cylinder (sb, cgno);
169 if (!ucpi)
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700170 goto failed_unlock;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700171 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700172 if (!ufs_cg_chkmagic(sb, ucg)) {
173 ufs_panic (sb, "ufs_free_blocks", "internal error, bad magic number on cg %u", cgno);
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700174 goto failed_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 }
176
177 for (i = bit; i < end_bit; i += uspi->s_fpb) {
178 blkno = ufs_fragstoblks(i);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700179 if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
181 }
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700182 ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700183 if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
184 ufs_clusteracct (sb, ucpi, blkno, 1);
185 DQUOT_FREE_BLOCK(inode, uspi->s_fpb);
186
187 fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700188 uspi->cs_total.cs_nbfree++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
190 cylno = ufs_cbtocylno(i);
191 fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(i)), 1);
192 fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
193 }
194
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700195 ubh_mark_buffer_dirty (USPI_UBH(uspi));
196 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700197 if (sb->s_flags & MS_SYNCHRONOUS) {
Evgeniy Dushistov098d5af2006-06-25 05:47:31 -0700198 ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700199 ubh_wait_on_buffer (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700200 }
201
202 if (overflow) {
203 fragment += count;
204 count = overflow;
205 goto do_more;
206 }
207
208 sb->s_dirt = 1;
209 unlock_super (sb);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700210 UFSD("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700211 return;
212
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700213failed_unlock:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214 unlock_super (sb);
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700215failed:
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700216 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 return;
218}
219
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700220/*
221 * Modify inode page cache in such way:
222 * have - blocks with b_blocknr equal to oldb...oldb+count-1
223 * get - blocks with b_blocknr equal to newb...newb+count-1
224 * also we suppose that oldb...oldb+count-1 blocks
225 * situated at the end of file.
226 *
227 * We can come here from ufs_writepage or ufs_prepare_write,
228 * locked_page is argument of these functions, so we already lock it.
229 */
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800230static void ufs_change_blocknr(struct inode *inode, unsigned int beg,
Evgeniy Dushistovf3914752006-06-25 05:47:28 -0700231 unsigned int count, unsigned int oldb,
232 unsigned int newb, struct page *locked_page)
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700233{
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800234 const unsigned mask = (1 << (PAGE_CACHE_SHIFT - inode->i_blkbits)) - 1;
235 struct address_space * const mapping = inode->i_mapping;
Evgeniy Dushistova685e262007-01-29 13:19:54 -0800236 pgoff_t index, cur_index;
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800237 unsigned end, pos, j;
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700238 struct page *page;
239 struct buffer_head *head, *bh;
240
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700241 UFSD("ENTER, ino %lu, count %u, oldb %u, newb %u\n",
242 inode->i_ino, count, oldb, newb);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700243
Evgeniy Dushistova685e262007-01-29 13:19:54 -0800244 BUG_ON(!locked_page);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700245 BUG_ON(!PageLocked(locked_page));
246
Evgeniy Dushistova685e262007-01-29 13:19:54 -0800247 cur_index = locked_page->index;
248
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800249 for (end = count + beg; beg < end; beg = (beg | mask) + 1) {
250 index = beg >> (PAGE_CACHE_SHIFT - inode->i_blkbits);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700251
252 if (likely(cur_index != index)) {
253 page = ufs_get_locked_page(mapping, index);
Evgeniy Dushistov06fa45d2006-08-05 12:13:57 -0700254 if (!page || IS_ERR(page)) /* it was truncated or EIO */
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700255 continue;
256 } else
257 page = locked_page;
258
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700259 head = page_buffers(page);
260 bh = head;
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800261 pos = beg & mask;
262 for (j = 0; j < pos; ++j)
263 bh = bh->b_this_page;
264 j = 0;
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700265 do {
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800266 if (buffer_mapped(bh)) {
267 pos = bh->b_blocknr - oldb;
268 if (pos < count) {
269 UFSD(" change from %llu to %llu\n",
270 (unsigned long long)pos + oldb,
271 (unsigned long long)pos + newb);
272 bh->b_blocknr = newb + pos;
273 unmap_underlying_metadata(bh->b_bdev,
274 bh->b_blocknr);
275 mark_buffer_dirty(bh);
276 ++j;
277 }
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700278 }
279
280 bh = bh->b_this_page;
281 } while (bh != head);
282
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800283 if (j)
284 set_page_dirty(page);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700285
Evgeniy Dushistov10e5dce2006-07-01 04:36:24 -0700286 if (likely(cur_index != index))
287 ufs_put_locked_page(page);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700288 }
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700289 UFSD("EXIT\n");
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700290}
291
Evgeniy Dushistovd63b7092007-01-05 16:37:04 -0800292static void ufs_clear_frags(struct inode *inode, sector_t beg, unsigned int n,
293 int sync)
294{
295 struct buffer_head *bh;
296 sector_t end = beg + n;
297
298 for (; beg < end; ++beg) {
299 bh = sb_getblk(inode->i_sb, beg);
300 lock_buffer(bh);
301 memset(bh->b_data, 0, inode->i_sb->s_blocksize);
302 set_buffer_uptodate(bh);
303 mark_buffer_dirty(bh);
304 unlock_buffer(bh);
305 if (IS_SYNC(inode) || sync)
306 sync_dirty_buffer(bh);
307 brelse(bh);
308 }
309}
310
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700311unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment,
312 unsigned goal, unsigned count, int * err, struct page *locked_page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700313{
314 struct super_block * sb;
315 struct ufs_sb_private_info * uspi;
316 struct ufs_super_block_first * usb1;
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700317 unsigned cgno, oldcount, newcount, tmp, request, result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700318
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700319 UFSD("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700320
321 sb = inode->i_sb;
322 uspi = UFS_SB(sb)->s_uspi;
Evgeniy7b4ee732006-01-14 11:42:06 +0300323 usb1 = ubh_get_usb_first(uspi);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700324 *err = -ENOSPC;
325
326 lock_super (sb);
327
328 tmp = fs32_to_cpu(sb, *p);
329 if (count + ufs_fragnum(fragment) > uspi->s_fpb) {
330 ufs_warning (sb, "ufs_new_fragments", "internal warning"
331 " fragment %u, count %u", fragment, count);
332 count = uspi->s_fpb - ufs_fragnum(fragment);
333 }
334 oldcount = ufs_fragnum (fragment);
335 newcount = oldcount + count;
336
337 /*
338 * Somebody else has just allocated our fragments
339 */
340 if (oldcount) {
341 if (!tmp) {
342 ufs_error (sb, "ufs_new_fragments", "internal error, "
343 "fragment %u, tmp %u\n", fragment, tmp);
344 unlock_super (sb);
345 return (unsigned)-1;
346 }
347 if (fragment < UFS_I(inode)->i_lastfrag) {
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700348 UFSD("EXIT (ALREADY ALLOCATED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700349 unlock_super (sb);
350 return 0;
351 }
352 }
353 else {
354 if (tmp) {
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700355 UFSD("EXIT (ALREADY ALLOCATED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 unlock_super(sb);
357 return 0;
358 }
359 }
360
361 /*
362 * There is not enough space for user on the device
363 */
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700364 if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(uspi, UFS_MINFREE) <= 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 unlock_super (sb);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700366 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700367 return 0;
368 }
369
370 if (goal >= uspi->s_size)
371 goal = 0;
372 if (goal == 0)
373 cgno = ufs_inotocg (inode->i_ino);
374 else
375 cgno = ufs_dtog (goal);
376
377 /*
378 * allocate new fragment
379 */
380 if (oldcount == 0) {
381 result = ufs_alloc_fragments (inode, cgno, goal, count, err);
382 if (result) {
383 *p = cpu_to_fs32(sb, result);
384 *err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
Evgeniy Dushistovd63b7092007-01-05 16:37:04 -0800386 ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
387 locked_page != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 }
389 unlock_super(sb);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700390 UFSD("EXIT, result %u\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700391 return result;
392 }
393
394 /*
395 * resize block
396 */
397 result = ufs_add_fragments (inode, tmp, oldcount, newcount, err);
398 if (result) {
399 *err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700400 UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
Evgeniy Dushistovd63b7092007-01-05 16:37:04 -0800401 ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
402 locked_page != NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700403 unlock_super(sb);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700404 UFSD("EXIT, result %u\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 return result;
406 }
407
408 /*
409 * allocate new block and move data
410 */
411 switch (fs32_to_cpu(sb, usb1->fs_optim)) {
412 case UFS_OPTSPACE:
413 request = newcount;
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700414 if (uspi->s_minfree < 5 || uspi->cs_total.cs_nffree
415 > uspi->s_dsize * uspi->s_minfree / (2 * 100))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700416 break;
417 usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
418 break;
419 default:
420 usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
421
422 case UFS_OPTTIME:
423 request = uspi->s_fpb;
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700424 if (uspi->cs_total.cs_nffree < uspi->s_dsize *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 (uspi->s_minfree - 2) / 100)
426 break;
427 usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
428 break;
429 }
430 result = ufs_alloc_fragments (inode, cgno, goal, request, err);
431 if (result) {
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800432 ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
433 locked_page != NULL);
Evgeniy Dushistovf3914752006-06-25 05:47:28 -0700434 ufs_change_blocknr(inode, fragment - oldcount, oldcount, tmp,
435 result, locked_page);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700436
Linus Torvalds1da177e2005-04-16 15:20:36 -0700437 *p = cpu_to_fs32(sb, result);
438 *err = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 unlock_super(sb);
441 if (newcount < request)
442 ufs_free_fragments (inode, result + newcount, request - newcount);
443 ufs_free_fragments (inode, tmp, oldcount);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700444 UFSD("EXIT, result %u\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445 return result;
446 }
447
448 unlock_super(sb);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700449 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 return 0;
451}
452
453static unsigned
454ufs_add_fragments (struct inode * inode, unsigned fragment,
455 unsigned oldcount, unsigned newcount, int * err)
456{
457 struct super_block * sb;
458 struct ufs_sb_private_info * uspi;
459 struct ufs_super_block_first * usb1;
460 struct ufs_cg_private_info * ucpi;
461 struct ufs_cylinder_group * ucg;
462 unsigned cgno, fragno, fragoff, count, fragsize, i;
463
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700464 UFSD("ENTER, fragment %u, oldcount %u, newcount %u\n", fragment, oldcount, newcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700465
466 sb = inode->i_sb;
467 uspi = UFS_SB(sb)->s_uspi;
Evgeniy7b4ee732006-01-14 11:42:06 +0300468 usb1 = ubh_get_usb_first (uspi);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700469 count = newcount - oldcount;
470
471 cgno = ufs_dtog(fragment);
472 if (fs32_to_cpu(sb, UFS_SB(sb)->fs_cs(cgno).cs_nffree) < count)
473 return 0;
474 if ((ufs_fragnum (fragment) + newcount) > uspi->s_fpb)
475 return 0;
476 ucpi = ufs_load_cylinder (sb, cgno);
477 if (!ucpi)
478 return 0;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700479 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700480 if (!ufs_cg_chkmagic(sb, ucg)) {
481 ufs_panic (sb, "ufs_add_fragments",
482 "internal error, bad magic number on cg %u", cgno);
483 return 0;
484 }
485
486 fragno = ufs_dtogd (fragment);
487 fragoff = ufs_fragnum (fragno);
488 for (i = oldcount; i < newcount; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700489 if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 return 0;
491 /*
492 * Block can be extended
493 */
494 ucg->cg_time = cpu_to_fs32(sb, get_seconds());
495 for (i = newcount; i < (uspi->s_fpb - fragoff); i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700496 if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700497 break;
498 fragsize = i - oldcount;
499 if (!fs32_to_cpu(sb, ucg->cg_frsum[fragsize]))
500 ufs_panic (sb, "ufs_add_fragments",
501 "internal error or corrupted bitmap on cg %u", cgno);
502 fs32_sub(sb, &ucg->cg_frsum[fragsize], 1);
503 if (fragsize != count)
504 fs32_add(sb, &ucg->cg_frsum[fragsize - count], 1);
505 for (i = oldcount; i < newcount; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700506 ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700507 if(DQUOT_ALLOC_BLOCK(inode, count)) {
508 *err = -EDQUOT;
509 return 0;
510 }
511
512 fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
513 fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700514 uspi->cs_total.cs_nffree -= count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700516 ubh_mark_buffer_dirty (USPI_UBH(uspi));
517 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 if (sb->s_flags & MS_SYNCHRONOUS) {
Evgeniy Dushistov098d5af2006-06-25 05:47:31 -0700519 ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700520 ubh_wait_on_buffer (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700521 }
522 sb->s_dirt = 1;
523
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700524 UFSD("EXIT, fragment %u\n", fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525
526 return fragment;
527}
528
529#define UFS_TEST_FREE_SPACE_CG \
530 ucg = (struct ufs_cylinder_group *) UFS_SB(sb)->s_ucg[cgno]->b_data; \
531 if (fs32_to_cpu(sb, ucg->cg_cs.cs_nbfree)) \
532 goto cg_found; \
533 for (k = count; k < uspi->s_fpb; k++) \
534 if (fs32_to_cpu(sb, ucg->cg_frsum[k])) \
535 goto cg_found;
536
537static unsigned ufs_alloc_fragments (struct inode * inode, unsigned cgno,
538 unsigned goal, unsigned count, int * err)
539{
540 struct super_block * sb;
541 struct ufs_sb_private_info * uspi;
542 struct ufs_super_block_first * usb1;
543 struct ufs_cg_private_info * ucpi;
544 struct ufs_cylinder_group * ucg;
545 unsigned oldcg, i, j, k, result, allocsize;
546
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700547 UFSD("ENTER, ino %lu, cgno %u, goal %u, count %u\n", inode->i_ino, cgno, goal, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548
549 sb = inode->i_sb;
550 uspi = UFS_SB(sb)->s_uspi;
Evgeniy7b4ee732006-01-14 11:42:06 +0300551 usb1 = ubh_get_usb_first(uspi);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 oldcg = cgno;
553
554 /*
555 * 1. searching on preferred cylinder group
556 */
557 UFS_TEST_FREE_SPACE_CG
558
559 /*
560 * 2. quadratic rehash
561 */
562 for (j = 1; j < uspi->s_ncg; j *= 2) {
563 cgno += j;
564 if (cgno >= uspi->s_ncg)
565 cgno -= uspi->s_ncg;
566 UFS_TEST_FREE_SPACE_CG
567 }
568
569 /*
570 * 3. brute force search
571 * We start at i = 2 ( 0 is checked at 1.step, 1 at 2.step )
572 */
573 cgno = (oldcg + 1) % uspi->s_ncg;
574 for (j = 2; j < uspi->s_ncg; j++) {
575 cgno++;
576 if (cgno >= uspi->s_ncg)
577 cgno = 0;
578 UFS_TEST_FREE_SPACE_CG
579 }
580
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700581 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582 return 0;
583
584cg_found:
585 ucpi = ufs_load_cylinder (sb, cgno);
586 if (!ucpi)
587 return 0;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700588 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 if (!ufs_cg_chkmagic(sb, ucg))
590 ufs_panic (sb, "ufs_alloc_fragments",
591 "internal error, bad magic number on cg %u", cgno);
592 ucg->cg_time = cpu_to_fs32(sb, get_seconds());
593
594 if (count == uspi->s_fpb) {
595 result = ufs_alloccg_block (inode, ucpi, goal, err);
596 if (result == (unsigned)-1)
597 return 0;
598 goto succed;
599 }
600
601 for (allocsize = count; allocsize < uspi->s_fpb; allocsize++)
602 if (fs32_to_cpu(sb, ucg->cg_frsum[allocsize]) != 0)
603 break;
604
605 if (allocsize == uspi->s_fpb) {
606 result = ufs_alloccg_block (inode, ucpi, goal, err);
607 if (result == (unsigned)-1)
608 return 0;
609 goal = ufs_dtogd (result);
610 for (i = count; i < uspi->s_fpb; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700611 ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700612 i = uspi->s_fpb - count;
613 DQUOT_FREE_BLOCK(inode, i);
614
615 fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700616 uspi->cs_total.cs_nffree += i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700617 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i);
618 fs32_add(sb, &ucg->cg_frsum[i], 1);
619 goto succed;
620 }
621
622 result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
623 if (result == (unsigned)-1)
624 return 0;
625 if(DQUOT_ALLOC_BLOCK(inode, count)) {
626 *err = -EDQUOT;
627 return 0;
628 }
629 for (i = 0; i < count; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700630 ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700631
632 fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700633 uspi->cs_total.cs_nffree -= count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
635 fs32_sub(sb, &ucg->cg_frsum[allocsize], 1);
636
637 if (count != allocsize)
638 fs32_add(sb, &ucg->cg_frsum[allocsize - count], 1);
639
640succed:
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700641 ubh_mark_buffer_dirty (USPI_UBH(uspi));
642 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643 if (sb->s_flags & MS_SYNCHRONOUS) {
Evgeniy Dushistov098d5af2006-06-25 05:47:31 -0700644 ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi));
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700645 ubh_wait_on_buffer (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 }
647 sb->s_dirt = 1;
648
649 result += cgno * uspi->s_fpg;
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700650 UFSD("EXIT3, result %u\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700651 return result;
652}
653
654static unsigned ufs_alloccg_block (struct inode * inode,
655 struct ufs_cg_private_info * ucpi, unsigned goal, int * err)
656{
657 struct super_block * sb;
658 struct ufs_sb_private_info * uspi;
659 struct ufs_super_block_first * usb1;
660 struct ufs_cylinder_group * ucg;
661 unsigned result, cylno, blkno;
662
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700663 UFSD("ENTER, goal %u\n", goal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700664
665 sb = inode->i_sb;
666 uspi = UFS_SB(sb)->s_uspi;
Evgeniy7b4ee732006-01-14 11:42:06 +0300667 usb1 = ubh_get_usb_first(uspi);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700668 ucg = ubh_get_ucg(UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669
670 if (goal == 0) {
671 goal = ucpi->c_rotor;
672 goto norot;
673 }
674 goal = ufs_blknum (goal);
675 goal = ufs_dtogd (goal);
676
677 /*
678 * If the requested block is available, use it.
679 */
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700680 if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, ufs_fragstoblks(goal))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 result = goal;
682 goto gotit;
683 }
684
685norot:
686 result = ufs_bitmap_search (sb, ucpi, goal, uspi->s_fpb);
687 if (result == (unsigned)-1)
688 return (unsigned)-1;
689 ucpi->c_rotor = result;
690gotit:
691 blkno = ufs_fragstoblks(result);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700692 ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700693 if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
694 ufs_clusteracct (sb, ucpi, blkno, -1);
695 if(DQUOT_ALLOC_BLOCK(inode, uspi->s_fpb)) {
696 *err = -EDQUOT;
697 return (unsigned)-1;
698 }
699
700 fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700701 uspi->cs_total.cs_nbfree--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 fs32_sub(sb, &UFS_SB(sb)->fs_cs(ucpi->c_cgx).cs_nbfree, 1);
703 cylno = ufs_cbtocylno(result);
704 fs16_sub(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(result)), 1);
705 fs32_sub(sb, &ubh_cg_blktot(ucpi, cylno), 1);
706
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700707 UFSD("EXIT, result %u\n", result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
709 return result;
710}
711
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700712static unsigned ubh_scanc(struct ufs_sb_private_info *uspi,
713 struct ufs_buffer_head *ubh,
714 unsigned begin, unsigned size,
715 unsigned char *table, unsigned char mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700716{
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700717 unsigned rest, offset;
718 unsigned char *cp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
Linus Torvalds1da177e2005-04-16 15:20:36 -0700720
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700721 offset = begin & ~uspi->s_fmask;
722 begin >>= uspi->s_fshift;
723 for (;;) {
724 if ((offset + size) < uspi->s_fsize)
725 rest = size;
726 else
727 rest = uspi->s_fsize - offset;
728 size -= rest;
729 cp = ubh->bh[begin]->b_data + offset;
730 while ((table[*cp++] & mask) == 0 && --rest)
731 ;
732 if (rest || !size)
733 break;
734 begin++;
735 offset = 0;
736 }
737 return (size + rest);
738}
739
740/*
741 * Find a block of the specified size in the specified cylinder group.
742 * @sp: pointer to super block
743 * @ucpi: pointer to cylinder group info
744 * @goal: near which block we want find new one
745 * @count: specified size
746 */
747static unsigned ufs_bitmap_search(struct super_block *sb,
748 struct ufs_cg_private_info *ucpi,
749 unsigned goal, unsigned count)
750{
751 /*
752 * Bit patterns for identifying fragments in the block map
753 * used as ((map & mask_arr) == want_arr)
754 */
755 static const int mask_arr[9] = {
756 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
757 };
758 static const int want_arr[9] = {
759 0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
760 };
761 struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
762 struct ufs_super_block_first *usb1;
763 struct ufs_cylinder_group *ucg;
764 unsigned start, length, loc, result;
765 unsigned pos, want, blockmap, mask, end;
766
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700767 UFSD("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count);
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700768
Evgeniy7b4ee732006-01-14 11:42:06 +0300769 usb1 = ubh_get_usb_first (uspi);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700770 ucg = ubh_get_ucg(UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771
772 if (goal)
773 start = ufs_dtogd(goal) >> 3;
774 else
775 start = ucpi->c_frotor >> 3;
776
777 length = ((uspi->s_fpg + 7) >> 3) - start;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700778 loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff + start, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779 (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
780 1 << (count - 1 + (uspi->s_fpb & 7)));
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700781 if (loc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 length = start + 1;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700783 loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, length,
784 (uspi->s_fpb == 8) ? ufs_fragtable_8fpb :
785 ufs_fragtable_other,
786 1 << (count - 1 + (uspi->s_fpb & 7)));
787 if (loc == 0) {
788 ufs_error(sb, "ufs_bitmap_search",
789 "bitmap corrupted on cg %u, start %u,"
790 " length %u, count %u, freeoff %u\n",
791 ucpi->c_cgx, start, length, count,
792 ucpi->c_freeoff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 return (unsigned)-1;
794 }
795 start = 0;
796 }
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700797 result = (start + length - loc) << 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700798 ucpi->c_frotor = result;
799
800 /*
801 * found the byte in the map
802 */
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700803
804 for (end = result + 8; result < end; result += uspi->s_fpb) {
805 blockmap = ubh_blkmap(UCPI_UBH(ucpi), ucpi->c_freeoff, result);
806 blockmap <<= 1;
807 mask = mask_arr[count];
808 want = want_arr[count];
809 for (pos = 0; pos <= uspi->s_fpb - count; pos++) {
810 if ((blockmap & mask) == want) {
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700811 UFSD("EXIT, result %u\n", result);
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700812 return result + pos;
813 }
814 mask <<= 1;
815 want <<= 1;
816 }
817 }
818
819 ufs_error(sb, "ufs_bitmap_search", "block not in map on cg %u\n",
820 ucpi->c_cgx);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700821 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 return (unsigned)-1;
823}
824
825static void ufs_clusteracct(struct super_block * sb,
826 struct ufs_cg_private_info * ucpi, unsigned blkno, int cnt)
827{
828 struct ufs_sb_private_info * uspi;
829 int i, start, end, forw, back;
830
831 uspi = UFS_SB(sb)->s_uspi;
832 if (uspi->s_contigsumsize <= 0)
833 return;
834
835 if (cnt > 0)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700836 ubh_setbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700837 else
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700838 ubh_clrbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839
840 /*
841 * Find the size of the cluster going forward.
842 */
843 start = blkno + 1;
844 end = start + uspi->s_contigsumsize;
845 if ( end >= ucpi->c_nclusterblks)
846 end = ucpi->c_nclusterblks;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700847 i = ubh_find_next_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, end, start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 if (i > end)
849 i = end;
850 forw = i - start;
851
852 /*
853 * Find the size of the cluster going backward.
854 */
855 start = blkno - 1;
856 end = start - uspi->s_contigsumsize;
857 if (end < 0 )
858 end = -1;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700859 i = ubh_find_last_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, start, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700860 if ( i < end)
861 i = end;
862 back = start - i;
863
864 /*
865 * Account for old cluster and the possibly new forward and
866 * back clusters.
867 */
868 i = back + forw + 1;
869 if (i > uspi->s_contigsumsize)
870 i = uspi->s_contigsumsize;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700871 fs32_add(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (i << 2)), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700872 if (back > 0)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700873 fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (back << 2)), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874 if (forw > 0)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700875 fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (forw << 2)), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876}
877
878
879static unsigned char ufs_fragtable_8fpb[] = {
880 0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
881 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
882 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
883 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20,
884 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
885 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
886 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
887 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x08, 0x09, 0x09, 0x0A, 0x10, 0x11, 0x20, 0x40,
888 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
889 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
890 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
891 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21,
892 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
893 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0A, 0x12,
894 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0C,
895 0x08, 0x09, 0x09, 0x0A, 0x09, 0x09, 0x0A, 0x0C, 0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80,
896};
897
898static unsigned char ufs_fragtable_other[] = {
899 0x00, 0x16, 0x16, 0x2A, 0x16, 0x16, 0x26, 0x4E, 0x16, 0x16, 0x16, 0x3E, 0x2A, 0x3E, 0x4E, 0x8A,
900 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
901 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
902 0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
903 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
904 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
905 0x26, 0x36, 0x36, 0x2E, 0x36, 0x36, 0x26, 0x6E, 0x36, 0x36, 0x36, 0x3E, 0x2E, 0x3E, 0x6E, 0xAE,
906 0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
907 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
908 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
909 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
910 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
911 0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
912 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
913 0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
914 0x8A, 0x9E, 0x9E, 0xAA, 0x9E, 0x9E, 0xAE, 0xCE, 0x9E, 0x9E, 0x9E, 0xBE, 0xAA, 0xBE, 0xCE, 0x8A,
915};