blob: 52d1ef415f6fc73d25ff17816a57a9851409a8b0 [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 }
Al Viroeb315d22017-06-08 21:15:03 -040085
86 inode_sub_bytes(inode, count << uspi->s_fshift);
Linus Torvalds1da177e2005-04-16 15:20:36 -070087 fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -070088 uspi->cs_total.cs_nffree += count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070089 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070090 blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -070091 ufs_fragacct(sb, blkmap, ucg->cg_frsum, 1);
92
93 /*
94 * Trying to reassemble free fragments into block
95 */
96 blkno = ufs_fragstoblks (bbase);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070097 if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070098 fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -070099 uspi->cs_total.cs_nffree -= uspi->s_fpb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700100 fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, uspi->s_fpb);
101 if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
102 ufs_clusteracct (sb, ucpi, blkno, 1);
103 fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700104 uspi->cs_total.cs_nbfree++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700105 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800106 if (uspi->fs_magic != UFS2_MAGIC) {
107 unsigned cylno = ufs_cbtocylno (bbase);
108
109 fs16_add(sb, &ubh_cg_blks(ucpi, cylno,
110 ufs_cbtorpos(bbase)), 1);
111 fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
112 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700113 }
114
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700115 ubh_mark_buffer_dirty (USPI_UBH(uspi));
116 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Christoph Hellwig9cb569d2010-08-11 17:06:24 +0200117 if (sb->s_flags & MS_SYNCHRONOUS)
118 ubh_sync_block(UCPI_UBH(ucpi));
Artem Bityutskiy9e9ad5f2012-07-12 16:28:08 +0300119 ufs_mark_sb_dirty(sb);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000120
121 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700122 UFSD("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700123 return;
124
125failed:
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000126 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700127 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700128 return;
129}
130
131/*
132 * Free 'count' fragments from fragment number 'fragment' (free whole blocks)
133 */
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800134void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count)
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700135{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700136 struct super_block * sb;
137 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 struct ufs_cg_private_info * ucpi;
139 struct ufs_cylinder_group * ucg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800140 unsigned overflow, cgno, bit, end_bit, i;
141 u64 blkno;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700142
143 sb = inode->i_sb;
144 uspi = UFS_SB(sb)->s_uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700145
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800146 UFSD("ENTER, fragment %llu, count %u\n",
147 (unsigned long long)fragment, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700148
149 if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) {
150 ufs_error (sb, "ufs_free_blocks", "internal error, "
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800151 "fragment %llu, count %u\n",
152 (unsigned long long)fragment, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700153 goto failed;
154 }
155
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000156 mutex_lock(&UFS_SB(sb)->s_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700157
158do_more:
159 overflow = 0;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800160 cgno = ufs_dtog(uspi, fragment);
161 bit = ufs_dtogd(uspi, fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162 if (cgno >= uspi->s_ncg) {
163 ufs_panic (sb, "ufs_free_blocks", "freeing blocks are outside device");
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700164 goto failed_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165 }
166 end_bit = bit + count;
167 if (end_bit > uspi->s_fpg) {
168 overflow = bit + count - uspi->s_fpg;
169 count -= overflow;
170 end_bit -= overflow;
171 }
172
173 ucpi = ufs_load_cylinder (sb, cgno);
174 if (!ucpi)
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700175 goto failed_unlock;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700176 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 if (!ufs_cg_chkmagic(sb, ucg)) {
178 ufs_panic (sb, "ufs_free_blocks", "internal error, bad magic number on cg %u", cgno);
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700179 goto failed_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180 }
181
182 for (i = bit; i < end_bit; i += uspi->s_fpb) {
183 blkno = ufs_fragstoblks(i);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700184 if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700185 ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
186 }
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700187 ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
Al Viroeb315d22017-06-08 21:15:03 -0400188 inode_sub_bytes(inode, uspi->s_fpb << uspi->s_fshift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700189 if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
190 ufs_clusteracct (sb, ucpi, blkno, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700191
192 fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700193 uspi->cs_total.cs_nbfree++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700194 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800195
196 if (uspi->fs_magic != UFS2_MAGIC) {
197 unsigned cylno = ufs_cbtocylno(i);
198
199 fs16_add(sb, &ubh_cg_blks(ucpi, cylno,
200 ufs_cbtorpos(i)), 1);
201 fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
202 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700203 }
204
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700205 ubh_mark_buffer_dirty (USPI_UBH(uspi));
206 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Christoph Hellwig9cb569d2010-08-11 17:06:24 +0200207 if (sb->s_flags & MS_SYNCHRONOUS)
208 ubh_sync_block(UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209
210 if (overflow) {
211 fragment += count;
212 count = overflow;
213 goto do_more;
214 }
215
Artem Bityutskiy9e9ad5f2012-07-12 16:28:08 +0300216 ufs_mark_sb_dirty(sb);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000217 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700218 UFSD("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700219 return;
220
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700221failed_unlock:
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000222 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700223failed:
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700224 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700225 return;
226}
227
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700228/*
229 * Modify inode page cache in such way:
230 * have - blocks with b_blocknr equal to oldb...oldb+count-1
231 * get - blocks with b_blocknr equal to newb...newb+count-1
232 * also we suppose that oldb...oldb+count-1 blocks
233 * situated at the end of file.
234 *
235 * We can come here from ufs_writepage or ufs_prepare_write,
236 * locked_page is argument of these functions, so we already lock it.
237 */
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800238static void ufs_change_blocknr(struct inode *inode, sector_t beg,
239 unsigned int count, sector_t oldb,
240 sector_t newb, struct page *locked_page)
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700241{
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800242 const unsigned blks_per_page =
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300243 1 << (PAGE_SHIFT - inode->i_blkbits);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800244 const unsigned mask = blks_per_page - 1;
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800245 struct address_space * const mapping = inode->i_mapping;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800246 pgoff_t index, cur_index, last_index;
247 unsigned pos, j, lblock;
248 sector_t end, i;
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700249 struct page *page;
250 struct buffer_head *head, *bh;
251
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800252 UFSD("ENTER, ino %lu, count %u, oldb %llu, newb %llu\n",
253 inode->i_ino, count,
254 (unsigned long long)oldb, (unsigned long long)newb);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700255
Evgeniy Dushistova685e262007-01-29 13:19:54 -0800256 BUG_ON(!locked_page);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700257 BUG_ON(!PageLocked(locked_page));
258
Evgeniy Dushistova685e262007-01-29 13:19:54 -0800259 cur_index = locked_page->index;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800260 end = count + beg;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300261 last_index = end >> (PAGE_SHIFT - inode->i_blkbits);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800262 for (i = beg; i < end; i = (i | mask) + 1) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300263 index = i >> (PAGE_SHIFT - inode->i_blkbits);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700264
265 if (likely(cur_index != index)) {
266 page = ufs_get_locked_page(mapping, index);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800267 if (!page)/* it was truncated */
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700268 continue;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800269 if (IS_ERR(page)) {/* or EIO */
Harvey Harrison9746077a72008-04-28 02:16:17 -0700270 ufs_error(inode->i_sb, __func__,
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800271 "read of page %llu failed\n",
272 (unsigned long long)index);
273 continue;
274 }
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700275 } else
276 page = locked_page;
277
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700278 head = page_buffers(page);
279 bh = head;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800280 pos = i & mask;
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800281 for (j = 0; j < pos; ++j)
282 bh = bh->b_this_page;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800283
284
285 if (unlikely(index == last_index))
286 lblock = end & mask;
287 else
288 lblock = blks_per_page;
289
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700290 do {
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800291 if (j >= lblock)
292 break;
293 pos = (i - beg) + j;
294
295 if (!buffer_mapped(bh))
296 map_bh(bh, inode->i_sb, oldb + pos);
297 if (!buffer_uptodate(bh)) {
Mike Christiedfec8a12016-06-05 14:31:44 -0500298 ll_rw_block(REQ_OP_READ, 0, 1, &bh);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800299 wait_on_buffer(bh);
300 if (!buffer_uptodate(bh)) {
Harvey Harrison9746077a72008-04-28 02:16:17 -0700301 ufs_error(inode->i_sb, __func__,
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800302 "read of block failed\n");
303 break;
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800304 }
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700305 }
306
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800307 UFSD(" change from %llu to %llu, pos %u\n",
Andrew Morton9df13032008-03-19 17:01:05 -0700308 (unsigned long long)(pos + oldb),
309 (unsigned long long)(pos + newb), pos);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800310
311 bh->b_blocknr = newb + pos;
Jan Karae64855c2016-11-04 18:08:15 +0100312 clean_bdev_bh_alias(bh);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800313 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 */
Al Virob451cec2017-06-14 15:41:17 -0400403 if (unlikely(ufs_freespace(uspi, uspi->s_minfree) <= 0)) {
404 if (!capable(CAP_SYS_RESOURCE)) {
405 mutex_unlock(&UFS_SB(sb)->s_lock);
406 UFSD("EXIT (FAILED)\n");
407 return 0;
408 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700409 }
410
411 if (goal >= uspi->s_size)
412 goal = 0;
413 if (goal == 0)
414 cgno = ufs_inotocg (inode->i_ino);
415 else
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800416 cgno = ufs_dtog(uspi, goal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417
418 /*
419 * allocate new fragment
420 */
421 if (oldcount == 0) {
422 result = ufs_alloc_fragments (inode, cgno, goal, count, err);
423 if (result) {
Al Virobd2843f2015-09-09 10:16:39 +0100424 ufs_clear_frags(inode, result + oldcount,
425 newcount - oldcount, locked_page != NULL);
Al Viro724bb092015-06-17 12:02:56 -0400426 write_seqlock(&UFS_I(inode)->meta_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800427 ufs_cpu_to_data_ptr(sb, p, result);
Al Viro724bb092015-06-17 12:02:56 -0400428 write_sequnlock(&UFS_I(inode)->meta_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700429 *err = 0;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800430 UFS_I(inode)->i_lastfrag =
Dan Carpenter1d582722011-05-26 16:25:12 -0700431 max(UFS_I(inode)->i_lastfrag, fragment + count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700432 }
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000433 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800434 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700435 return result;
436 }
437
438 /*
439 * resize block
440 */
Fabian Frederick45641c82014-06-06 14:36:33 -0700441 result = ufs_add_fragments(inode, tmp, oldcount, newcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442 if (result) {
443 *err = 0;
Dan Carpenter1d582722011-05-26 16:25:12 -0700444 UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag,
445 fragment + count);
Evgeniy Dushistovd63b7092007-01-05 16:37:04 -0800446 ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
447 locked_page != NULL);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000448 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800449 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700450 return result;
451 }
452
453 /*
454 * allocate new block and move data
455 */
456 switch (fs32_to_cpu(sb, usb1->fs_optim)) {
457 case UFS_OPTSPACE:
458 request = newcount;
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700459 if (uspi->s_minfree < 5 || uspi->cs_total.cs_nffree
460 > uspi->s_dsize * uspi->s_minfree / (2 * 100))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 break;
462 usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
463 break;
464 default:
465 usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
466
467 case UFS_OPTTIME:
468 request = uspi->s_fpb;
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700469 if (uspi->cs_total.cs_nffree < uspi->s_dsize *
Linus Torvalds1da177e2005-04-16 15:20:36 -0700470 (uspi->s_minfree - 2) / 100)
471 break;
472 usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
473 break;
474 }
475 result = ufs_alloc_fragments (inode, cgno, goal, request, err);
476 if (result) {
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800477 ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
478 locked_page != NULL);
Evgeniy Dushistov4b25a372007-03-16 13:38:09 -0800479 ufs_change_blocknr(inode, fragment - oldcount, oldcount,
480 uspi->s_sbbase + tmp,
481 uspi->s_sbbase + result, locked_page);
Al Viro724bb092015-06-17 12:02:56 -0400482 write_seqlock(&UFS_I(inode)->meta_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800483 ufs_cpu_to_data_ptr(sb, p, result);
Al Viro724bb092015-06-17 12:02:56 -0400484 write_sequnlock(&UFS_I(inode)->meta_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700485 *err = 0;
Dan Carpenter1d582722011-05-26 16:25:12 -0700486 UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag,
487 fragment + count);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000488 mutex_unlock(&UFS_SB(sb)->s_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700489 if (newcount < request)
490 ufs_free_fragments (inode, result + newcount, request - newcount);
491 ufs_free_fragments (inode, tmp, oldcount);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800492 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 return result;
494 }
495
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000496 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700497 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498 return 0;
499}
500
Al Viroeb315d22017-06-08 21:15:03 -0400501static bool try_add_frags(struct inode *inode, unsigned frags)
502{
503 unsigned size = frags * i_blocksize(inode);
504 spin_lock(&inode->i_lock);
505 __inode_add_bytes(inode, size);
506 if (unlikely((u32)inode->i_blocks != inode->i_blocks)) {
507 __inode_sub_bytes(inode, size);
508 spin_unlock(&inode->i_lock);
509 return false;
510 }
511 spin_unlock(&inode->i_lock);
512 return true;
513}
514
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800515static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
Fabian Frederick45641c82014-06-06 14:36:33 -0700516 unsigned oldcount, unsigned newcount)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517{
518 struct super_block * sb;
519 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700520 struct ufs_cg_private_info * ucpi;
521 struct ufs_cylinder_group * ucg;
522 unsigned cgno, fragno, fragoff, count, fragsize, i;
523
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800524 UFSD("ENTER, fragment %llu, oldcount %u, newcount %u\n",
525 (unsigned long long)fragment, oldcount, newcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526
527 sb = inode->i_sb;
528 uspi = UFS_SB(sb)->s_uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529 count = newcount - oldcount;
530
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800531 cgno = ufs_dtog(uspi, fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700532 if (fs32_to_cpu(sb, UFS_SB(sb)->fs_cs(cgno).cs_nffree) < count)
533 return 0;
534 if ((ufs_fragnum (fragment) + newcount) > uspi->s_fpb)
535 return 0;
536 ucpi = ufs_load_cylinder (sb, cgno);
537 if (!ucpi)
538 return 0;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700539 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 if (!ufs_cg_chkmagic(sb, ucg)) {
541 ufs_panic (sb, "ufs_add_fragments",
542 "internal error, bad magic number on cg %u", cgno);
543 return 0;
544 }
545
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800546 fragno = ufs_dtogd(uspi, fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 fragoff = ufs_fragnum (fragno);
548 for (i = oldcount; i < newcount; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700549 if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700550 return 0;
Al Viroeb315d22017-06-08 21:15:03 -0400551
552 if (!try_add_frags(inode, count))
553 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700554 /*
555 * Block can be extended
556 */
557 ucg->cg_time = cpu_to_fs32(sb, get_seconds());
558 for (i = newcount; i < (uspi->s_fpb - fragoff); i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700559 if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700560 break;
561 fragsize = i - oldcount;
562 if (!fs32_to_cpu(sb, ucg->cg_frsum[fragsize]))
563 ufs_panic (sb, "ufs_add_fragments",
564 "internal error or corrupted bitmap on cg %u", cgno);
565 fs32_sub(sb, &ucg->cg_frsum[fragsize], 1);
566 if (fragsize != count)
567 fs32_add(sb, &ucg->cg_frsum[fragsize - count], 1);
568 for (i = oldcount; i < newcount; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700569 ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
571 fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
572 fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700573 uspi->cs_total.cs_nffree -= count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700574
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700575 ubh_mark_buffer_dirty (USPI_UBH(uspi));
576 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Christoph Hellwig9cb569d2010-08-11 17:06:24 +0200577 if (sb->s_flags & MS_SYNCHRONOUS)
578 ubh_sync_block(UCPI_UBH(ucpi));
Artem Bityutskiy9e9ad5f2012-07-12 16:28:08 +0300579 ufs_mark_sb_dirty(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700580
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800581 UFSD("EXIT, fragment %llu\n", (unsigned long long)fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700582
583 return fragment;
584}
585
586#define UFS_TEST_FREE_SPACE_CG \
587 ucg = (struct ufs_cylinder_group *) UFS_SB(sb)->s_ucg[cgno]->b_data; \
588 if (fs32_to_cpu(sb, ucg->cg_cs.cs_nbfree)) \
589 goto cg_found; \
590 for (k = count; k < uspi->s_fpb; k++) \
591 if (fs32_to_cpu(sb, ucg->cg_frsum[k])) \
592 goto cg_found;
593
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800594static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno,
595 u64 goal, unsigned count, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596{
597 struct super_block * sb;
598 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599 struct ufs_cg_private_info * ucpi;
600 struct ufs_cylinder_group * ucg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800601 unsigned oldcg, i, j, k, allocsize;
602 u64 result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700603
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800604 UFSD("ENTER, ino %lu, cgno %u, goal %llu, count %u\n",
605 inode->i_ino, cgno, (unsigned long long)goal, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606
607 sb = inode->i_sb;
608 uspi = UFS_SB(sb)->s_uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700609 oldcg = cgno;
610
611 /*
612 * 1. searching on preferred cylinder group
613 */
614 UFS_TEST_FREE_SPACE_CG
615
616 /*
617 * 2. quadratic rehash
618 */
619 for (j = 1; j < uspi->s_ncg; j *= 2) {
620 cgno += j;
621 if (cgno >= uspi->s_ncg)
622 cgno -= uspi->s_ncg;
623 UFS_TEST_FREE_SPACE_CG
624 }
625
626 /*
627 * 3. brute force search
628 * We start at i = 2 ( 0 is checked at 1.step, 1 at 2.step )
629 */
630 cgno = (oldcg + 1) % uspi->s_ncg;
631 for (j = 2; j < uspi->s_ncg; j++) {
632 cgno++;
633 if (cgno >= uspi->s_ncg)
634 cgno = 0;
635 UFS_TEST_FREE_SPACE_CG
636 }
637
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700638 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 return 0;
640
641cg_found:
642 ucpi = ufs_load_cylinder (sb, cgno);
643 if (!ucpi)
644 return 0;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700645 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700646 if (!ufs_cg_chkmagic(sb, ucg))
647 ufs_panic (sb, "ufs_alloc_fragments",
648 "internal error, bad magic number on cg %u", cgno);
649 ucg->cg_time = cpu_to_fs32(sb, get_seconds());
650
651 if (count == uspi->s_fpb) {
652 result = ufs_alloccg_block (inode, ucpi, goal, err);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800653 if (result == INVBLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700654 return 0;
655 goto succed;
656 }
657
658 for (allocsize = count; allocsize < uspi->s_fpb; allocsize++)
659 if (fs32_to_cpu(sb, ucg->cg_frsum[allocsize]) != 0)
660 break;
661
662 if (allocsize == uspi->s_fpb) {
663 result = ufs_alloccg_block (inode, ucpi, goal, err);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800664 if (result == INVBLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 return 0;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800666 goal = ufs_dtogd(uspi, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 for (i = count; i < uspi->s_fpb; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700668 ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 i = uspi->s_fpb - count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670
Al Viroeb315d22017-06-08 21:15:03 -0400671 inode_sub_bytes(inode, i << uspi->s_fshift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700672 fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700673 uspi->cs_total.cs_nffree += i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i);
675 fs32_add(sb, &ucg->cg_frsum[i], 1);
676 goto succed;
677 }
678
679 result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800680 if (result == INVBLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700681 return 0;
Al Viroeb315d22017-06-08 21:15:03 -0400682 if (!try_add_frags(inode, count))
683 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700684 for (i = 0; i < count; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700685 ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700686
687 fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700688 uspi->cs_total.cs_nffree -= count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689 fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
690 fs32_sub(sb, &ucg->cg_frsum[allocsize], 1);
691
692 if (count != allocsize)
693 fs32_add(sb, &ucg->cg_frsum[allocsize - count], 1);
694
695succed:
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700696 ubh_mark_buffer_dirty (USPI_UBH(uspi));
697 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Christoph Hellwig9cb569d2010-08-11 17:06:24 +0200698 if (sb->s_flags & MS_SYNCHRONOUS)
699 ubh_sync_block(UCPI_UBH(ucpi));
Artem Bityutskiy9e9ad5f2012-07-12 16:28:08 +0300700 ufs_mark_sb_dirty(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702 result += cgno * uspi->s_fpg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800703 UFSD("EXIT3, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 return result;
705}
706
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800707static u64 ufs_alloccg_block(struct inode *inode,
708 struct ufs_cg_private_info *ucpi,
709 u64 goal, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710{
711 struct super_block * sb;
712 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700713 struct ufs_cylinder_group * ucg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800714 u64 result, blkno;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700715
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800716 UFSD("ENTER, goal %llu\n", (unsigned long long)goal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717
718 sb = inode->i_sb;
719 uspi = UFS_SB(sb)->s_uspi;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700720 ucg = ubh_get_ucg(UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
722 if (goal == 0) {
723 goal = ucpi->c_rotor;
724 goto norot;
725 }
726 goal = ufs_blknum (goal);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800727 goal = ufs_dtogd(uspi, goal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728
729 /*
730 * If the requested block is available, use it.
731 */
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700732 if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, ufs_fragstoblks(goal))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700733 result = goal;
734 goto gotit;
735 }
736
737norot:
738 result = ufs_bitmap_search (sb, ucpi, goal, uspi->s_fpb);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800739 if (result == INVBLOCK)
740 return INVBLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700741 ucpi->c_rotor = result;
742gotit:
Al Viroeb315d22017-06-08 21:15:03 -0400743 if (!try_add_frags(inode, uspi->s_fpb))
744 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 blkno = ufs_fragstoblks(result);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700746 ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700747 if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
748 ufs_clusteracct (sb, ucpi, blkno, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700749
750 fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700751 uspi->cs_total.cs_nbfree--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700752 fs32_sub(sb, &UFS_SB(sb)->fs_cs(ucpi->c_cgx).cs_nbfree, 1);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800753
754 if (uspi->fs_magic != UFS2_MAGIC) {
755 unsigned cylno = ufs_cbtocylno((unsigned)result);
756
757 fs16_sub(sb, &ubh_cg_blks(ucpi, cylno,
758 ufs_cbtorpos((unsigned)result)), 1);
759 fs32_sub(sb, &ubh_cg_blktot(ucpi, cylno), 1);
760 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700761
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800762 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763
764 return result;
765}
766
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700767static unsigned ubh_scanc(struct ufs_sb_private_info *uspi,
768 struct ufs_buffer_head *ubh,
769 unsigned begin, unsigned size,
770 unsigned char *table, unsigned char mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771{
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700772 unsigned rest, offset;
773 unsigned char *cp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700774
Linus Torvalds1da177e2005-04-16 15:20:36 -0700775
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700776 offset = begin & ~uspi->s_fmask;
777 begin >>= uspi->s_fshift;
778 for (;;) {
779 if ((offset + size) < uspi->s_fsize)
780 rest = size;
781 else
782 rest = uspi->s_fsize - offset;
783 size -= rest;
784 cp = ubh->bh[begin]->b_data + offset;
785 while ((table[*cp++] & mask) == 0 && --rest)
786 ;
787 if (rest || !size)
788 break;
789 begin++;
790 offset = 0;
791 }
792 return (size + rest);
793}
794
795/*
796 * Find a block of the specified size in the specified cylinder group.
797 * @sp: pointer to super block
798 * @ucpi: pointer to cylinder group info
799 * @goal: near which block we want find new one
800 * @count: specified size
801 */
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800802static u64 ufs_bitmap_search(struct super_block *sb,
803 struct ufs_cg_private_info *ucpi,
804 u64 goal, unsigned count)
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700805{
806 /*
807 * Bit patterns for identifying fragments in the block map
808 * used as ((map & mask_arr) == want_arr)
809 */
810 static const int mask_arr[9] = {
811 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
812 };
813 static const int want_arr[9] = {
814 0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
815 };
816 struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800817 unsigned start, length, loc;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700818 unsigned pos, want, blockmap, mask, end;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800819 u64 result;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700820
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800821 UFSD("ENTER, cg %u, goal %llu, count %u\n", ucpi->c_cgx,
822 (unsigned long long)goal, count);
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700823
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 if (goal)
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800825 start = ufs_dtogd(uspi, goal) >> 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700826 else
827 start = ucpi->c_frotor >> 3;
828
829 length = ((uspi->s_fpg + 7) >> 3) - start;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700830 loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff + start, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700831 (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
832 1 << (count - 1 + (uspi->s_fpb & 7)));
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700833 if (loc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700834 length = start + 1;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700835 loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, length,
836 (uspi->s_fpb == 8) ? ufs_fragtable_8fpb :
837 ufs_fragtable_other,
838 1 << (count - 1 + (uspi->s_fpb & 7)));
839 if (loc == 0) {
840 ufs_error(sb, "ufs_bitmap_search",
841 "bitmap corrupted on cg %u, start %u,"
842 " length %u, count %u, freeoff %u\n",
843 ucpi->c_cgx, start, length, count,
844 ucpi->c_freeoff);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800845 return INVBLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846 }
847 start = 0;
848 }
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700849 result = (start + length - loc) << 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 ucpi->c_frotor = result;
851
852 /*
853 * found the byte in the map
854 */
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700855
856 for (end = result + 8; result < end; result += uspi->s_fpb) {
857 blockmap = ubh_blkmap(UCPI_UBH(ucpi), ucpi->c_freeoff, result);
858 blockmap <<= 1;
859 mask = mask_arr[count];
860 want = want_arr[count];
861 for (pos = 0; pos <= uspi->s_fpb - count; pos++) {
862 if ((blockmap & mask) == want) {
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800863 UFSD("EXIT, result %llu\n",
864 (unsigned long long)result);
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700865 return result + pos;
866 }
867 mask <<= 1;
868 want <<= 1;
869 }
870 }
871
872 ufs_error(sb, "ufs_bitmap_search", "block not in map on cg %u\n",
873 ucpi->c_cgx);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700874 UFSD("EXIT (FAILED)\n");
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800875 return INVBLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700876}
877
878static void ufs_clusteracct(struct super_block * sb,
879 struct ufs_cg_private_info * ucpi, unsigned blkno, int cnt)
880{
881 struct ufs_sb_private_info * uspi;
882 int i, start, end, forw, back;
883
884 uspi = UFS_SB(sb)->s_uspi;
885 if (uspi->s_contigsumsize <= 0)
886 return;
887
888 if (cnt > 0)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700889 ubh_setbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890 else
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700891 ubh_clrbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700892
893 /*
894 * Find the size of the cluster going forward.
895 */
896 start = blkno + 1;
897 end = start + uspi->s_contigsumsize;
898 if ( end >= ucpi->c_nclusterblks)
899 end = ucpi->c_nclusterblks;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700900 i = ubh_find_next_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, end, start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700901 if (i > end)
902 i = end;
903 forw = i - start;
904
905 /*
906 * Find the size of the cluster going backward.
907 */
908 start = blkno - 1;
909 end = start - uspi->s_contigsumsize;
910 if (end < 0 )
911 end = -1;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700912 i = ubh_find_last_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, start, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700913 if ( i < end)
914 i = end;
915 back = start - i;
916
917 /*
918 * Account for old cluster and the possibly new forward and
919 * back clusters.
920 */
921 i = back + forw + 1;
922 if (i > uspi->s_contigsumsize)
923 i = uspi->s_contigsumsize;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700924 fs32_add(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (i << 2)), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 if (back > 0)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700926 fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (back << 2)), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 if (forw > 0)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700928 fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (forw << 2)), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929}
930
931
932static unsigned char ufs_fragtable_8fpb[] = {
933 0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
934 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
935 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
936 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20,
937 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
938 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
939 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
940 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x08, 0x09, 0x09, 0x0A, 0x10, 0x11, 0x20, 0x40,
941 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
942 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
943 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
944 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21,
945 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
946 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0A, 0x12,
947 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0C,
948 0x08, 0x09, 0x09, 0x0A, 0x09, 0x09, 0x0A, 0x0C, 0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80,
949};
950
951static unsigned char ufs_fragtable_other[] = {
952 0x00, 0x16, 0x16, 0x2A, 0x16, 0x16, 0x26, 0x4E, 0x16, 0x16, 0x16, 0x3E, 0x2A, 0x3E, 0x4E, 0x8A,
953 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
954 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
955 0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
956 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
957 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
958 0x26, 0x36, 0x36, 0x2E, 0x36, 0x36, 0x26, 0x6E, 0x36, 0x36, 0x36, 0x3E, 0x2E, 0x3E, 0x6E, 0xAE,
959 0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
960 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
961 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
962 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
963 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
964 0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
965 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
966 0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
967 0x8A, 0x9E, 0x9E, 0xAA, 0x9E, 0x9E, 0xAE, 0xCE, 0x9E, 0x9E, 0x9E, 0xBE, 0xAA, 0xBE, 0xCE, 0x8A,
968};