jfs_extent.c (9970B)
1// SPDX-License-Identifier: GPL-2.0-or-later 2/* 3 * Copyright (C) International Business Machines Corp., 2000-2004 4 */ 5 6#include <linux/fs.h> 7#include <linux/quotaops.h> 8#include "jfs_incore.h" 9#include "jfs_inode.h" 10#include "jfs_superblock.h" 11#include "jfs_dmap.h" 12#include "jfs_extent.h" 13#include "jfs_debug.h" 14 15/* 16 * forward references 17 */ 18static int extBalloc(struct inode *, s64, s64 *, s64 *); 19static s64 extRoundDown(s64 nb); 20 21#define DPD(a) (printk("(a): %d\n",(a))) 22#define DPC(a) (printk("(a): %c\n",(a))) 23#define DPL1(a) \ 24{ \ 25 if ((a) >> 32) \ 26 printk("(a): %x%08x ",(a)); \ 27 else \ 28 printk("(a): %x ",(a) << 32); \ 29} 30#define DPL(a) \ 31{ \ 32 if ((a) >> 32) \ 33 printk("(a): %x%08x\n",(a)); \ 34 else \ 35 printk("(a): %x\n",(a) << 32); \ 36} 37 38#define DPD1(a) (printk("(a): %d ",(a))) 39#define DPX(a) (printk("(a): %08x\n",(a))) 40#define DPX1(a) (printk("(a): %08x ",(a))) 41#define DPS(a) (printk("%s\n",(a))) 42#define DPE(a) (printk("\nENTERING: %s\n",(a))) 43#define DPE1(a) (printk("\nENTERING: %s",(a))) 44#define DPS1(a) (printk(" %s ",(a))) 45 46 47/* 48 * NAME: extAlloc() 49 * 50 * FUNCTION: allocate an extent for a specified page range within a 51 * file. 52 * 53 * PARAMETERS: 54 * ip - the inode of the file. 55 * xlen - requested extent length. 56 * pno - the starting page number with the file. 57 * xp - pointer to an xad. on entry, xad describes an 58 * extent that is used as an allocation hint if the 59 * xaddr of the xad is non-zero. on successful exit, 60 * the xad describes the newly allocated extent. 61 * abnr - bool indicating whether the newly allocated extent 62 * should be marked as allocated but not recorded. 63 * 64 * RETURN VALUES: 65 * 0 - success 66 * -EIO - i/o error. 67 * -ENOSPC - insufficient disk resources. 68 */ 69int 70extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr) 71{ 72 struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); 73 s64 nxlen, nxaddr, xoff, hint, xaddr = 0; 74 int rc; 75 int xflag; 76 77 /* This blocks if we are low on resources */ 78 txBeginAnon(ip->i_sb); 79 80 /* Avoid race with jfs_commit_inode() */ 81 mutex_lock(&JFS_IP(ip)->commit_mutex); 82 83 /* validate extent length */ 84 if (xlen > MAXXLEN) 85 xlen = MAXXLEN; 86 87 /* get the page's starting extent offset */ 88 xoff = pno << sbi->l2nbperpage; 89 90 /* check if an allocation hint was provided */ 91 if ((hint = addressXAD(xp))) { 92 /* get the size of the extent described by the hint */ 93 nxlen = lengthXAD(xp); 94 95 /* check if the hint is for the portion of the file 96 * immediately previous to the current allocation 97 * request and if hint extent has the same abnr 98 * value as the current request. if so, we can 99 * extend the hint extent to include the current 100 * extent if we can allocate the blocks immediately 101 * following the hint extent. 102 */ 103 if (offsetXAD(xp) + nxlen == xoff && 104 abnr == ((xp->flag & XAD_NOTRECORDED) ? true : false)) 105 xaddr = hint + nxlen; 106 107 /* adjust the hint to the last block of the extent */ 108 hint += (nxlen - 1); 109 } 110 111 /* allocate the disk blocks for the extent. initially, extBalloc() 112 * will try to allocate disk blocks for the requested size (xlen). 113 * if this fails (xlen contiguous free blocks not available), it'll 114 * try to allocate a smaller number of blocks (producing a smaller 115 * extent), with this smaller number of blocks consisting of the 116 * requested number of blocks rounded down to the next smaller 117 * power of 2 number (i.e. 16 -> 8). it'll continue to round down 118 * and retry the allocation until the number of blocks to allocate 119 * is smaller than the number of blocks per page. 120 */ 121 nxlen = xlen; 122 if ((rc = extBalloc(ip, hint ? hint : INOHINT(ip), &nxlen, &nxaddr))) { 123 mutex_unlock(&JFS_IP(ip)->commit_mutex); 124 return (rc); 125 } 126 127 /* Allocate blocks to quota. */ 128 rc = dquot_alloc_block(ip, nxlen); 129 if (rc) { 130 dbFree(ip, nxaddr, (s64) nxlen); 131 mutex_unlock(&JFS_IP(ip)->commit_mutex); 132 return rc; 133 } 134 135 /* determine the value of the extent flag */ 136 xflag = abnr ? XAD_NOTRECORDED : 0; 137 138 /* if we can extend the hint extent to cover the current request, 139 * extend it. otherwise, insert a new extent to 140 * cover the current request. 141 */ 142 if (xaddr && xaddr == nxaddr) 143 rc = xtExtend(0, ip, xoff, (int) nxlen, 0); 144 else 145 rc = xtInsert(0, ip, xflag, xoff, (int) nxlen, &nxaddr, 0); 146 147 /* if the extend or insert failed, 148 * free the newly allocated blocks and return the error. 149 */ 150 if (rc) { 151 dbFree(ip, nxaddr, nxlen); 152 dquot_free_block(ip, nxlen); 153 mutex_unlock(&JFS_IP(ip)->commit_mutex); 154 return (rc); 155 } 156 157 /* set the results of the extent allocation */ 158 XADaddress(xp, nxaddr); 159 XADlength(xp, nxlen); 160 XADoffset(xp, xoff); 161 xp->flag = xflag; 162 163 mark_inode_dirty(ip); 164 165 mutex_unlock(&JFS_IP(ip)->commit_mutex); 166 /* 167 * COMMIT_SyncList flags an anonymous tlock on page that is on 168 * sync list. 169 * We need to commit the inode to get the page written disk. 170 */ 171 if (test_and_clear_cflag(COMMIT_Synclist,ip)) 172 jfs_commit_inode(ip, 0); 173 174 return (0); 175} 176 177/* 178 * NAME: extHint() 179 * 180 * FUNCTION: produce an extent allocation hint for a file offset. 181 * 182 * PARAMETERS: 183 * ip - the inode of the file. 184 * offset - file offset for which the hint is needed. 185 * xp - pointer to the xad that is to be filled in with 186 * the hint. 187 * 188 * RETURN VALUES: 189 * 0 - success 190 * -EIO - i/o error. 191 */ 192int extHint(struct inode *ip, s64 offset, xad_t * xp) 193{ 194 struct super_block *sb = ip->i_sb; 195 int nbperpage = JFS_SBI(sb)->nbperpage; 196 s64 prev; 197 int rc = 0; 198 s64 xaddr; 199 int xlen; 200 int xflag; 201 202 /* init the hint as "no hint provided" */ 203 XADaddress(xp, 0); 204 205 /* determine the starting extent offset of the page previous 206 * to the page containing the offset. 207 */ 208 prev = ((offset & ~POFFSET) >> JFS_SBI(sb)->l2bsize) - nbperpage; 209 210 /* if the offset is in the first page of the file, no hint provided. 211 */ 212 if (prev < 0) 213 goto out; 214 215 rc = xtLookup(ip, prev, nbperpage, &xflag, &xaddr, &xlen, 0); 216 217 if ((rc == 0) && xlen) { 218 if (xlen != nbperpage) { 219 jfs_error(ip->i_sb, "corrupt xtree\n"); 220 rc = -EIO; 221 } 222 XADaddress(xp, xaddr); 223 XADlength(xp, xlen); 224 XADoffset(xp, prev); 225 /* 226 * only preserve the abnr flag within the xad flags 227 * of the returned hint. 228 */ 229 xp->flag = xflag & XAD_NOTRECORDED; 230 } else 231 rc = 0; 232 233out: 234 return (rc); 235} 236 237 238/* 239 * NAME: extRecord() 240 * 241 * FUNCTION: change a page with a file from not recorded to recorded. 242 * 243 * PARAMETERS: 244 * ip - inode of the file. 245 * cp - cbuf of the file page. 246 * 247 * RETURN VALUES: 248 * 0 - success 249 * -EIO - i/o error. 250 * -ENOSPC - insufficient disk resources. 251 */ 252int extRecord(struct inode *ip, xad_t * xp) 253{ 254 int rc; 255 256 txBeginAnon(ip->i_sb); 257 258 mutex_lock(&JFS_IP(ip)->commit_mutex); 259 260 /* update the extent */ 261 rc = xtUpdate(0, ip, xp); 262 263 mutex_unlock(&JFS_IP(ip)->commit_mutex); 264 return rc; 265} 266 267/* 268 * NAME: extBalloc() 269 * 270 * FUNCTION: allocate disk blocks to form an extent. 271 * 272 * initially, we will try to allocate disk blocks for the 273 * requested size (nblocks). if this fails (nblocks 274 * contiguous free blocks not available), we'll try to allocate 275 * a smaller number of blocks (producing a smaller extent), with 276 * this smaller number of blocks consisting of the requested 277 * number of blocks rounded down to the next smaller power of 2 278 * number (i.e. 16 -> 8). we'll continue to round down and 279 * retry the allocation until the number of blocks to allocate 280 * is smaller than the number of blocks per page. 281 * 282 * PARAMETERS: 283 * ip - the inode of the file. 284 * hint - disk block number to be used as an allocation hint. 285 * *nblocks - pointer to an s64 value. on entry, this value specifies 286 * the desired number of block to be allocated. on successful 287 * exit, this value is set to the number of blocks actually 288 * allocated. 289 * blkno - pointer to a block address that is filled in on successful 290 * return with the starting block number of the newly 291 * allocated block range. 292 * 293 * RETURN VALUES: 294 * 0 - success 295 * -EIO - i/o error. 296 * -ENOSPC - insufficient disk resources. 297 */ 298static int 299extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno) 300{ 301 struct jfs_inode_info *ji = JFS_IP(ip); 302 struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); 303 s64 nb, nblks, daddr, max; 304 int rc, nbperpage = sbi->nbperpage; 305 struct bmap *bmp = sbi->bmap; 306 int ag; 307 308 /* get the number of blocks to initially attempt to allocate. 309 * we'll first try the number of blocks requested unless this 310 * number is greater than the maximum number of contiguous free 311 * blocks in the map. in that case, we'll start off with the 312 * maximum free. 313 */ 314 max = (s64) 1 << bmp->db_maxfreebud; 315 if (*nblocks >= max && *nblocks > nbperpage) 316 nb = nblks = (max > nbperpage) ? max : nbperpage; 317 else 318 nb = nblks = *nblocks; 319 320 /* try to allocate blocks */ 321 while ((rc = dbAlloc(ip, hint, nb, &daddr)) != 0) { 322 /* if something other than an out of space error, 323 * stop and return this error. 324 */ 325 if (rc != -ENOSPC) 326 return (rc); 327 328 /* decrease the allocation request size */ 329 nb = min(nblks, extRoundDown(nb)); 330 331 /* give up if we cannot cover a page */ 332 if (nb < nbperpage) 333 return (rc); 334 } 335 336 *nblocks = nb; 337 *blkno = daddr; 338 339 if (S_ISREG(ip->i_mode) && (ji->fileset == FILESYSTEM_I)) { 340 ag = BLKTOAG(daddr, sbi); 341 spin_lock_irq(&ji->ag_lock); 342 if (ji->active_ag == -1) { 343 atomic_inc(&bmp->db_active[ag]); 344 ji->active_ag = ag; 345 } else if (ji->active_ag != ag) { 346 atomic_dec(&bmp->db_active[ji->active_ag]); 347 atomic_inc(&bmp->db_active[ag]); 348 ji->active_ag = ag; 349 } 350 spin_unlock_irq(&ji->ag_lock); 351 } 352 353 return (0); 354} 355 356/* 357 * NAME: extRoundDown() 358 * 359 * FUNCTION: round down a specified number of blocks to the next 360 * smallest power of 2 number. 361 * 362 * PARAMETERS: 363 * nb - the inode of the file. 364 * 365 * RETURN VALUES: 366 * next smallest power of 2 number. 367 */ 368static s64 extRoundDown(s64 nb) 369{ 370 int i; 371 u64 m, k; 372 373 for (i = 0, m = (u64) 1 << 63; i < 64; i++, m >>= 1) { 374 if (m & nb) 375 break; 376 } 377 378 i = 63 - i; 379 k = (u64) 1 << i; 380 k = ((k - 1) & nb) ? k : k >> 1; 381 382 return (k); 383}