blob: 075d3d9114c8fa961df937fb80d9d8a1cb4eb417 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * linux/fs/ufs/balloc.c
4 *
5 * Copyright (C) 1998
6 * Daniel Pirkl <daniel.pirkl@email.cz>
7 * Charles University, Faculty of Mathematics and Physics
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -08008 *
9 * UFS2 write support Evgeniy Dushistov <dushistov@mail.ru>, 2007
Linus Torvalds1da177e2005-04-16 15:20:36 -070010 */
11
12#include <linux/fs.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/stat.h>
14#include <linux/time.h>
15#include <linux/string.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070016#include <linux/buffer_head.h>
Randy Dunlap16f7e0f2006-01-11 12:17:46 -080017#include <linux/capability.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include <linux/bitops.h>
Christoph Hellwig2f8b5442016-11-01 07:40:13 -060019#include <linux/bio.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070020#include <asm/byteorder.h>
21
Mike Frysingere5420592008-02-08 04:21:31 -080022#include "ufs_fs.h"
Christoph Hellwigbcd6d4e2007-10-16 23:26:51 -070023#include "ufs.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070024#include "swab.h"
25#include "util.h"
26
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080027#define INVBLOCK ((u64)-1L)
28
Fabian Frederick45641c82014-06-06 14:36:33 -070029static u64 ufs_add_fragments(struct inode *, u64, unsigned, unsigned);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080030static u64 ufs_alloc_fragments(struct inode *, unsigned, u64, unsigned, int *);
31static u64 ufs_alloccg_block(struct inode *, struct ufs_cg_private_info *, u64, int *);
32static u64 ufs_bitmap_search (struct super_block *, struct ufs_cg_private_info *, u64, unsigned);
Linus Torvalds1da177e2005-04-16 15:20:36 -070033static unsigned char ufs_fragtable_8fpb[], ufs_fragtable_other[];
34static void ufs_clusteracct(struct super_block *, struct ufs_cg_private_info *, unsigned, int);
35
36/*
37 * Free 'count' fragments from fragment number 'fragment'
38 */
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080039void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count)
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -070040{
Linus Torvalds1da177e2005-04-16 15:20:36 -070041 struct super_block * sb;
42 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -070043 struct ufs_cg_private_info * ucpi;
44 struct ufs_cylinder_group * ucg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080045 unsigned cgno, bit, end_bit, bbase, blkmap, i;
46 u64 blkno;
Linus Torvalds1da177e2005-04-16 15:20:36 -070047
48 sb = inode->i_sb;
49 uspi = UFS_SB(sb)->s_uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -070050
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080051 UFSD("ENTER, fragment %llu, count %u\n",
52 (unsigned long long)fragment, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -070053
54 if (ufs_fragnum(fragment) + count > uspi->s_fpg)
55 ufs_error (sb, "ufs_free_fragments", "internal error");
Fabian Frederickcdd9eef2015-06-10 10:09:32 +100056
57 mutex_lock(&UFS_SB(sb)->s_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -070058
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -080059 cgno = ufs_dtog(uspi, fragment);
60 bit = ufs_dtogd(uspi, fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -070061 if (cgno >= uspi->s_ncg) {
62 ufs_panic (sb, "ufs_free_fragments", "freeing blocks are outside device");
63 goto failed;
64 }
65
66 ucpi = ufs_load_cylinder (sb, cgno);
67 if (!ucpi)
68 goto failed;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070069 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -070070 if (!ufs_cg_chkmagic(sb, ucg)) {
71 ufs_panic (sb, "ufs_free_fragments", "internal error, bad magic number on cg %u", cgno);
72 goto failed;
73 }
74
75 end_bit = bit + count;
76 bbase = ufs_blknum (bit);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070077 blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078 ufs_fragacct (sb, blkmap, ucg->cg_frsum, -1);
79 for (i = bit; i < end_bit; i++) {
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070080 if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, i))
81 ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, i);
Evgeniy7b4ee732006-01-14 11:42:06 +030082 else
83 ufs_error (sb, "ufs_free_fragments",
84 "bit already cleared for fragment %u", i);
Linus Torvalds1da177e2005-04-16 15:20:36 -070085 }
Al Viroeb315d22017-06-08 21:15:03 -040086
87 inode_sub_bytes(inode, count << uspi->s_fshift);
Linus Torvalds1da177e2005-04-16 15:20:36 -070088 fs32_add(sb, &ucg->cg_cs.cs_nffree, count);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -070089 uspi->cs_total.cs_nffree += count;
Linus Torvalds1da177e2005-04-16 15:20:36 -070090 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070091 blkmap = ubh_blkmap (UCPI_UBH(ucpi), ucpi->c_freeoff, bbase);
Linus Torvalds1da177e2005-04-16 15:20:36 -070092 ufs_fragacct(sb, blkmap, ucg->cg_frsum, 1);
93
94 /*
95 * Trying to reassemble free fragments into block
96 */
97 blkno = ufs_fragstoblks (bbase);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -070098 if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -070099 fs32_sub(sb, &ucg->cg_cs.cs_nffree, uspi->s_fpb);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700100 uspi->cs_total.cs_nffree -= uspi->s_fpb;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700101 fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, uspi->s_fpb);
102 if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
103 ufs_clusteracct (sb, ucpi, blkno, 1);
104 fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700105 uspi->cs_total.cs_nbfree++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700106 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800107 if (uspi->fs_magic != UFS2_MAGIC) {
108 unsigned cylno = ufs_cbtocylno (bbase);
109
110 fs16_add(sb, &ubh_cg_blks(ucpi, cylno,
111 ufs_cbtorpos(bbase)), 1);
112 fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
113 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114 }
115
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700116 ubh_mark_buffer_dirty (USPI_UBH(uspi));
117 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Linus Torvalds1751e8a2017-11-27 13:05:09 -0800118 if (sb->s_flags & SB_SYNCHRONOUS)
Christoph Hellwig9cb569d2010-08-11 17:06:24 +0200119 ubh_sync_block(UCPI_UBH(ucpi));
Artem Bityutskiy9e9ad5f2012-07-12 16:28:08 +0300120 ufs_mark_sb_dirty(sb);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000121
122 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700123 UFSD("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700124 return;
125
126failed:
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000127 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700128 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700129 return;
130}
131
132/*
133 * Free 'count' fragments from fragment number 'fragment' (free whole blocks)
134 */
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800135void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count)
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700136{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700137 struct super_block * sb;
138 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700139 struct ufs_cg_private_info * ucpi;
140 struct ufs_cylinder_group * ucg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800141 unsigned overflow, cgno, bit, end_bit, i;
142 u64 blkno;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700143
144 sb = inode->i_sb;
145 uspi = UFS_SB(sb)->s_uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700146
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800147 UFSD("ENTER, fragment %llu, count %u\n",
148 (unsigned long long)fragment, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700149
150 if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) {
151 ufs_error (sb, "ufs_free_blocks", "internal error, "
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800152 "fragment %llu, count %u\n",
153 (unsigned long long)fragment, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700154 goto failed;
155 }
156
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000157 mutex_lock(&UFS_SB(sb)->s_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700158
159do_more:
160 overflow = 0;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800161 cgno = ufs_dtog(uspi, fragment);
162 bit = ufs_dtogd(uspi, fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700163 if (cgno >= uspi->s_ncg) {
164 ufs_panic (sb, "ufs_free_blocks", "freeing blocks are outside device");
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700165 goto failed_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700166 }
167 end_bit = bit + count;
168 if (end_bit > uspi->s_fpg) {
169 overflow = bit + count - uspi->s_fpg;
170 count -= overflow;
171 end_bit -= overflow;
172 }
173
174 ucpi = ufs_load_cylinder (sb, cgno);
175 if (!ucpi)
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700176 goto failed_unlock;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700177 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700178 if (!ufs_cg_chkmagic(sb, ucg)) {
179 ufs_panic (sb, "ufs_free_blocks", "internal error, bad magic number on cg %u", cgno);
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700180 goto failed_unlock;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700181 }
182
183 for (i = bit; i < end_bit; i += uspi->s_fpb) {
184 blkno = ufs_fragstoblks(i);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700185 if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700186 ufs_error(sb, "ufs_free_blocks", "freeing free fragment");
187 }
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700188 ubh_setblock(UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
Al Viroeb315d22017-06-08 21:15:03 -0400189 inode_sub_bytes(inode, uspi->s_fpb << uspi->s_fshift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700190 if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
191 ufs_clusteracct (sb, ucpi, blkno, 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700192
193 fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700194 uspi->cs_total.cs_nbfree++;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800196
197 if (uspi->fs_magic != UFS2_MAGIC) {
198 unsigned cylno = ufs_cbtocylno(i);
199
200 fs16_add(sb, &ubh_cg_blks(ucpi, cylno,
201 ufs_cbtorpos(i)), 1);
202 fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1);
203 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204 }
205
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700206 ubh_mark_buffer_dirty (USPI_UBH(uspi));
207 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Linus Torvalds1751e8a2017-11-27 13:05:09 -0800208 if (sb->s_flags & SB_SYNCHRONOUS)
Christoph Hellwig9cb569d2010-08-11 17:06:24 +0200209 ubh_sync_block(UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700210
211 if (overflow) {
212 fragment += count;
213 count = overflow;
214 goto do_more;
215 }
216
Artem Bityutskiy9e9ad5f2012-07-12 16:28:08 +0300217 ufs_mark_sb_dirty(sb);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000218 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700219 UFSD("EXIT\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700220 return;
221
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700222failed_unlock:
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000223 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov2e006392006-06-25 05:47:26 -0700224failed:
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700225 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700226 return;
227}
228
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700229/*
230 * Modify inode page cache in such way:
231 * have - blocks with b_blocknr equal to oldb...oldb+count-1
232 * get - blocks with b_blocknr equal to newb...newb+count-1
233 * also we suppose that oldb...oldb+count-1 blocks
234 * situated at the end of file.
235 *
236 * We can come here from ufs_writepage or ufs_prepare_write,
237 * locked_page is argument of these functions, so we already lock it.
238 */
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800239static void ufs_change_blocknr(struct inode *inode, sector_t beg,
240 unsigned int count, sector_t oldb,
241 sector_t newb, struct page *locked_page)
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700242{
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800243 const unsigned blks_per_page =
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300244 1 << (PAGE_SHIFT - inode->i_blkbits);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800245 const unsigned mask = blks_per_page - 1;
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800246 struct address_space * const mapping = inode->i_mapping;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800247 pgoff_t index, cur_index, last_index;
248 unsigned pos, j, lblock;
249 sector_t end, i;
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700250 struct page *page;
251 struct buffer_head *head, *bh;
252
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800253 UFSD("ENTER, ino %lu, count %u, oldb %llu, newb %llu\n",
254 inode->i_ino, count,
255 (unsigned long long)oldb, (unsigned long long)newb);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700256
Evgeniy Dushistova685e262007-01-29 13:19:54 -0800257 BUG_ON(!locked_page);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700258 BUG_ON(!PageLocked(locked_page));
259
Evgeniy Dushistova685e262007-01-29 13:19:54 -0800260 cur_index = locked_page->index;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800261 end = count + beg;
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300262 last_index = end >> (PAGE_SHIFT - inode->i_blkbits);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800263 for (i = beg; i < end; i = (i | mask) + 1) {
Kirill A. Shutemov09cbfea2016-04-01 15:29:47 +0300264 index = i >> (PAGE_SHIFT - inode->i_blkbits);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700265
266 if (likely(cur_index != index)) {
267 page = ufs_get_locked_page(mapping, index);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800268 if (!page)/* it was truncated */
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700269 continue;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800270 if (IS_ERR(page)) {/* or EIO */
Harvey Harrison9746077a72008-04-28 02:16:17 -0700271 ufs_error(inode->i_sb, __func__,
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800272 "read of page %llu failed\n",
273 (unsigned long long)index);
274 continue;
275 }
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700276 } else
277 page = locked_page;
278
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700279 head = page_buffers(page);
280 bh = head;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800281 pos = i & mask;
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800282 for (j = 0; j < pos; ++j)
283 bh = bh->b_this_page;
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800284
285
286 if (unlikely(index == last_index))
287 lblock = end & mask;
288 else
289 lblock = blks_per_page;
290
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700291 do {
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800292 if (j >= lblock)
293 break;
294 pos = (i - beg) + j;
295
296 if (!buffer_mapped(bh))
297 map_bh(bh, inode->i_sb, oldb + pos);
298 if (!buffer_uptodate(bh)) {
Mike Christiedfec8a12016-06-05 14:31:44 -0500299 ll_rw_block(REQ_OP_READ, 0, 1, &bh);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800300 wait_on_buffer(bh);
301 if (!buffer_uptodate(bh)) {
Harvey Harrison9746077a72008-04-28 02:16:17 -0700302 ufs_error(inode->i_sb, __func__,
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800303 "read of block failed\n");
304 break;
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800305 }
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700306 }
307
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800308 UFSD(" change from %llu to %llu, pos %u\n",
Andrew Morton9df13032008-03-19 17:01:05 -0700309 (unsigned long long)(pos + oldb),
310 (unsigned long long)(pos + newb), pos);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800311
312 bh->b_blocknr = newb + pos;
Jan Karae64855c2016-11-04 18:08:15 +0100313 clean_bdev_bh_alias(bh);
Evgeniy Dushistov5431bf92007-03-16 13:38:08 -0800314 mark_buffer_dirty(bh);
315 ++j;
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700316 bh = bh->b_this_page;
317 } while (bh != head);
318
Evgeniy Dushistov10e5dce2006-07-01 04:36:24 -0700319 if (likely(cur_index != index))
320 ufs_put_locked_page(page);
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700321 }
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700322 UFSD("EXIT\n");
Evgeniy Dushistov6ef4d6b2006-06-25 05:47:20 -0700323}
324
Evgeniy Dushistovd63b7092007-01-05 16:37:04 -0800325static void ufs_clear_frags(struct inode *inode, sector_t beg, unsigned int n,
326 int sync)
327{
328 struct buffer_head *bh;
329 sector_t end = beg + n;
330
331 for (; beg < end; ++beg) {
332 bh = sb_getblk(inode->i_sb, beg);
333 lock_buffer(bh);
334 memset(bh->b_data, 0, inode->i_sb->s_blocksize);
335 set_buffer_uptodate(bh);
336 mark_buffer_dirty(bh);
337 unlock_buffer(bh);
338 if (IS_SYNC(inode) || sync)
339 sync_dirty_buffer(bh);
340 brelse(bh);
341 }
342}
343
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800344u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment,
345 u64 goal, unsigned count, int *err,
346 struct page *locked_page)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700347{
348 struct super_block * sb;
349 struct ufs_sb_private_info * uspi;
350 struct ufs_super_block_first * usb1;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800351 unsigned cgno, oldcount, newcount;
352 u64 tmp, request, result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700353
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800354 UFSD("ENTER, ino %lu, fragment %llu, goal %llu, count %u\n",
355 inode->i_ino, (unsigned long long)fragment,
356 (unsigned long long)goal, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700357
358 sb = inode->i_sb;
359 uspi = UFS_SB(sb)->s_uspi;
Evgeniy7b4ee732006-01-14 11:42:06 +0300360 usb1 = ubh_get_usb_first(uspi);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700361 *err = -ENOSPC;
362
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000363 mutex_lock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800364 tmp = ufs_data_ptr_to_cpu(sb, p);
365
Linus Torvalds1da177e2005-04-16 15:20:36 -0700366 if (count + ufs_fragnum(fragment) > uspi->s_fpb) {
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800367 ufs_warning(sb, "ufs_new_fragments", "internal warning"
368 " fragment %llu, count %u",
369 (unsigned long long)fragment, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700370 count = uspi->s_fpb - ufs_fragnum(fragment);
371 }
372 oldcount = ufs_fragnum (fragment);
373 newcount = oldcount + count;
374
375 /*
376 * Somebody else has just allocated our fragments
377 */
378 if (oldcount) {
379 if (!tmp) {
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800380 ufs_error(sb, "ufs_new_fragments", "internal error, "
381 "fragment %llu, tmp %llu\n",
382 (unsigned long long)fragment,
383 (unsigned long long)tmp);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000384 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800385 return INVBLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386 }
387 if (fragment < UFS_I(inode)->i_lastfrag) {
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700388 UFSD("EXIT (ALREADY ALLOCATED)\n");
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000389 mutex_unlock(&UFS_SB(sb)->s_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700390 return 0;
391 }
392 }
393 else {
394 if (tmp) {
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700395 UFSD("EXIT (ALREADY ALLOCATED)\n");
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000396 mutex_unlock(&UFS_SB(sb)->s_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700397 return 0;
398 }
399 }
400
401 /*
402 * There is not enough space for user on the device
403 */
Al Viroc5969612017-06-14 16:36:29 -0400404 if (unlikely(ufs_freefrags(uspi) <= uspi->s_root_blocks)) {
Al Virob451cec2017-06-14 15:41:17 -0400405 if (!capable(CAP_SYS_RESOURCE)) {
406 mutex_unlock(&UFS_SB(sb)->s_lock);
407 UFSD("EXIT (FAILED)\n");
408 return 0;
409 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700410 }
411
412 if (goal >= uspi->s_size)
413 goal = 0;
414 if (goal == 0)
415 cgno = ufs_inotocg (inode->i_ino);
416 else
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800417 cgno = ufs_dtog(uspi, goal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418
419 /*
420 * allocate new fragment
421 */
422 if (oldcount == 0) {
423 result = ufs_alloc_fragments (inode, cgno, goal, count, err);
424 if (result) {
Al Virobd2843f2015-09-09 10:16:39 +0100425 ufs_clear_frags(inode, result + oldcount,
426 newcount - oldcount, locked_page != NULL);
Al Viro09bf4f52017-06-15 00:17:30 -0400427 *err = 0;
Al Viro724bb092015-06-17 12:02:56 -0400428 write_seqlock(&UFS_I(inode)->meta_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800429 ufs_cpu_to_data_ptr(sb, p, result);
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);
Al Viro09bf4f52017-06-15 00:17:30 -0400432 write_sequnlock(&UFS_I(inode)->meta_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700433 }
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000434 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800435 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700436 return result;
437 }
438
439 /*
440 * resize block
441 */
Fabian Frederick45641c82014-06-06 14:36:33 -0700442 result = ufs_add_fragments(inode, tmp, oldcount, newcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700443 if (result) {
444 *err = 0;
Al Viro09bf4f52017-06-15 00:17:30 -0400445 read_seqlock_excl(&UFS_I(inode)->meta_lock);
Dan Carpenter1d582722011-05-26 16:25:12 -0700446 UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag,
447 fragment + count);
Al Viro09bf4f52017-06-15 00:17:30 -0400448 read_sequnlock_excl(&UFS_I(inode)->meta_lock);
Evgeniy Dushistovd63b7092007-01-05 16:37:04 -0800449 ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
450 locked_page != NULL);
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000451 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800452 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700453 return result;
454 }
455
456 /*
457 * allocate new block and move data
458 */
Al Viro77e9ce32017-06-17 15:44:06 -0400459 if (fs32_to_cpu(sb, usb1->fs_optim) == UFS_OPTSPACE) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700460 request = newcount;
Al Viro77e9ce32017-06-17 15:44:06 -0400461 if (uspi->cs_total.cs_nffree < uspi->s_space_to_time)
462 usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTTIME);
463 } else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700464 request = uspi->s_fpb;
Al Viro77e9ce32017-06-17 15:44:06 -0400465 if (uspi->cs_total.cs_nffree > uspi->s_time_to_space)
466 usb1->fs_optim = cpu_to_fs32(sb, UFS_OPTSPACE);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467 }
468 result = ufs_alloc_fragments (inode, cgno, goal, request, err);
469 if (result) {
Evgeniy Dushistovefee2b82007-01-29 13:19:56 -0800470 ufs_clear_frags(inode, result + oldcount, newcount - oldcount,
471 locked_page != NULL);
Al Viro289dec52017-06-15 00:42:56 -0400472 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistov4b25a372007-03-16 13:38:09 -0800473 ufs_change_blocknr(inode, fragment - oldcount, oldcount,
474 uspi->s_sbbase + tmp,
475 uspi->s_sbbase + result, locked_page);
Al Viro09bf4f52017-06-15 00:17:30 -0400476 *err = 0;
Al Viro724bb092015-06-17 12:02:56 -0400477 write_seqlock(&UFS_I(inode)->meta_lock);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800478 ufs_cpu_to_data_ptr(sb, p, result);
Dan Carpenter1d582722011-05-26 16:25:12 -0700479 UFS_I(inode)->i_lastfrag = max(UFS_I(inode)->i_lastfrag,
480 fragment + count);
Al Viro09bf4f52017-06-15 00:17:30 -0400481 write_sequnlock(&UFS_I(inode)->meta_lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700482 if (newcount < request)
483 ufs_free_fragments (inode, result + newcount, request - newcount);
484 ufs_free_fragments (inode, tmp, oldcount);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800485 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700486 return result;
487 }
488
Fabian Frederickcdd9eef2015-06-10 10:09:32 +1000489 mutex_unlock(&UFS_SB(sb)->s_lock);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700490 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700491 return 0;
492}
493
Al Viroeb315d22017-06-08 21:15:03 -0400494static bool try_add_frags(struct inode *inode, unsigned frags)
495{
496 unsigned size = frags * i_blocksize(inode);
497 spin_lock(&inode->i_lock);
498 __inode_add_bytes(inode, size);
499 if (unlikely((u32)inode->i_blocks != inode->i_blocks)) {
500 __inode_sub_bytes(inode, size);
501 spin_unlock(&inode->i_lock);
502 return false;
503 }
504 spin_unlock(&inode->i_lock);
505 return true;
506}
507
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800508static u64 ufs_add_fragments(struct inode *inode, u64 fragment,
Fabian Frederick45641c82014-06-06 14:36:33 -0700509 unsigned oldcount, unsigned newcount)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700510{
511 struct super_block * sb;
512 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700513 struct ufs_cg_private_info * ucpi;
514 struct ufs_cylinder_group * ucg;
515 unsigned cgno, fragno, fragoff, count, fragsize, i;
516
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800517 UFSD("ENTER, fragment %llu, oldcount %u, newcount %u\n",
518 (unsigned long long)fragment, oldcount, newcount);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700519
520 sb = inode->i_sb;
521 uspi = UFS_SB(sb)->s_uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700522 count = newcount - oldcount;
523
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800524 cgno = ufs_dtog(uspi, fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700525 if (fs32_to_cpu(sb, UFS_SB(sb)->fs_cs(cgno).cs_nffree) < count)
526 return 0;
527 if ((ufs_fragnum (fragment) + newcount) > uspi->s_fpb)
528 return 0;
529 ucpi = ufs_load_cylinder (sb, cgno);
530 if (!ucpi)
531 return 0;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700532 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700533 if (!ufs_cg_chkmagic(sb, ucg)) {
534 ufs_panic (sb, "ufs_add_fragments",
535 "internal error, bad magic number on cg %u", cgno);
536 return 0;
537 }
538
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800539 fragno = ufs_dtogd(uspi, fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 fragoff = ufs_fragnum (fragno);
541 for (i = oldcount; i < newcount; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700542 if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700543 return 0;
Al Viroeb315d22017-06-08 21:15:03 -0400544
545 if (!try_add_frags(inode, count))
546 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 /*
548 * Block can be extended
549 */
Arnd Bergmanna3fda0f2018-08-17 15:43:47 -0700550 ucg->cg_time = ufs_get_seconds(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 for (i = newcount; i < (uspi->s_fpb - fragoff); i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700552 if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700553 break;
554 fragsize = i - oldcount;
555 if (!fs32_to_cpu(sb, ucg->cg_frsum[fragsize]))
556 ufs_panic (sb, "ufs_add_fragments",
557 "internal error or corrupted bitmap on cg %u", cgno);
558 fs32_sub(sb, &ucg->cg_frsum[fragsize], 1);
559 if (fragsize != count)
560 fs32_add(sb, &ucg->cg_frsum[fragsize - count], 1);
561 for (i = oldcount; i < newcount; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700562 ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700563
564 fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
565 fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700566 uspi->cs_total.cs_nffree -= count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700568 ubh_mark_buffer_dirty (USPI_UBH(uspi));
569 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Linus Torvalds1751e8a2017-11-27 13:05:09 -0800570 if (sb->s_flags & SB_SYNCHRONOUS)
Christoph Hellwig9cb569d2010-08-11 17:06:24 +0200571 ubh_sync_block(UCPI_UBH(ucpi));
Artem Bityutskiy9e9ad5f2012-07-12 16:28:08 +0300572 ufs_mark_sb_dirty(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800574 UFSD("EXIT, fragment %llu\n", (unsigned long long)fragment);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575
576 return fragment;
577}
578
579#define UFS_TEST_FREE_SPACE_CG \
580 ucg = (struct ufs_cylinder_group *) UFS_SB(sb)->s_ucg[cgno]->b_data; \
581 if (fs32_to_cpu(sb, ucg->cg_cs.cs_nbfree)) \
582 goto cg_found; \
583 for (k = count; k < uspi->s_fpb; k++) \
584 if (fs32_to_cpu(sb, ucg->cg_frsum[k])) \
585 goto cg_found;
586
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800587static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno,
588 u64 goal, unsigned count, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700589{
590 struct super_block * sb;
591 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700592 struct ufs_cg_private_info * ucpi;
593 struct ufs_cylinder_group * ucg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800594 unsigned oldcg, i, j, k, allocsize;
595 u64 result;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700596
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800597 UFSD("ENTER, ino %lu, cgno %u, goal %llu, count %u\n",
598 inode->i_ino, cgno, (unsigned long long)goal, count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700599
600 sb = inode->i_sb;
601 uspi = UFS_SB(sb)->s_uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700602 oldcg = cgno;
603
604 /*
605 * 1. searching on preferred cylinder group
606 */
607 UFS_TEST_FREE_SPACE_CG
608
609 /*
610 * 2. quadratic rehash
611 */
612 for (j = 1; j < uspi->s_ncg; j *= 2) {
613 cgno += j;
614 if (cgno >= uspi->s_ncg)
615 cgno -= uspi->s_ncg;
616 UFS_TEST_FREE_SPACE_CG
617 }
618
619 /*
620 * 3. brute force search
621 * We start at i = 2 ( 0 is checked at 1.step, 1 at 2.step )
622 */
623 cgno = (oldcg + 1) % uspi->s_ncg;
624 for (j = 2; j < uspi->s_ncg; j++) {
625 cgno++;
626 if (cgno >= uspi->s_ncg)
627 cgno = 0;
628 UFS_TEST_FREE_SPACE_CG
629 }
630
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700631 UFSD("EXIT (FAILED)\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700632 return 0;
633
634cg_found:
635 ucpi = ufs_load_cylinder (sb, cgno);
636 if (!ucpi)
637 return 0;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700638 ucg = ubh_get_ucg (UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 if (!ufs_cg_chkmagic(sb, ucg))
640 ufs_panic (sb, "ufs_alloc_fragments",
641 "internal error, bad magic number on cg %u", cgno);
Arnd Bergmanna3fda0f2018-08-17 15:43:47 -0700642 ucg->cg_time = ufs_get_seconds(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700643
644 if (count == uspi->s_fpb) {
645 result = ufs_alloccg_block (inode, ucpi, goal, err);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800646 if (result == INVBLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700647 return 0;
648 goto succed;
649 }
650
651 for (allocsize = count; allocsize < uspi->s_fpb; allocsize++)
652 if (fs32_to_cpu(sb, ucg->cg_frsum[allocsize]) != 0)
653 break;
654
655 if (allocsize == uspi->s_fpb) {
656 result = ufs_alloccg_block (inode, ucpi, goal, err);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800657 if (result == INVBLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700658 return 0;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800659 goal = ufs_dtogd(uspi, result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700660 for (i = count; i < uspi->s_fpb; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700661 ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700662 i = uspi->s_fpb - count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700663
Al Viroeb315d22017-06-08 21:15:03 -0400664 inode_sub_bytes(inode, i << uspi->s_fshift);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 fs32_add(sb, &ucg->cg_cs.cs_nffree, i);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700666 uspi->cs_total.cs_nffree += i;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700667 fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, i);
668 fs32_add(sb, &ucg->cg_frsum[i], 1);
669 goto succed;
670 }
671
672 result = ufs_bitmap_search (sb, ucpi, goal, allocsize);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800673 if (result == INVBLOCK)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700674 return 0;
Al Viroeb315d22017-06-08 21:15:03 -0400675 if (!try_add_frags(inode, count))
676 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700677 for (i = 0; i < count; i++)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700678 ubh_clrbit (UCPI_UBH(ucpi), ucpi->c_freeoff, result + i);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700679
680 fs32_sub(sb, &ucg->cg_cs.cs_nffree, count);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700681 uspi->cs_total.cs_nffree -= count;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700682 fs32_sub(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nffree, count);
683 fs32_sub(sb, &ucg->cg_frsum[allocsize], 1);
684
685 if (count != allocsize)
686 fs32_add(sb, &ucg->cg_frsum[allocsize - count], 1);
687
688succed:
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700689 ubh_mark_buffer_dirty (USPI_UBH(uspi));
690 ubh_mark_buffer_dirty (UCPI_UBH(ucpi));
Linus Torvalds1751e8a2017-11-27 13:05:09 -0800691 if (sb->s_flags & SB_SYNCHRONOUS)
Christoph Hellwig9cb569d2010-08-11 17:06:24 +0200692 ubh_sync_block(UCPI_UBH(ucpi));
Artem Bityutskiy9e9ad5f2012-07-12 16:28:08 +0300693 ufs_mark_sb_dirty(sb);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700694
695 result += cgno * uspi->s_fpg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800696 UFSD("EXIT3, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697 return result;
698}
699
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800700static u64 ufs_alloccg_block(struct inode *inode,
701 struct ufs_cg_private_info *ucpi,
702 u64 goal, int *err)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703{
704 struct super_block * sb;
705 struct ufs_sb_private_info * uspi;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700706 struct ufs_cylinder_group * ucg;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800707 u64 result, blkno;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700708
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800709 UFSD("ENTER, goal %llu\n", (unsigned long long)goal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700710
711 sb = inode->i_sb;
712 uspi = UFS_SB(sb)->s_uspi;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700713 ucg = ubh_get_ucg(UCPI_UBH(ucpi));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714
715 if (goal == 0) {
716 goal = ucpi->c_rotor;
717 goto norot;
718 }
719 goal = ufs_blknum (goal);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800720 goal = ufs_dtogd(uspi, goal);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700721
722 /*
723 * If the requested block is available, use it.
724 */
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700725 if (ubh_isblockset(UCPI_UBH(ucpi), ucpi->c_freeoff, ufs_fragstoblks(goal))) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 result = goal;
727 goto gotit;
728 }
729
730norot:
731 result = ufs_bitmap_search (sb, ucpi, goal, uspi->s_fpb);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800732 if (result == INVBLOCK)
733 return INVBLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 ucpi->c_rotor = result;
735gotit:
Al Viroeb315d22017-06-08 21:15:03 -0400736 if (!try_add_frags(inode, uspi->s_fpb))
737 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700738 blkno = ufs_fragstoblks(result);
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700739 ubh_clrblock (UCPI_UBH(ucpi), ucpi->c_freeoff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700740 if ((UFS_SB(sb)->s_flags & UFS_CG_MASK) == UFS_CG_44BSD)
741 ufs_clusteracct (sb, ucpi, blkno, -1);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
743 fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1);
Evgeniy Dushistovee3ffd62006-06-25 05:47:30 -0700744 uspi->cs_total.cs_nbfree--;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 fs32_sub(sb, &UFS_SB(sb)->fs_cs(ucpi->c_cgx).cs_nbfree, 1);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800746
747 if (uspi->fs_magic != UFS2_MAGIC) {
748 unsigned cylno = ufs_cbtocylno((unsigned)result);
749
750 fs16_sub(sb, &ubh_cg_blks(ucpi, cylno,
751 ufs_cbtorpos((unsigned)result)), 1);
752 fs32_sub(sb, &ubh_cg_blktot(ucpi, cylno), 1);
753 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700754
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800755 UFSD("EXIT, result %llu\n", (unsigned long long)result);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700756
757 return result;
758}
759
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700760static unsigned ubh_scanc(struct ufs_sb_private_info *uspi,
761 struct ufs_buffer_head *ubh,
762 unsigned begin, unsigned size,
763 unsigned char *table, unsigned char mask)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700764{
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700765 unsigned rest, offset;
766 unsigned char *cp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700767
Linus Torvalds1da177e2005-04-16 15:20:36 -0700768
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700769 offset = begin & ~uspi->s_fmask;
770 begin >>= uspi->s_fshift;
771 for (;;) {
772 if ((offset + size) < uspi->s_fsize)
773 rest = size;
774 else
775 rest = uspi->s_fsize - offset;
776 size -= rest;
777 cp = ubh->bh[begin]->b_data + offset;
778 while ((table[*cp++] & mask) == 0 && --rest)
779 ;
780 if (rest || !size)
781 break;
782 begin++;
783 offset = 0;
784 }
785 return (size + rest);
786}
787
788/*
789 * Find a block of the specified size in the specified cylinder group.
790 * @sp: pointer to super block
791 * @ucpi: pointer to cylinder group info
792 * @goal: near which block we want find new one
793 * @count: specified size
794 */
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800795static u64 ufs_bitmap_search(struct super_block *sb,
796 struct ufs_cg_private_info *ucpi,
797 u64 goal, unsigned count)
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700798{
799 /*
800 * Bit patterns for identifying fragments in the block map
801 * used as ((map & mask_arr) == want_arr)
802 */
803 static const int mask_arr[9] = {
804 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f, 0xff, 0x1ff, 0x3ff
805 };
806 static const int want_arr[9] = {
807 0x0, 0x2, 0x6, 0xe, 0x1e, 0x3e, 0x7e, 0xfe, 0x1fe
808 };
809 struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800810 unsigned start, length, loc;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700811 unsigned pos, want, blockmap, mask, end;
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800812 u64 result;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700813
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800814 UFSD("ENTER, cg %u, goal %llu, count %u\n", ucpi->c_cgx,
815 (unsigned long long)goal, count);
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700816
Linus Torvalds1da177e2005-04-16 15:20:36 -0700817 if (goal)
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800818 start = ufs_dtogd(uspi, goal) >> 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700819 else
820 start = ucpi->c_frotor >> 3;
821
822 length = ((uspi->s_fpg + 7) >> 3) - start;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700823 loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff + start, length,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700824 (uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
825 1 << (count - 1 + (uspi->s_fpb & 7)));
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700826 if (loc == 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700827 length = start + 1;
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700828 loc = ubh_scanc(uspi, UCPI_UBH(ucpi), ucpi->c_freeoff, length,
829 (uspi->s_fpb == 8) ? ufs_fragtable_8fpb :
830 ufs_fragtable_other,
831 1 << (count - 1 + (uspi->s_fpb & 7)));
832 if (loc == 0) {
833 ufs_error(sb, "ufs_bitmap_search",
834 "bitmap corrupted on cg %u, start %u,"
835 " length %u, count %u, freeoff %u\n",
836 ucpi->c_cgx, start, length, count,
837 ucpi->c_freeoff);
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800838 return INVBLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839 }
840 start = 0;
841 }
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700842 result = (start + length - loc) << 3;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700843 ucpi->c_frotor = result;
844
845 /*
846 * found the byte in the map
847 */
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700848
849 for (end = result + 8; result < end; result += uspi->s_fpb) {
850 blockmap = ubh_blkmap(UCPI_UBH(ucpi), ucpi->c_freeoff, result);
851 blockmap <<= 1;
852 mask = mask_arr[count];
853 want = want_arr[count];
854 for (pos = 0; pos <= uspi->s_fpb - count; pos++) {
855 if ((blockmap & mask) == want) {
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800856 UFSD("EXIT, result %llu\n",
857 (unsigned long long)result);
Evgeniy Dushistov3e41f592006-06-25 05:47:23 -0700858 return result + pos;
859 }
860 mask <<= 1;
861 want <<= 1;
862 }
863 }
864
865 ufs_error(sb, "ufs_bitmap_search", "block not in map on cg %u\n",
866 ucpi->c_cgx);
Evgeniy Dushistovabf5d152006-06-25 05:47:24 -0700867 UFSD("EXIT (FAILED)\n");
Evgeniy Dushistov54fb9962007-02-12 00:54:32 -0800868 return INVBLOCK;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700869}
870
871static void ufs_clusteracct(struct super_block * sb,
872 struct ufs_cg_private_info * ucpi, unsigned blkno, int cnt)
873{
874 struct ufs_sb_private_info * uspi;
875 int i, start, end, forw, back;
876
877 uspi = UFS_SB(sb)->s_uspi;
878 if (uspi->s_contigsumsize <= 0)
879 return;
880
881 if (cnt > 0)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700882 ubh_setbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700883 else
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700884 ubh_clrbit(UCPI_UBH(ucpi), ucpi->c_clusteroff, blkno);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700885
886 /*
887 * Find the size of the cluster going forward.
888 */
889 start = blkno + 1;
890 end = start + uspi->s_contigsumsize;
891 if ( end >= ucpi->c_nclusterblks)
892 end = ucpi->c_nclusterblks;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700893 i = ubh_find_next_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, end, start);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894 if (i > end)
895 i = end;
896 forw = i - start;
897
898 /*
899 * Find the size of the cluster going backward.
900 */
901 start = blkno - 1;
902 end = start - uspi->s_contigsumsize;
903 if (end < 0 )
904 end = -1;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700905 i = ubh_find_last_zero_bit (UCPI_UBH(ucpi), ucpi->c_clusteroff, start, end);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700906 if ( i < end)
907 i = end;
908 back = start - i;
909
910 /*
911 * Account for old cluster and the possibly new forward and
912 * back clusters.
913 */
914 i = back + forw + 1;
915 if (i > uspi->s_contigsumsize)
916 i = uspi->s_contigsumsize;
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700917 fs32_add(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (i << 2)), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700918 if (back > 0)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700919 fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (back << 2)), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700920 if (forw > 0)
Evgeniy Dushistov9695ef12006-06-25 05:47:22 -0700921 fs32_sub(sb, (__fs32*)ubh_get_addr(UCPI_UBH(ucpi), ucpi->c_clustersumoff + (forw << 2)), cnt);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700922}
923
924
925static unsigned char ufs_fragtable_8fpb[] = {
926 0x00, 0x01, 0x01, 0x02, 0x01, 0x01, 0x02, 0x04, 0x01, 0x01, 0x01, 0x03, 0x02, 0x03, 0x04, 0x08,
927 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x02, 0x03, 0x03, 0x02, 0x04, 0x05, 0x08, 0x10,
928 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
929 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x04, 0x05, 0x05, 0x06, 0x08, 0x09, 0x10, 0x20,
930 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
931 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
932 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
933 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x08, 0x09, 0x09, 0x0A, 0x10, 0x11, 0x20, 0x40,
934 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
935 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x03, 0x03, 0x03, 0x03, 0x05, 0x05, 0x09, 0x11,
936 0x01, 0x01, 0x01, 0x03, 0x01, 0x01, 0x03, 0x05, 0x01, 0x01, 0x01, 0x03, 0x03, 0x03, 0x05, 0x09,
937 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x05, 0x05, 0x05, 0x07, 0x09, 0x09, 0x11, 0x21,
938 0x02, 0x03, 0x03, 0x02, 0x03, 0x03, 0x02, 0x06, 0x03, 0x03, 0x03, 0x03, 0x02, 0x03, 0x06, 0x0A,
939 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07, 0x02, 0x03, 0x03, 0x02, 0x06, 0x07, 0x0A, 0x12,
940 0x04, 0x05, 0x05, 0x06, 0x05, 0x05, 0x06, 0x04, 0x05, 0x05, 0x05, 0x07, 0x06, 0x07, 0x04, 0x0C,
941 0x08, 0x09, 0x09, 0x0A, 0x09, 0x09, 0x0A, 0x0C, 0x10, 0x11, 0x11, 0x12, 0x20, 0x21, 0x40, 0x80,
942};
943
944static unsigned char ufs_fragtable_other[] = {
945 0x00, 0x16, 0x16, 0x2A, 0x16, 0x16, 0x26, 0x4E, 0x16, 0x16, 0x16, 0x3E, 0x2A, 0x3E, 0x4E, 0x8A,
946 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
947 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
948 0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
949 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
950 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
951 0x26, 0x36, 0x36, 0x2E, 0x36, 0x36, 0x26, 0x6E, 0x36, 0x36, 0x36, 0x3E, 0x2E, 0x3E, 0x6E, 0xAE,
952 0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
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 0x16, 0x16, 0x16, 0x3E, 0x16, 0x16, 0x36, 0x5E, 0x16, 0x16, 0x16, 0x3E, 0x3E, 0x3E, 0x5E, 0x9E,
956 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
957 0x2A, 0x3E, 0x3E, 0x2A, 0x3E, 0x3E, 0x2E, 0x6E, 0x3E, 0x3E, 0x3E, 0x3E, 0x2A, 0x3E, 0x6E, 0xAA,
958 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x3E, 0x7E, 0xBE,
959 0x4E, 0x5E, 0x5E, 0x6E, 0x5E, 0x5E, 0x6E, 0x4E, 0x5E, 0x5E, 0x5E, 0x7E, 0x6E, 0x7E, 0x4E, 0xCE,
960 0x8A, 0x9E, 0x9E, 0xAA, 0x9E, 0x9E, 0xAE, 0xCE, 0x9E, 0x9E, 0x9E, 0xBE, 0xAA, 0xBE, 0xCE, 0x8A,
961};