blob: b035af54f538324f7904267228632177fd92fa13 [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
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -08007 *
8 * UFS2 write support Evgeniy Dushistov <dushistov@mail.ru>, 2007
Linus Torvalds1da177e2005-04-16 15:20:36 -07009 */
10
11#include <linux/fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070012#include <linux/stat.h>
13#include <linux/time.h>
14#include <linux/string.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070015#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/bitops.h>
Christoph Hellwig2f8b5442016-11-01 07:40:13 -060018#include <linux/bio.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070019#include <asm/byteorder.h>
20
Mike Frysingere5420592008-02-08 04:21:31 -080021#include "ufs_fs.h"
Christoph Hellwigbcd6d4e2007-10-16 23:26:51 -070022#include "ufs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070023#include "swab.h"
24#include "util.h"
25
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080026#define INVBLOCK ((u64)-1L)
27
Fabian Frederick45641c82014-06-06 14:36:33 -070028static u64 ufs_add_fragments(struct inode *, u64, unsigned, unsigned);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080029static u64 ufs_alloc_fragments(struct inode *, unsigned, u64, unsigned, int *);
30static u64 ufs_alloccg_block(struct inode *, struct ufs_cg_private_info *, u64, int *);
31static u64 ufs_bitmap_search (struct super_block *, struct ufs_cg_private_info *, u64, unsigned);
Linus Torvalds1da177e2005-04-16 15:20:36 -070032static unsigned char ufs_fragtable_8fpb[], ufs_fragtable_other[];
33static void ufs_clusteracct(struct super_block *, struct ufs_cg_private_info *, unsigned, int);
34
35/*
36 * Free 'count' fragments from fragment number 'fragment'
37 */
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080038void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -070039{
Linus Torvalds1da177e2005-04-16 15:20:36 -070040 struct super_block * sb;
41 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -070042 struct ufs_cg_private_info * ucpi;
43 struct ufs_cylinder_group * ucg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080044 unsigned cgno, bit, end_bit, bbase, blkmap, i;
45 u64 blkno;
Linus Torvalds1da177e2005-04-16 15:20:36 -070046
47 sb = inode->i_sb;
48 uspi = UFS_SB(sb)->s_uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -070049
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080050 UFSD("ENTER, fragment %llu, count %u\n",
51 (unsigned long long)fragment, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -070052
53 if (ufs_fragnum(fragment) + count > uspi->s_fpg)
54 ufs_error (sb, "ufs_free_fragments", "internal error");
Fabian Frederickcdd9eef2015-06-10 10:09:32 +100055
56 mutex_lock(&UFS_SB(sb)->s_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080058 cgno = ufs_dtog(uspi, fragment);
59 bit = ufs_dtogd(uspi, fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -070060 if (cgno >= uspi->s_ncg) {
61 ufs_panic (sb, "ufs_free_fragments", "freeing blocks are outside device");
62 goto failed;
63 }
64
65 ucpi = ufs_load_cylinder (sb, cgno);
66 if (!ucpi)
67 goto failed;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070068 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -070069 if (!ufs_cg_chkmagic(sb, ucg)) {
70 ufs_panic (sb, "ufs_free_fragments", "internal error, bad magic number on cg %u", cgno);
71 goto failed;
72 }
73
74 end_bit = bit + count;
75 bbase = ufs_blknum (bit);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070076 blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -070077 ufs_fragacct (sb, blkmap, ucg->cg_frsum, -1);
78 for (i = bit; i < end_bit; i++) {
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070079 if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, i))
80 ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, i);
Evgeniy7b4ee732006-01-14 11:42:06 +030081 else
82 ufs_error (sb, "ufs_free_fragments",
83 "bit already cleared for fragment %u", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070084 }
85
Linus Torvalds1da177e2005-04-16 15:20:36 -070086 fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -070087 uspi->cs_total.cs_nffree += count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070089 blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 ufs_fragacct(sb, blkmap, ucg->cg_frsum, 1);
91
92 /*
93 * Trying to reassemble free fragments into block
94 */
95 blkno = ufs_fragstoblks (bbase);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070096 if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070097 fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -070098 uspi->cs_total.cs_nffree -= uspi->s_fpb;
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, uspi->s_fpb);
100 if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
101 ufs_clusteracct (sb, ucpi, blkno, 1);
102 fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700103 uspi->cs_total.cs_nbfree++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700104 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800105 if (uspi->fs_magic != UFS2_MAGIC) {
106 unsigned cylno = ufs_cbtocylno (bbase);
107
108 fs16_add(sb, &ubh_cg_blks(ucpi, cylno,
109 ufs_cbtorpos(bbase)), 1);
110 fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
111 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700112 }
113
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700114 ubh_mark_buffer_dirty (USPI_UBH(uspi));
115 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Christoph Hellwig9cb569d2010-08-11 17:06:24 +0200116 if (sb->s_flags & MS_SYNCHRONOUS)
117 ubh_sync_block(UCPI_UBH(ucpi));
Artem Bityutskiy9e9ad5f2012-07-12 16:28:08 +0300118 ufs_mark_sb_dirty(sb);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000119
120 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700121 UFSD("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700122 return;
123
124failed:
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000125 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700126 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 return;
128}
129
130/*
131 * Free 'count' fragments from fragment number 'fragment' (free whole blocks)
132 */
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800133void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count)
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700134{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700135 struct super_block * sb;
136 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 struct ufs_cg_private_info * ucpi;
138 struct ufs_cylinder_group * ucg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800139 unsigned overflow, cgno, bit, end_bit, i;
140 u64 blkno;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700141
142 sb = inode->i_sb;
143 uspi = UFS_SB(sb)->s_uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700144
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800145 UFSD("ENTER, fragment %llu, count %u\n",
146 (unsigned long long)fragment, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
148 if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) {
149 ufs_error (sb, "ufs_free_blocks", "internal error, "
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800150 "fragment %llu, count %u\n",
151 (unsigned long long)fragment, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700152 goto failed;
153 }
154
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000155 mutex_lock(&UFS_SB(sb)->s_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700156
157do_more:
158 overflow = 0;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800159 cgno = ufs_dtog(uspi, fragment);
160 bit = ufs_dtogd(uspi, fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700161 if (cgno >= uspi->s_ncg) {
162 ufs_panic (sb, "ufs_free_blocks", "freeing blocks are outside device");
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700163 goto failed_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700164 }
165 end_bit = bit + count;
166 if (end_bit > uspi->s_fpg) {
167 overflow = bit + count - uspi->s_fpg;
168 count -= overflow;
169 end_bit -= overflow;
170 }
171
172 ucpi = ufs_load_cylinder (sb, cgno);
173 if (!ucpi)
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700174 goto failed_unlock;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700175 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700176 if (!ufs_cg_chkmagic(sb, ucg)) {
177 ufs_panic (sb, "ufs_free_blocks", "internal error, bad magic number on cg %u", cgno);
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700178 goto failed_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700179 }
180
181 for (i = bit; i < end_bit; i += uspi->s_fpb) {
182 blkno = ufs_fragstoblks(i);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700183 if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700184 ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
185 }
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700186 ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700187 if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
188 ufs_clusteracct (sb, ucpi, blkno, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189
190 fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700191 uspi->cs_total.cs_nbfree++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800193
194 if (uspi->fs_magic != UFS2_MAGIC) {
195 unsigned cylno = ufs_cbtocylno(i);
196
197 fs16_add(sb, &ubh_cg_blks(ucpi, cylno,
198 ufs_cbtorpos(i)), 1);
199 fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
200 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201 }
202
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700203 ubh_mark_buffer_dirty (USPI_UBH(uspi));
204 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Christoph Hellwig9cb569d2010-08-11 17:06:24 +0200205 if (sb->s_flags & MS_SYNCHRONOUS)
206 ubh_sync_block(UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700207
208 if (overflow) {
209 fragment += count;
210 count = overflow;
211 goto do_more;
212 }
213
Artem Bityutskiy9e9ad5f2012-07-12 16:28:08 +0300214 ufs_mark_sb_dirty(sb);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000215 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700216 UFSD("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700217 return;
218
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700219failed_unlock:
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000220 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700221failed:
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700222 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223 return;
224}
225
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700226/*
227 * Modify inode page cache in such way:
228 * have - blocks with b_blocknr equal to oldb...oldb+count-1
229 * get - blocks with b_blocknr equal to newb...newb+count-1
230 * also we suppose that oldb...oldb+count-1 blocks
231 * situated at the end of file.
232 *
233 * We can come here from ufs_writepage or ufs_prepare_write,
234 * locked_page is argument of these functions, so we already lock it.
235 */
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800236static void ufs_change_blocknr(struct inode *inode, sector_t beg,
237 unsigned int count, sector_t oldb,
238 sector_t newb, struct page *locked_page)
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700239{
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800240 const unsigned blks_per_page =
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300241 1 << (PAGE_SHIFT - inode->i_blkbits);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800242 const unsigned mask = blks_per_page - 1;
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800243 struct address_space * const mapping = inode->i_mapping;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800244 pgoff_t index, cur_index, last_index;
245 unsigned pos, j, lblock;
246 sector_t end, i;
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700247 struct page *page;
248 struct buffer_head *head, *bh;
249
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800250 UFSD("ENTER, ino %lu, count %u, oldb %llu, newb %llu\n",
251 inode->i_ino, count,
252 (unsigned long long)oldb, (unsigned long long)newb);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700253
Evgeniy Dushistova685e262007-01-29 13:19:54 -0800254 BUG_ON(!locked_page);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700255 BUG_ON(!PageLocked(locked_page));
256
Evgeniy Dushistova685e262007-01-29 13:19:54 -0800257 cur_index = locked_page->index;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800258 end = count + beg;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300259 last_index = end >> (PAGE_SHIFT - inode->i_blkbits);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800260 for (i = beg; i < end; i = (i | mask) + 1) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300261 index = i >> (PAGE_SHIFT - inode->i_blkbits);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700262
263 if (likely(cur_index != index)) {
264 page = ufs_get_locked_page(mapping, index);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800265 if (!page)/* it was truncated */
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700266 continue;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800267 if (IS_ERR(page)) {/* or EIO */
Harvey Harrison9746077a72008-04-28 02:16:17 -0700268 ufs_error(inode->i_sb, __func__,
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800269 "read of page %llu failed\n",
270 (unsigned long long)index);
271 continue;
272 }
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700273 } else
274 page = locked_page;
275
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700276 head = page_buffers(page);
277 bh = head;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800278 pos = i & mask;
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800279 for (j = 0; j < pos; ++j)
280 bh = bh->b_this_page;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800281
282
283 if (unlikely(index == last_index))
284 lblock = end & mask;
285 else
286 lblock = blks_per_page;
287
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700288 do {
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800289 if (j >= lblock)
290 break;
291 pos = (i - beg) + j;
292
293 if (!buffer_mapped(bh))
294 map_bh(bh, inode->i_sb, oldb + pos);
295 if (!buffer_uptodate(bh)) {
Mike Christiedfec8a12016-06-05 14:31:44 -0500296 ll_rw_block(REQ_OP_READ, 0, 1, &bh);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800297 wait_on_buffer(bh);
298 if (!buffer_uptodate(bh)) {
Harvey Harrison9746077a72008-04-28 02:16:17 -0700299 ufs_error(inode->i_sb, __func__,
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800300 "read of block failed\n");
301 break;
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800302 }
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700303 }
304
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800305 UFSD(" change from %llu to %llu, pos %u\n",
Andrew Morton9df13032008-03-19 17:01:05 -0700306 (unsigned long long)(pos + oldb),
307 (unsigned long long)(pos + newb), pos);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800308
309 bh->b_blocknr = newb + pos;
310 unmap_underlying_metadata(bh->b_bdev,
311 bh->b_blocknr);
312 mark_buffer_dirty(bh);
313 ++j;
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700314 bh = bh->b_this_page;
315 } while (bh != head);
316
Evgeniy Dushistov10e5dce2006-07-01 04:36:24 -0700317 if (likely(cur_index != index))
318 ufs_put_locked_page(page);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700319 }
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700320 UFSD("EXIT\n");
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700321}
322
Evgeniy Dushistovd63b7092007-01-05 16:37:04 -0800323static void ufs_clear_frags(struct inode *inode, sector_t beg, unsigned int n,
324 int sync)
325{
326 struct buffer_head *bh;
327 sector_t end = beg + n;
328
329 for (; beg < end; ++beg) {
330 bh = sb_getblk(inode->i_sb, beg);
331 lock_buffer(bh);
332 memset(bh->b_data, 0, inode->i_sb->s_blocksize);
333 set_buffer_uptodate(bh);
334 mark_buffer_dirty(bh);
335 unlock_buffer(bh);
336 if (IS_SYNC(inode) || sync)
337 sync_dirty_buffer(bh);
338 brelse(bh);
339 }
340}
341
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800342u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,
343 u64 goal, unsigned count, int *err,
344 struct page *locked_page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700345{
346 struct super_block * sb;
347 struct ufs_sb_private_info * uspi;
348 struct ufs_super_block_first * usb1;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800349 unsigned cgno, oldcount, newcount;
350 u64 tmp, request, result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700351
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800352 UFSD("ENTER, ino %lu, fragment %llu, goal %llu, count %u\n",
353 inode->i_ino, (unsigned long long)fragment,
354 (unsigned long long)goal, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700355
356 sb = inode->i_sb;
357 uspi = UFS_SB(sb)->s_uspi;
Evgeniy7b4ee732006-01-14 11:42:06 +0300358 usb1 = ubh_get_usb_first(uspi);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700359 *err = -ENOSPC;
360
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000361 mutex_lock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800362 tmp = ufs_data_ptr_to_cpu(sb, p);
363
Linus Torvalds1da177e2005-04-16 15:20:36 -0700364 if (count + ufs_fragnum(fragment) > uspi->s_fpb) {
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800365 ufs_warning(sb, "ufs_new_fragments", "internal warning"
366 " fragment %llu, count %u",
367 (unsigned long long)fragment, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 count = uspi->s_fpb - ufs_fragnum(fragment);
369 }
370 oldcount = ufs_fragnum (fragment);
371 newcount = oldcount + count;
372
373 /*
374 * Somebody else has just allocated our fragments
375 */
376 if (oldcount) {
377 if (!tmp) {
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800378 ufs_error(sb, "ufs_new_fragments", "internal error, "
379 "fragment %llu, tmp %llu\n",
380 (unsigned long long)fragment,
381 (unsigned long long)tmp);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000382 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800383 return INVBLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700384 }
385 if (fragment < UFS_I(inode)->i_lastfrag) {
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700386 UFSD("EXIT (ALREADY ALLOCATED)\n");
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000387 mutex_unlock(&UFS_SB(sb)->s_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700388 return 0;
389 }
390 }
391 else {
392 if (tmp) {
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700393 UFSD("EXIT (ALREADY ALLOCATED)\n");
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000394 mutex_unlock(&UFS_SB(sb)->s_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700395 return 0;
396 }
397 }
398
399 /*
400 * There is not enough space for user on the device
401 */
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700402 if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(uspi, UFS_MINFREE) <= 0) {
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000403 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700404 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700405 return 0;
406 }
407
408 if (goal >= uspi->s_size)
409 goal = 0;
410 if (goal == 0)
411 cgno = ufs_inotocg (inode->i_ino);
412 else
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800413 cgno = ufs_dtog(uspi, goal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700414
415 /*
416 * allocate new fragment
417 */
418 if (oldcount == 0) {
419 result = ufs_alloc_fragments (inode, cgno, goal, count, err);
420 if (result) {
Al Virobd2843f2015-09-09 10:16:39 +0100421 ufs_clear_frags(inode, result + oldcount,
422 newcount - oldcount, locked_page != NULL);
Al Viro724bb092015-06-17 12:02:56 -0400423 write_seqlock(&UFS_I(inode)->meta_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800424 ufs_cpu_to_data_ptr(sb, p, result);
Al Viro724bb092015-06-17 12:02:56 -0400425 write_sequnlock(&UFS_I(inode)->meta_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700426 *err = 0;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800427 UFS_I(inode)->i_lastfrag =
Dan Carpenter1d582722011-05-26 16:25:12 -0700428 max(UFS_I(inode)->i_lastfrag, fragment + count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 }
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000430 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800431 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 return result;
433 }
434
435 /*
436 * resize block
437 */
Fabian Frederick45641c82014-06-06 14:36:33 -0700438 result = ufs_add_fragments(inode, tmp, oldcount, newcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700439 if (result) {
440 *err = 0;
Dan Carpenter1d582722011-05-26 16:25:12 -0700441 UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag,
442 fragment + count);
Evgeniy Dushistovd63b7092007-01-05 16:37:04 -0800443 ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
444 locked_page != NULL);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000445 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800446 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447 return result;
448 }
449
450 /*
451 * allocate new block and move data
452 */
453 switch (fs32_to_cpu(sb, usb1->fs_optim)) {
454 case UFS_OPTSPACE:
455 request = newcount;
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700456 if (uspi->s_minfree < 5 || uspi->cs_total.cs_nffree
457 > uspi->s_dsize * uspi->s_minfree / (2 * 100))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700458 break;
459 usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
460 break;
461 default:
462 usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
463
464 case UFS_OPTTIME:
465 request = uspi->s_fpb;
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700466 if (uspi->cs_total.cs_nffree < uspi->s_dsize *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 (uspi->s_minfree - 2) / 100)
468 break;
469 usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
470 break;
471 }
472 result = ufs_alloc_fragments (inode, cgno, goal, request, err);
473 if (result) {
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800474 ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
475 locked_page != NULL);
Evgeniy Dushistov4b25a372007-03-16 13:38:09 -0800476 ufs_change_blocknr(inode, fragment - oldcount, oldcount,
477 uspi->s_sbbase + tmp,
478 uspi->s_sbbase + result, locked_page);
Al Viro724bb092015-06-17 12:02:56 -0400479 write_seqlock(&UFS_I(inode)->meta_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800480 ufs_cpu_to_data_ptr(sb, p, result);
Al Viro724bb092015-06-17 12:02:56 -0400481 write_sequnlock(&UFS_I(inode)->meta_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 *err = 0;
Dan Carpenter1d582722011-05-26 16:25:12 -0700483 UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag,
484 fragment + count);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000485 mutex_unlock(&UFS_SB(sb)->s_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 if (newcount < request)
487 ufs_free_fragments (inode, result + newcount, request - newcount);
488 ufs_free_fragments (inode, tmp, oldcount);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800489 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700490 return result;
491 }
492
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000493 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700494 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700495 return 0;
496}
497
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800498static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
Fabian Frederick45641c82014-06-06 14:36:33 -0700499 unsigned oldcount, unsigned newcount)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700500{
501 struct super_block * sb;
502 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700503 struct ufs_cg_private_info * ucpi;
504 struct ufs_cylinder_group * ucg;
505 unsigned cgno, fragno, fragoff, count, fragsize, i;
506
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800507 UFSD("ENTER, fragment %llu, oldcount %u, newcount %u\n",
508 (unsigned long long)fragment, oldcount, newcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700509
510 sb = inode->i_sb;
511 uspi = UFS_SB(sb)->s_uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700512 count = newcount - oldcount;
513
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800514 cgno = ufs_dtog(uspi, fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515 if (fs32_to_cpu(sb, UFS_SB(sb)->fs_cs(cgno).cs_nffree) < count)
516 return 0;
517 if ((ufs_fragnum (fragment) + newcount) > uspi->s_fpb)
518 return 0;
519 ucpi = ufs_load_cylinder (sb, cgno);
520 if (!ucpi)
521 return 0;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700522 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 if (!ufs_cg_chkmagic(sb, ucg)) {
524 ufs_panic (sb, "ufs_add_fragments",
525 "internal error, bad magic number on cg %u", cgno);
526 return 0;
527 }
528
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800529 fragno = ufs_dtogd(uspi, fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 fragoff = ufs_fragnum (fragno);
531 for (i = oldcount; i < newcount; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700532 if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 return 0;
534 /*
535 * Block can be extended
536 */
537 ucg->cg_time = cpu_to_fs32(sb, get_seconds());
538 for (i = newcount; i < (uspi->s_fpb - fragoff); i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700539 if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 break;
541 fragsize = i - oldcount;
542 if (!fs32_to_cpu(sb, ucg->cg_frsum[fragsize]))
543 ufs_panic (sb, "ufs_add_fragments",
544 "internal error or corrupted bitmap on cg %u", cgno);
545 fs32_sub(sb, &ucg->cg_frsum[fragsize], 1);
546 if (fragsize != count)
547 fs32_add(sb, &ucg->cg_frsum[fragsize - count], 1);
548 for (i = oldcount; i < newcount; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700549 ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550
551 fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
552 fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700553 uspi->cs_total.cs_nffree -= count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700555 ubh_mark_buffer_dirty (USPI_UBH(uspi));
556 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Christoph Hellwig9cb569d2010-08-11 17:06:24 +0200557 if (sb->s_flags & MS_SYNCHRONOUS)
558 ubh_sync_block(UCPI_UBH(ucpi));
Artem Bityutskiy9e9ad5f2012-07-12 16:28:08 +0300559 ufs_mark_sb_dirty(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800561 UFSD("EXIT, fragment %llu\n", (unsigned long long)fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700562
563 return fragment;
564}
565
566#define UFS_TEST_FREE_SPACE_CG \
567 ucg = (struct ufs_cylinder_group *) UFS_SB(sb)->s_ucg[cgno]->b_data; \
568 if (fs32_to_cpu(sb, ucg->cg_cs.cs_nbfree)) \
569 goto cg_found; \
570 for (k = count; k < uspi->s_fpb; k++) \
571 if (fs32_to_cpu(sb, ucg->cg_frsum[k])) \
572 goto cg_found;
573
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800574static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno,
575 u64 goal, unsigned count, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576{
577 struct super_block * sb;
578 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700579 struct ufs_cg_private_info * ucpi;
580 struct ufs_cylinder_group * ucg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800581 unsigned oldcg, i, j, k, allocsize;
582 u64 result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700583
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800584 UFSD("ENTER, ino %lu, cgno %u, goal %llu, count %u\n",
585 inode->i_ino, cgno, (unsigned long long)goal, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700586
587 sb = inode->i_sb;
588 uspi = UFS_SB(sb)->s_uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589 oldcg = cgno;
590
591 /*
592 * 1. searching on preferred cylinder group
593 */
594 UFS_TEST_FREE_SPACE_CG
595
596 /*
597 * 2. quadratic rehash
598 */
599 for (j = 1; j < uspi->s_ncg; j *= 2) {
600 cgno += j;
601 if (cgno >= uspi->s_ncg)
602 cgno -= uspi->s_ncg;
603 UFS_TEST_FREE_SPACE_CG
604 }
605
606 /*
607 * 3. brute force search
608 * We start at i = 2 ( 0 is checked at 1.step, 1 at 2.step )
609 */
610 cgno = (oldcg + 1) % uspi->s_ncg;
611 for (j = 2; j < uspi->s_ncg; j++) {
612 cgno++;
613 if (cgno >= uspi->s_ncg)
614 cgno = 0;
615 UFS_TEST_FREE_SPACE_CG
616 }
617
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700618 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 return 0;
620
621cg_found:
622 ucpi = ufs_load_cylinder (sb, cgno);
623 if (!ucpi)
624 return 0;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700625 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 if (!ufs_cg_chkmagic(sb, ucg))
627 ufs_panic (sb, "ufs_alloc_fragments",
628 "internal error, bad magic number on cg %u", cgno);
629 ucg->cg_time = cpu_to_fs32(sb, get_seconds());
630
631 if (count == uspi->s_fpb) {
632 result = ufs_alloccg_block (inode, ucpi, goal, err);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800633 if (result == INVBLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700634 return 0;
635 goto succed;
636 }
637
638 for (allocsize = count; allocsize < uspi->s_fpb; allocsize++)
639 if (fs32_to_cpu(sb, ucg->cg_frsum[allocsize]) != 0)
640 break;
641
642 if (allocsize == uspi->s_fpb) {
643 result = ufs_alloccg_block (inode, ucpi, goal, err);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800644 if (result == INVBLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700645 return 0;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800646 goal = ufs_dtogd(uspi, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 for (i = count; i < uspi->s_fpb; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700648 ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700649 i = uspi->s_fpb - count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650
651 fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700652 uspi->cs_total.cs_nffree += i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700653 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i);
654 fs32_add(sb, &ucg->cg_frsum[i], 1);
655 goto succed;
656 }
657
658 result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800659 if (result == INVBLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 for (i = 0; i < count; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700662 ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
664 fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700665 uspi->cs_total.cs_nffree -= count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
667 fs32_sub(sb, &ucg->cg_frsum[allocsize], 1);
668
669 if (count != allocsize)
670 fs32_add(sb, &ucg->cg_frsum[allocsize - count], 1);
671
672succed:
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700673 ubh_mark_buffer_dirty (USPI_UBH(uspi));
674 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Christoph Hellwig9cb569d2010-08-11 17:06:24 +0200675 if (sb->s_flags & MS_SYNCHRONOUS)
676 ubh_sync_block(UCPI_UBH(ucpi));
Artem Bityutskiy9e9ad5f2012-07-12 16:28:08 +0300677 ufs_mark_sb_dirty(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700678
679 result += cgno * uspi->s_fpg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800680 UFSD("EXIT3, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 return result;
682}
683
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800684static u64 ufs_alloccg_block(struct inode *inode,
685 struct ufs_cg_private_info *ucpi,
686 u64 goal, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687{
688 struct super_block * sb;
689 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 struct ufs_cylinder_group * ucg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800691 u64 result, blkno;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800693 UFSD("ENTER, goal %llu\n", (unsigned long long)goal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
695 sb = inode->i_sb;
696 uspi = UFS_SB(sb)->s_uspi;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700697 ucg = ubh_get_ucg(UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700698
699 if (goal == 0) {
700 goal = ucpi->c_rotor;
701 goto norot;
702 }
703 goal = ufs_blknum (goal);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800704 goal = ufs_dtogd(uspi, goal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700705
706 /*
707 * If the requested block is available, use it.
708 */
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700709 if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, ufs_fragstoblks(goal))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710 result = goal;
711 goto gotit;
712 }
713
714norot:
715 result = ufs_bitmap_search (sb, ucpi, goal, uspi->s_fpb);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800716 if (result == INVBLOCK)
717 return INVBLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700718 ucpi->c_rotor = result;
719gotit:
720 blkno = ufs_fragstoblks(result);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700721 ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
723 ufs_clusteracct (sb, ucpi, blkno, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700724
725 fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700726 uspi->cs_total.cs_nbfree--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700727 fs32_sub(sb, &UFS_SB(sb)->fs_cs(ucpi->c_cgx).cs_nbfree, 1);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800728
729 if (uspi->fs_magic != UFS2_MAGIC) {
730 unsigned cylno = ufs_cbtocylno((unsigned)result);
731
732 fs16_sub(sb, &ubh_cg_blks(ucpi, cylno,
733 ufs_cbtorpos((unsigned)result)), 1);
734 fs32_sub(sb, &ubh_cg_blktot(ucpi, cylno), 1);
735 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700736
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800737 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738
739 return result;
740}
741
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700742static unsigned ubh_scanc(struct ufs_sb_private_info *uspi,
743 struct ufs_buffer_head *ubh,
744 unsigned begin, unsigned size,
745 unsigned char *table, unsigned char mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700746{
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700747 unsigned rest, offset;
748 unsigned char *cp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700751 offset = begin & ~uspi->s_fmask;
752 begin >>= uspi->s_fshift;
753 for (;;) {
754 if ((offset + size) < uspi->s_fsize)
755 rest = size;
756 else
757 rest = uspi->s_fsize - offset;
758 size -= rest;
759 cp = ubh->bh[begin]->b_data + offset;
760 while ((table[*cp++] & mask) == 0 && --rest)
761 ;
762 if (rest || !size)
763 break;
764 begin++;
765 offset = 0;
766 }
767 return (size + rest);
768}
769
770/*
771 * Find a block of the specified size in the specified cylinder group.
772 * @sp: pointer to super block
773 * @ucpi: pointer to cylinder group info
774 * @goal: near which block we want find new one
775 * @count: specified size
776 */
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800777static u64 ufs_bitmap_search(struct super_block *sb,
778 struct ufs_cg_private_info *ucpi,
779 u64 goal, unsigned count)
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700780{
781 /*
782 * Bit patterns for identifying fragments in the block map
783 * used as ((map & mask_arr) == want_arr)
784 */
785 static const int mask_arr[9] = {
786 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
787 };
788 static const int want_arr[9] = {
789 0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
790 };
791 struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800792 unsigned start, length, loc;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700793 unsigned pos, want, blockmap, mask, end;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800794 u64 result;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700795
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800796 UFSD("ENTER, cg %u, goal %llu, count %u\n", ucpi->c_cgx,
797 (unsigned long long)goal, count);
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700798
Linus Torvalds1da177e2005-04-16 15:20:36 -0700799 if (goal)
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800800 start = ufs_dtogd(uspi, goal) >> 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700801 else
802 start = ucpi->c_frotor >> 3;
803
804 length = ((uspi->s_fpg + 7) >> 3) - start;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700805 loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff + start, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700806 (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
807 1 << (count - 1 + (uspi->s_fpb & 7)));
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700808 if (loc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700809 length = start + 1;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700810 loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, length,
811 (uspi->s_fpb == 8) ? ufs_fragtable_8fpb :
812 ufs_fragtable_other,
813 1 << (count - 1 + (uspi->s_fpb & 7)));
814 if (loc == 0) {
815 ufs_error(sb, "ufs_bitmap_search",
816 "bitmap corrupted on cg %u, start %u,"
817 " length %u, count %u, freeoff %u\n",
818 ucpi->c_cgx, start, length, count,
819 ucpi->c_freeoff);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800820 return INVBLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700821 }
822 start = 0;
823 }
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700824 result = (start + length - loc) << 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700825 ucpi->c_frotor = result;
826
827 /*
828 * found the byte in the map
829 */
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700830
831 for (end = result + 8; result < end; result += uspi->s_fpb) {
832 blockmap = ubh_blkmap(UCPI_UBH(ucpi), ucpi->c_freeoff, result);
833 blockmap <<= 1;
834 mask = mask_arr[count];
835 want = want_arr[count];
836 for (pos = 0; pos <= uspi->s_fpb - count; pos++) {
837 if ((blockmap & mask) == want) {
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800838 UFSD("EXIT, result %llu\n",
839 (unsigned long long)result);
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700840 return result + pos;
841 }
842 mask <<= 1;
843 want <<= 1;
844 }
845 }
846
847 ufs_error(sb, "ufs_bitmap_search", "block not in map on cg %u\n",
848 ucpi->c_cgx);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700849 UFSD("EXIT (FAILED)\n");
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800850 return INVBLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700851}
852
853static void ufs_clusteracct(struct super_block * sb,
854 struct ufs_cg_private_info * ucpi, unsigned blkno, int cnt)
855{
856 struct ufs_sb_private_info * uspi;
857 int i, start, end, forw, back;
858
859 uspi = UFS_SB(sb)->s_uspi;
860 if (uspi->s_contigsumsize <= 0)
861 return;
862
863 if (cnt > 0)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700864 ubh_setbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700865 else
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700866 ubh_clrbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700867
868 /*
869 * Find the size of the cluster going forward.
870 */
871 start = blkno + 1;
872 end = start + uspi->s_contigsumsize;
873 if ( end >= ucpi->c_nclusterblks)
874 end = ucpi->c_nclusterblks;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700875 i = ubh_find_next_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, end, start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876 if (i > end)
877 i = end;
878 forw = i - start;
879
880 /*
881 * Find the size of the cluster going backward.
882 */
883 start = blkno - 1;
884 end = start - uspi->s_contigsumsize;
885 if (end < 0 )
886 end = -1;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700887 i = ubh_find_last_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, start, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 if ( i < end)
889 i = end;
890 back = start - i;
891
892 /*
893 * Account for old cluster and the possibly new forward and
894 * back clusters.
895 */
896 i = back + forw + 1;
897 if (i > uspi->s_contigsumsize)
898 i = uspi->s_contigsumsize;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700899 fs32_add(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (i << 2)), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700900 if (back > 0)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700901 fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (back << 2)), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 if (forw > 0)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700903 fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (forw << 2)), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700904}
905
906
907static unsigned char ufs_fragtable_8fpb[] = {
908 0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
909 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
910 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
911 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20,
912 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
913 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
914 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
915 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x08, 0x09, 0x09, 0x0A, 0x10, 0x11, 0x20, 0x40,
916 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
917 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
918 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
919 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21,
920 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
921 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0A, 0x12,
922 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0C,
923 0x08, 0x09, 0x09, 0x0A, 0x09, 0x09, 0x0A, 0x0C, 0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80,
924};
925
926static unsigned char ufs_fragtable_other[] = {
927 0x00, 0x16, 0x16, 0x2A, 0x16, 0x16, 0x26, 0x4E, 0x16, 0x16, 0x16, 0x3E, 0x2A, 0x3E, 0x4E, 0x8A,
928 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
929 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
930 0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
931 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
932 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
933 0x26, 0x36, 0x36, 0x2E, 0x36, 0x36, 0x26, 0x6E, 0x36, 0x36, 0x36, 0x3E, 0x2E, 0x3E, 0x6E, 0xAE,
934 0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
935 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
936 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
937 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
938 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
939 0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
940 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
941 0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
942 0x8A, 0x9E, 0x9E, 0xAA, 0x9E, 0x9E, 0xAE, 0xCE, 0x9E, 0x9E, 0x9E, 0xBE, 0xAA, 0xBE, 0xCE, 0x8A,
943};