blob: a81b9701302199be9a486d119605a83d4a47679a [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>
18#include <asm/byteorder.h>
19
Mike Frysingere5420592008-02-08 04:21:31 -080020#include "ufs_fs.h"
Christoph Hellwigbcd6d4e2007-10-16 23:26:51 -070021#include "ufs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include "swab.h"
23#include "util.h"
24
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080025#define INVBLOCK ((u64)-1L)
26
Fabian Frederick45641c82014-06-06 14:36:33 -070027static u64 ufs_add_fragments(struct inode *, u64, unsigned, unsigned);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080028static u64 ufs_alloc_fragments(struct inode *, unsigned, u64, unsigned, int *);
29static u64 ufs_alloccg_block(struct inode *, struct ufs_cg_private_info *, u64, int *);
30static u64 ufs_bitmap_search (struct super_block *, struct ufs_cg_private_info *, u64, unsigned);
Linus Torvalds1da177e2005-04-16 15:20:36 -070031static unsigned char ufs_fragtable_8fpb[], ufs_fragtable_other[];
32static void ufs_clusteracct(struct super_block *, struct ufs_cg_private_info *, unsigned, int);
33
34/*
35 * Free 'count' fragments from fragment number 'fragment'
36 */
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080037void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -070038{
Linus Torvalds1da177e2005-04-16 15:20:36 -070039 struct super_block * sb;
40 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 struct ufs_cg_private_info * ucpi;
42 struct ufs_cylinder_group * ucg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080043 unsigned cgno, bit, end_bit, bbase, blkmap, i;
44 u64 blkno;
Linus Torvalds1da177e2005-04-16 15:20:36 -070045
46 sb = inode->i_sb;
47 uspi = UFS_SB(sb)->s_uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -070048
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080049 UFSD("ENTER, fragment %llu, count %u\n",
50 (unsigned long long)fragment, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52 if (ufs_fragnum(fragment) + count > uspi->s_fpg)
53 ufs_error (sb, "ufs_free_fragments", "internal error");
Fabian Frederickcdd9eef2015-06-10 10:09:32 +100054
55 mutex_lock(&UFS_SB(sb)->s_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070056
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080057 cgno = ufs_dtog(uspi, fragment);
58 bit = ufs_dtogd(uspi, fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -070059 if (cgno >= uspi->s_ncg) {
60 ufs_panic (sb, "ufs_free_fragments", "freeing blocks are outside device");
61 goto failed;
62 }
63
64 ucpi = ufs_load_cylinder (sb, cgno);
65 if (!ucpi)
66 goto failed;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070067 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -070068 if (!ufs_cg_chkmagic(sb, ucg)) {
69 ufs_panic (sb, "ufs_free_fragments", "internal error, bad magic number on cg %u", cgno);
70 goto failed;
71 }
72
73 end_bit = bit + count;
74 bbase = ufs_blknum (bit);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070075 blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -070076 ufs_fragacct (sb, blkmap, ucg->cg_frsum, -1);
77 for (i = bit; i < end_bit; i++) {
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070078 if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, i))
79 ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, i);
Evgeniy7b4ee732006-01-14 11:42:06 +030080 else
81 ufs_error (sb, "ufs_free_fragments",
82 "bit already cleared for fragment %u", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070083 }
Al Viroaed005f2017-06-08 21:15:03 -040084
85 inode_sub_bytes(inode, count << uspi->s_fshift);
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);
Al Viroaed005f2017-06-08 21:15:03 -0400187 inode_sub_bytes(inode, uspi->s_fpb << uspi->s_fshift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700188 if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
189 ufs_clusteracct (sb, ucpi, blkno, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190
191 fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700192 uspi->cs_total.cs_nbfree++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700193 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800194
195 if (uspi->fs_magic != UFS2_MAGIC) {
196 unsigned cylno = ufs_cbtocylno(i);
197
198 fs16_add(sb, &ubh_cg_blks(ucpi, cylno,
199 ufs_cbtorpos(i)), 1);
200 fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
201 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700202 }
203
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700204 ubh_mark_buffer_dirty (USPI_UBH(uspi));
205 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Christoph Hellwig9cb569d2010-08-11 17:06:24 +0200206 if (sb->s_flags & MS_SYNCHRONOUS)
207 ubh_sync_block(UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700208
209 if (overflow) {
210 fragment += count;
211 count = overflow;
212 goto do_more;
213 }
214
Artem Bityutskiy9e9ad5f2012-07-12 16:28:08 +0300215 ufs_mark_sb_dirty(sb);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000216 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700217 UFSD("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700218 return;
219
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700220failed_unlock:
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000221 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700222failed:
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700223 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700224 return;
225}
226
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700227/*
228 * Modify inode page cache in such way:
229 * have - blocks with b_blocknr equal to oldb...oldb+count-1
230 * get - blocks with b_blocknr equal to newb...newb+count-1
231 * also we suppose that oldb...oldb+count-1 blocks
232 * situated at the end of file.
233 *
234 * We can come here from ufs_writepage or ufs_prepare_write,
235 * locked_page is argument of these functions, so we already lock it.
236 */
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800237static void ufs_change_blocknr(struct inode *inode, sector_t beg,
238 unsigned int count, sector_t oldb,
239 sector_t newb, struct page *locked_page)
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700240{
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800241 const unsigned blks_per_page =
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300242 1 << (PAGE_SHIFT - inode->i_blkbits);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800243 const unsigned mask = blks_per_page - 1;
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800244 struct address_space * const mapping = inode->i_mapping;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800245 pgoff_t index, cur_index, last_index;
246 unsigned pos, j, lblock;
247 sector_t end, i;
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700248 struct page *page;
249 struct buffer_head *head, *bh;
250
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800251 UFSD("ENTER, ino %lu, count %u, oldb %llu, newb %llu\n",
252 inode->i_ino, count,
253 (unsigned long long)oldb, (unsigned long long)newb);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700254
Evgeniy Dushistova685e262007-01-29 13:19:54 -0800255 BUG_ON(!locked_page);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700256 BUG_ON(!PageLocked(locked_page));
257
Evgeniy Dushistova685e262007-01-29 13:19:54 -0800258 cur_index = locked_page->index;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800259 end = count + beg;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300260 last_index = end >> (PAGE_SHIFT - inode->i_blkbits);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800261 for (i = beg; i < end; i = (i | mask) + 1) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300262 index = i >> (PAGE_SHIFT - inode->i_blkbits);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700263
264 if (likely(cur_index != index)) {
265 page = ufs_get_locked_page(mapping, index);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800266 if (!page)/* it was truncated */
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700267 continue;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800268 if (IS_ERR(page)) {/* or EIO */
Harvey Harrison9746077a72008-04-28 02:16:17 -0700269 ufs_error(inode->i_sb, __func__,
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800270 "read of page %llu failed\n",
271 (unsigned long long)index);
272 continue;
273 }
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700274 } else
275 page = locked_page;
276
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700277 head = page_buffers(page);
278 bh = head;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800279 pos = i & mask;
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800280 for (j = 0; j < pos; ++j)
281 bh = bh->b_this_page;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800282
283
284 if (unlikely(index == last_index))
285 lblock = end & mask;
286 else
287 lblock = blks_per_page;
288
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700289 do {
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800290 if (j >= lblock)
291 break;
292 pos = (i - beg) + j;
293
294 if (!buffer_mapped(bh))
295 map_bh(bh, inode->i_sb, oldb + pos);
296 if (!buffer_uptodate(bh)) {
Mike Christiedfec8a12016-06-05 14:31:44 -0500297 ll_rw_block(REQ_OP_READ, 0, 1, &bh);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800298 wait_on_buffer(bh);
299 if (!buffer_uptodate(bh)) {
Harvey Harrison9746077a72008-04-28 02:16:17 -0700300 ufs_error(inode->i_sb, __func__,
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800301 "read of block failed\n");
302 break;
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800303 }
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700304 }
305
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800306 UFSD(" change from %llu to %llu, pos %u\n",
Andrew Morton9df13032008-03-19 17:01:05 -0700307 (unsigned long long)(pos + oldb),
308 (unsigned long long)(pos + newb), pos);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800309
310 bh->b_blocknr = newb + pos;
311 unmap_underlying_metadata(bh->b_bdev,
312 bh->b_blocknr);
313 mark_buffer_dirty(bh);
314 ++j;
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700315 bh = bh->b_this_page;
316 } while (bh != head);
317
Evgeniy Dushistov10e5dce2006-07-01 04:36:24 -0700318 if (likely(cur_index != index))
319 ufs_put_locked_page(page);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700320 }
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700321 UFSD("EXIT\n");
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700322}
323
Evgeniy Dushistovd63b7092007-01-05 16:37:04 -0800324static void ufs_clear_frags(struct inode *inode, sector_t beg, unsigned int n,
325 int sync)
326{
327 struct buffer_head *bh;
328 sector_t end = beg + n;
329
330 for (; beg < end; ++beg) {
331 bh = sb_getblk(inode->i_sb, beg);
332 lock_buffer(bh);
333 memset(bh->b_data, 0, inode->i_sb->s_blocksize);
334 set_buffer_uptodate(bh);
335 mark_buffer_dirty(bh);
336 unlock_buffer(bh);
337 if (IS_SYNC(inode) || sync)
338 sync_dirty_buffer(bh);
339 brelse(bh);
340 }
341}
342
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800343u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,
344 u64 goal, unsigned count, int *err,
345 struct page *locked_page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700346{
347 struct super_block * sb;
348 struct ufs_sb_private_info * uspi;
349 struct ufs_super_block_first * usb1;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800350 unsigned cgno, oldcount, newcount;
351 u64 tmp, request, result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700352
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800353 UFSD("ENTER, ino %lu, fragment %llu, goal %llu, count %u\n",
354 inode->i_ino, (unsigned long long)fragment,
355 (unsigned long long)goal, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356
357 sb = inode->i_sb;
358 uspi = UFS_SB(sb)->s_uspi;
Evgeniy7b4ee732006-01-14 11:42:06 +0300359 usb1 = ubh_get_usb_first(uspi);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 *err = -ENOSPC;
361
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000362 mutex_lock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800363 tmp = ufs_data_ptr_to_cpu(sb, p);
364
Linus Torvalds1da177e2005-04-16 15:20:36 -0700365 if (count + ufs_fragnum(fragment) > uspi->s_fpb) {
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800366 ufs_warning(sb, "ufs_new_fragments", "internal warning"
367 " fragment %llu, count %u",
368 (unsigned long long)fragment, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700369 count = uspi->s_fpb - ufs_fragnum(fragment);
370 }
371 oldcount = ufs_fragnum (fragment);
372 newcount = oldcount + count;
373
374 /*
375 * Somebody else has just allocated our fragments
376 */
377 if (oldcount) {
378 if (!tmp) {
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800379 ufs_error(sb, "ufs_new_fragments", "internal error, "
380 "fragment %llu, tmp %llu\n",
381 (unsigned long long)fragment,
382 (unsigned long long)tmp);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000383 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800384 return INVBLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700385 }
386 if (fragment < UFS_I(inode)->i_lastfrag) {
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700387 UFSD("EXIT (ALREADY ALLOCATED)\n");
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000388 mutex_unlock(&UFS_SB(sb)->s_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700389 return 0;
390 }
391 }
392 else {
393 if (tmp) {
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700394 UFSD("EXIT (ALREADY ALLOCATED)\n");
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000395 mutex_unlock(&UFS_SB(sb)->s_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700396 return 0;
397 }
398 }
399
400 /*
401 * There is not enough space for user on the device
402 */
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700403 if (!capable(CAP_SYS_RESOURCE) && ufs_freespace(uspi, UFS_MINFREE) <= 0) {
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000404 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700405 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700406 return 0;
407 }
408
409 if (goal >= uspi->s_size)
410 goal = 0;
411 if (goal == 0)
412 cgno = ufs_inotocg (inode->i_ino);
413 else
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800414 cgno = ufs_dtog(uspi, goal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700415
416 /*
417 * allocate new fragment
418 */
419 if (oldcount == 0) {
420 result = ufs_alloc_fragments (inode, cgno, goal, count, err);
421 if (result) {
Al Virobd2843f2015-09-09 10:16:39 +0100422 ufs_clear_frags(inode, result + oldcount,
423 newcount - oldcount, locked_page != NULL);
Al Viro724bb092015-06-17 12:02:56 -0400424 write_seqlock(&UFS_I(inode)->meta_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800425 ufs_cpu_to_data_ptr(sb, p, result);
Al Viro724bb092015-06-17 12:02:56 -0400426 write_sequnlock(&UFS_I(inode)->meta_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 *err = 0;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800428 UFS_I(inode)->i_lastfrag =
Dan Carpenter1d582722011-05-26 16:25:12 -0700429 max(UFS_I(inode)->i_lastfrag, fragment + count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700430 }
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000431 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800432 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 return result;
434 }
435
436 /*
437 * resize block
438 */
Fabian Frederick45641c82014-06-06 14:36:33 -0700439 result = ufs_add_fragments(inode, tmp, oldcount, newcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700440 if (result) {
441 *err = 0;
Dan Carpenter1d582722011-05-26 16:25:12 -0700442 UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag,
443 fragment + count);
Evgeniy Dushistovd63b7092007-01-05 16:37:04 -0800444 ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
445 locked_page != NULL);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000446 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800447 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700448 return result;
449 }
450
451 /*
452 * allocate new block and move data
453 */
454 switch (fs32_to_cpu(sb, usb1->fs_optim)) {
455 case UFS_OPTSPACE:
456 request = newcount;
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700457 if (uspi->s_minfree < 5 || uspi->cs_total.cs_nffree
458 > uspi->s_dsize * uspi->s_minfree / (2 * 100))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 break;
460 usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
461 break;
462 default:
463 usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
464
465 case UFS_OPTTIME:
466 request = uspi->s_fpb;
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700467 if (uspi->cs_total.cs_nffree < uspi->s_dsize *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 (uspi->s_minfree - 2) / 100)
469 break;
470 usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
471 break;
472 }
473 result = ufs_alloc_fragments (inode, cgno, goal, request, err);
474 if (result) {
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800475 ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
476 locked_page != NULL);
Evgeniy Dushistov4b25a372007-03-16 13:38:09 -0800477 ufs_change_blocknr(inode, fragment - oldcount, oldcount,
478 uspi->s_sbbase + tmp,
479 uspi->s_sbbase + result, locked_page);
Al Viro724bb092015-06-17 12:02:56 -0400480 write_seqlock(&UFS_I(inode)->meta_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800481 ufs_cpu_to_data_ptr(sb, p, result);
Al Viro724bb092015-06-17 12:02:56 -0400482 write_sequnlock(&UFS_I(inode)->meta_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700483 *err = 0;
Dan Carpenter1d582722011-05-26 16:25:12 -0700484 UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag,
485 fragment + count);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000486 mutex_unlock(&UFS_SB(sb)->s_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700487 if (newcount < request)
488 ufs_free_fragments (inode, result + newcount, request - newcount);
489 ufs_free_fragments (inode, tmp, oldcount);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800490 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 return result;
492 }
493
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000494 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700495 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700496 return 0;
497}
498
Al Viroaed005f2017-06-08 21:15:03 -0400499static bool try_add_frags(struct inode *inode, unsigned frags)
500{
501 unsigned size = frags * i_blocksize(inode);
502 spin_lock(&inode->i_lock);
503 __inode_add_bytes(inode, size);
504 if (unlikely((u32)inode->i_blocks != inode->i_blocks)) {
505 __inode_sub_bytes(inode, size);
506 spin_unlock(&inode->i_lock);
507 return false;
508 }
509 spin_unlock(&inode->i_lock);
510 return true;
511}
512
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800513static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
Fabian Frederick45641c82014-06-06 14:36:33 -0700514 unsigned oldcount, unsigned newcount)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700515{
516 struct super_block * sb;
517 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700518 struct ufs_cg_private_info * ucpi;
519 struct ufs_cylinder_group * ucg;
520 unsigned cgno, fragno, fragoff, count, fragsize, i;
521
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800522 UFSD("ENTER, fragment %llu, oldcount %u, newcount %u\n",
523 (unsigned long long)fragment, oldcount, newcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524
525 sb = inode->i_sb;
526 uspi = UFS_SB(sb)->s_uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527 count = newcount - oldcount;
528
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800529 cgno = ufs_dtog(uspi, fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700530 if (fs32_to_cpu(sb, UFS_SB(sb)->fs_cs(cgno).cs_nffree) < count)
531 return 0;
532 if ((ufs_fragnum (fragment) + newcount) > uspi->s_fpb)
533 return 0;
534 ucpi = ufs_load_cylinder (sb, cgno);
535 if (!ucpi)
536 return 0;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700537 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700538 if (!ufs_cg_chkmagic(sb, ucg)) {
539 ufs_panic (sb, "ufs_add_fragments",
540 "internal error, bad magic number on cg %u", cgno);
541 return 0;
542 }
543
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800544 fragno = ufs_dtogd(uspi, fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700545 fragoff = ufs_fragnum (fragno);
546 for (i = oldcount; i < newcount; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700547 if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700548 return 0;
Al Viroaed005f2017-06-08 21:15:03 -0400549
550 if (!try_add_frags(inode, count))
551 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552 /*
553 * Block can be extended
554 */
555 ucg->cg_time = cpu_to_fs32(sb, get_seconds());
556 for (i = newcount; i < (uspi->s_fpb - fragoff); i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700557 if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700558 break;
559 fragsize = i - oldcount;
560 if (!fs32_to_cpu(sb, ucg->cg_frsum[fragsize]))
561 ufs_panic (sb, "ufs_add_fragments",
562 "internal error or corrupted bitmap on cg %u", cgno);
563 fs32_sub(sb, &ucg->cg_frsum[fragsize], 1);
564 if (fragsize != count)
565 fs32_add(sb, &ucg->cg_frsum[fragsize - count], 1);
566 for (i = oldcount; i < newcount; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700567 ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568
569 fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
570 fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700571 uspi->cs_total.cs_nffree -= count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700572
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700573 ubh_mark_buffer_dirty (USPI_UBH(uspi));
574 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Christoph Hellwig9cb569d2010-08-11 17:06:24 +0200575 if (sb->s_flags & MS_SYNCHRONOUS)
576 ubh_sync_block(UCPI_UBH(ucpi));
Artem Bityutskiy9e9ad5f2012-07-12 16:28:08 +0300577 ufs_mark_sb_dirty(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700578
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800579 UFSD("EXIT, fragment %llu\n", (unsigned long long)fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
581 return fragment;
582}
583
584#define UFS_TEST_FREE_SPACE_CG \
585 ucg = (struct ufs_cylinder_group *) UFS_SB(sb)->s_ucg[cgno]->b_data; \
586 if (fs32_to_cpu(sb, ucg->cg_cs.cs_nbfree)) \
587 goto cg_found; \
588 for (k = count; k < uspi->s_fpb; k++) \
589 if (fs32_to_cpu(sb, ucg->cg_frsum[k])) \
590 goto cg_found;
591
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800592static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno,
593 u64 goal, unsigned count, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700594{
595 struct super_block * sb;
596 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700597 struct ufs_cg_private_info * ucpi;
598 struct ufs_cylinder_group * ucg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800599 unsigned oldcg, i, j, k, allocsize;
600 u64 result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700601
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800602 UFSD("ENTER, ino %lu, cgno %u, goal %llu, count %u\n",
603 inode->i_ino, cgno, (unsigned long long)goal, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700604
605 sb = inode->i_sb;
606 uspi = UFS_SB(sb)->s_uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700607 oldcg = cgno;
608
609 /*
610 * 1. searching on preferred cylinder group
611 */
612 UFS_TEST_FREE_SPACE_CG
613
614 /*
615 * 2. quadratic rehash
616 */
617 for (j = 1; j < uspi->s_ncg; j *= 2) {
618 cgno += j;
619 if (cgno >= uspi->s_ncg)
620 cgno -= uspi->s_ncg;
621 UFS_TEST_FREE_SPACE_CG
622 }
623
624 /*
625 * 3. brute force search
626 * We start at i = 2 ( 0 is checked at 1.step, 1 at 2.step )
627 */
628 cgno = (oldcg + 1) % uspi->s_ncg;
629 for (j = 2; j < uspi->s_ncg; j++) {
630 cgno++;
631 if (cgno >= uspi->s_ncg)
632 cgno = 0;
633 UFS_TEST_FREE_SPACE_CG
634 }
635
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700636 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700637 return 0;
638
639cg_found:
640 ucpi = ufs_load_cylinder (sb, cgno);
641 if (!ucpi)
642 return 0;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700643 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700644 if (!ufs_cg_chkmagic(sb, ucg))
645 ufs_panic (sb, "ufs_alloc_fragments",
646 "internal error, bad magic number on cg %u", cgno);
647 ucg->cg_time = cpu_to_fs32(sb, get_seconds());
648
649 if (count == uspi->s_fpb) {
650 result = ufs_alloccg_block (inode, ucpi, goal, err);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800651 if (result == INVBLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700652 return 0;
653 goto succed;
654 }
655
656 for (allocsize = count; allocsize < uspi->s_fpb; allocsize++)
657 if (fs32_to_cpu(sb, ucg->cg_frsum[allocsize]) != 0)
658 break;
659
660 if (allocsize == uspi->s_fpb) {
661 result = ufs_alloccg_block (inode, ucpi, goal, err);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800662 if (result == INVBLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663 return 0;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800664 goal = ufs_dtogd(uspi, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 for (i = count; i < uspi->s_fpb; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700666 ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 i = uspi->s_fpb - count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700668
Al Viroaed005f2017-06-08 21:15:03 -0400669 inode_sub_bytes(inode, i << uspi->s_fshift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700671 uspi->cs_total.cs_nffree += i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i);
673 fs32_add(sb, &ucg->cg_frsum[i], 1);
674 goto succed;
675 }
676
677 result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800678 if (result == INVBLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679 return 0;
Al Viroaed005f2017-06-08 21:15:03 -0400680 if (!try_add_frags(inode, count))
681 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 for (i = 0; i < count; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700683 ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684
685 fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700686 uspi->cs_total.cs_nffree -= count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700687 fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
688 fs32_sub(sb, &ucg->cg_frsum[allocsize], 1);
689
690 if (count != allocsize)
691 fs32_add(sb, &ucg->cg_frsum[allocsize - count], 1);
692
693succed:
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700694 ubh_mark_buffer_dirty (USPI_UBH(uspi));
695 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Christoph Hellwig9cb569d2010-08-11 17:06:24 +0200696 if (sb->s_flags & MS_SYNCHRONOUS)
697 ubh_sync_block(UCPI_UBH(ucpi));
Artem Bityutskiy9e9ad5f2012-07-12 16:28:08 +0300698 ufs_mark_sb_dirty(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699
700 result += cgno * uspi->s_fpg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800701 UFSD("EXIT3, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700702 return result;
703}
704
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800705static u64 ufs_alloccg_block(struct inode *inode,
706 struct ufs_cg_private_info *ucpi,
707 u64 goal, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708{
709 struct super_block * sb;
710 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700711 struct ufs_cylinder_group * ucg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800712 u64 result, blkno;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800714 UFSD("ENTER, goal %llu\n", (unsigned long long)goal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
716 sb = inode->i_sb;
717 uspi = UFS_SB(sb)->s_uspi;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700718 ucg = ubh_get_ucg(UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719
720 if (goal == 0) {
721 goal = ucpi->c_rotor;
722 goto norot;
723 }
724 goal = ufs_blknum (goal);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800725 goal = ufs_dtogd(uspi, goal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726
727 /*
728 * If the requested block is available, use it.
729 */
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700730 if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, ufs_fragstoblks(goal))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731 result = goal;
732 goto gotit;
733 }
734
735norot:
736 result = ufs_bitmap_search (sb, ucpi, goal, uspi->s_fpb);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800737 if (result == INVBLOCK)
738 return INVBLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700739 ucpi->c_rotor = result;
740gotit:
Al Viroaed005f2017-06-08 21:15:03 -0400741 if (!try_add_frags(inode, uspi->s_fpb))
742 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700743 blkno = ufs_fragstoblks(result);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700744 ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
746 ufs_clusteracct (sb, ucpi, blkno, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747
748 fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700749 uspi->cs_total.cs_nbfree--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700750 fs32_sub(sb, &UFS_SB(sb)->fs_cs(ucpi->c_cgx).cs_nbfree, 1);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800751
752 if (uspi->fs_magic != UFS2_MAGIC) {
753 unsigned cylno = ufs_cbtocylno((unsigned)result);
754
755 fs16_sub(sb, &ubh_cg_blks(ucpi, cylno,
756 ufs_cbtorpos((unsigned)result)), 1);
757 fs32_sub(sb, &ubh_cg_blktot(ucpi, cylno), 1);
758 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800760 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
762 return result;
763}
764
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700765static unsigned ubh_scanc(struct ufs_sb_private_info *uspi,
766 struct ufs_buffer_head *ubh,
767 unsigned begin, unsigned size,
768 unsigned char *table, unsigned char mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700769{
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700770 unsigned rest, offset;
771 unsigned char *cp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700772
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700774 offset = begin & ~uspi->s_fmask;
775 begin >>= uspi->s_fshift;
776 for (;;) {
777 if ((offset + size) < uspi->s_fsize)
778 rest = size;
779 else
780 rest = uspi->s_fsize - offset;
781 size -= rest;
782 cp = ubh->bh[begin]->b_data + offset;
783 while ((table[*cp++] & mask) == 0 && --rest)
784 ;
785 if (rest || !size)
786 break;
787 begin++;
788 offset = 0;
789 }
790 return (size + rest);
791}
792
793/*
794 * Find a block of the specified size in the specified cylinder group.
795 * @sp: pointer to super block
796 * @ucpi: pointer to cylinder group info
797 * @goal: near which block we want find new one
798 * @count: specified size
799 */
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800800static u64 ufs_bitmap_search(struct super_block *sb,
801 struct ufs_cg_private_info *ucpi,
802 u64 goal, unsigned count)
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700803{
804 /*
805 * Bit patterns for identifying fragments in the block map
806 * used as ((map & mask_arr) == want_arr)
807 */
808 static const int mask_arr[9] = {
809 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
810 };
811 static const int want_arr[9] = {
812 0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
813 };
814 struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800815 unsigned start, length, loc;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700816 unsigned pos, want, blockmap, mask, end;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800817 u64 result;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700818
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800819 UFSD("ENTER, cg %u, goal %llu, count %u\n", ucpi->c_cgx,
820 (unsigned long long)goal, count);
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700821
Linus Torvalds1da177e2005-04-16 15:20:36 -0700822 if (goal)
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800823 start = ufs_dtogd(uspi, goal) >> 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 else
825 start = ucpi->c_frotor >> 3;
826
827 length = ((uspi->s_fpg + 7) >> 3) - start;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700828 loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff + start, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
830 1 << (count - 1 + (uspi->s_fpb & 7)));
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700831 if (loc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832 length = start + 1;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700833 loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, length,
834 (uspi->s_fpb == 8) ? ufs_fragtable_8fpb :
835 ufs_fragtable_other,
836 1 << (count - 1 + (uspi->s_fpb & 7)));
837 if (loc == 0) {
838 ufs_error(sb, "ufs_bitmap_search",
839 "bitmap corrupted on cg %u, start %u,"
840 " length %u, count %u, freeoff %u\n",
841 ucpi->c_cgx, start, length, count,
842 ucpi->c_freeoff);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800843 return INVBLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700844 }
845 start = 0;
846 }
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700847 result = (start + length - loc) << 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848 ucpi->c_frotor = result;
849
850 /*
851 * found the byte in the map
852 */
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700853
854 for (end = result + 8; result < end; result += uspi->s_fpb) {
855 blockmap = ubh_blkmap(UCPI_UBH(ucpi), ucpi->c_freeoff, result);
856 blockmap <<= 1;
857 mask = mask_arr[count];
858 want = want_arr[count];
859 for (pos = 0; pos <= uspi->s_fpb - count; pos++) {
860 if ((blockmap & mask) == want) {
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800861 UFSD("EXIT, result %llu\n",
862 (unsigned long long)result);
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700863 return result + pos;
864 }
865 mask <<= 1;
866 want <<= 1;
867 }
868 }
869
870 ufs_error(sb, "ufs_bitmap_search", "block not in map on cg %u\n",
871 ucpi->c_cgx);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700872 UFSD("EXIT (FAILED)\n");
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800873 return INVBLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700874}
875
876static void ufs_clusteracct(struct super_block * sb,
877 struct ufs_cg_private_info * ucpi, unsigned blkno, int cnt)
878{
879 struct ufs_sb_private_info * uspi;
880 int i, start, end, forw, back;
881
882 uspi = UFS_SB(sb)->s_uspi;
883 if (uspi->s_contigsumsize <= 0)
884 return;
885
886 if (cnt > 0)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700887 ubh_setbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700888 else
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700889 ubh_clrbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
891 /*
892 * Find the size of the cluster going forward.
893 */
894 start = blkno + 1;
895 end = start + uspi->s_contigsumsize;
896 if ( end >= ucpi->c_nclusterblks)
897 end = ucpi->c_nclusterblks;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700898 i = ubh_find_next_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, end, start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700899 if (i > end)
900 i = end;
901 forw = i - start;
902
903 /*
904 * Find the size of the cluster going backward.
905 */
906 start = blkno - 1;
907 end = start - uspi->s_contigsumsize;
908 if (end < 0 )
909 end = -1;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700910 i = ubh_find_last_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, start, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700911 if ( i < end)
912 i = end;
913 back = start - i;
914
915 /*
916 * Account for old cluster and the possibly new forward and
917 * back clusters.
918 */
919 i = back + forw + 1;
920 if (i > uspi->s_contigsumsize)
921 i = uspi->s_contigsumsize;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700922 fs32_add(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (i << 2)), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923 if (back > 0)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700924 fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (back << 2)), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 if (forw > 0)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700926 fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (forw << 2)), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927}
928
929
930static unsigned char ufs_fragtable_8fpb[] = {
931 0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
932 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
933 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
934 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20,
935 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
936 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
937 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
938 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x08, 0x09, 0x09, 0x0A, 0x10, 0x11, 0x20, 0x40,
939 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
940 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
941 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
942 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21,
943 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
944 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0A, 0x12,
945 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0C,
946 0x08, 0x09, 0x09, 0x0A, 0x09, 0x09, 0x0A, 0x0C, 0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80,
947};
948
949static unsigned char ufs_fragtable_other[] = {
950 0x00, 0x16, 0x16, 0x2A, 0x16, 0x16, 0x26, 0x4E, 0x16, 0x16, 0x16, 0x3E, 0x2A, 0x3E, 0x4E, 0x8A,
951 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
952 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
953 0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
954 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
955 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
956 0x26, 0x36, 0x36, 0x2E, 0x36, 0x36, 0x26, 0x6E, 0x36, 0x36, 0x36, 0x3E, 0x2E, 0x3E, 0x6E, 0xAE,
957 0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
958 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
959 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
960 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
961 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
962 0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
963 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
964 0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
965 0x8A, 0x9E, 0x9E, 0xAA, 0x9E, 0x9E, 0xAE, 0xCE, 0x9E, 0x9E, 0x9E, 0xBE, 0xAA, 0xBE, 0xCE, 0x8A,
966};