1 // SPDX-License-Identifier: GPL-2.0-or-later 1 2 /* 3 * Copyright (C) International Business Mach 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 */ 18 static int extBalloc(struct inode *, s64, s64 19 static 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", 40 #define DPX1(a) (printk("(a): %08x ", 41 #define DPS(a) (printk("%s\n",(a))) 42 #define DPE(a) (printk("\nENTERING: % 43 #define DPE1(a) (printk("\nENTERING: % 44 #define DPS1(a) (printk(" %s ",(a))) 45 46 47 /* 48 * NAME: extAlloc() 49 * 50 * FUNCTION: allocate an extent for a speci 51 * file. 52 * 53 * PARAMETERS: 54 * ip - the inode of the file. 55 * xlen - requested extent length. 56 * pno - the starting page number wit 57 * xp - pointer to an xad. on entry 58 * extent that is used as an al 59 * xaddr of the xad is non-zero 60 * the xad describes the newly 61 * abnr - bool indicating whether the 62 * should be marked as allocate 63 * 64 * RETURN VALUES: 65 * 0 - success 66 * -EIO - i/o error. 67 * -ENOSPC - insufficient disk resources. 68 */ 69 int 70 extAlloc(struct inode *ip, s64 xlen, s64 pno, 71 { 72 struct jfs_sb_info *sbi = JFS_SBI(ip-> 73 s64 nxlen, nxaddr, xoff, hint, xaddr = 74 int rc; 75 int xflag; 76 77 /* This blocks if we are low on resour 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 offs 88 xoff = pno << sbi->l2nbperpage; 89 90 /* check if an allocation hint was pro 91 if ((hint = addressXAD(xp))) { 92 /* get the size of the extent 93 nxlen = lengthXAD(xp); 94 95 /* check if the hint is for th 96 * immediately previous to the 97 * request and if hint extent 98 * value as the current reques 99 * extend the hint extent to i 100 * extent if we can allocate t 101 * following the hint extent. 102 */ 103 if (offsetXAD(xp) + nxlen == x 104 abnr == ((xp->flag & XAD_N 105 xaddr = hint + nxlen; 106 107 /* adjust the hint to the last 108 hint += (nxlen - 1); 109 } 110 111 /* allocate the disk blocks for the ex 112 * will try to allocate disk blocks fo 113 * if this fails (xlen contiguous free 114 * try to allocate a smaller number of 115 * extent), with this smaller number o 116 * requested number of blocks rounded 117 * power of 2 number (i.e. 16 -> 8). 118 * and retry the allocation until the 119 * is smaller than the number of block 120 */ 121 nxlen = xlen; 122 if ((rc = extBalloc(ip, hint ? hint : 123 mutex_unlock(&JFS_IP(ip)->comm 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)->comm 132 return rc; 133 } 134 135 /* determine the value of the extent f 136 xflag = abnr ? XAD_NOTRECORDED : 0; 137 138 /* if we can extend the hint extent to 139 * extend it. otherwise, insert a new 140 * cover the current request. 141 */ 142 if (xaddr && xaddr == nxaddr) 143 rc = xtExtend(0, ip, xoff, (in 144 else 145 rc = xtInsert(0, ip, xflag, xo 146 147 /* if the extend or insert failed, 148 * free the newly allocated blocks and 149 */ 150 if (rc) { 151 dbFree(ip, nxaddr, nxlen); 152 dquot_free_block(ip, nxlen); 153 mutex_unlock(&JFS_IP(ip)->comm 154 return (rc); 155 } 156 157 /* set the results of the extent alloc 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 168 * sync list. 169 * We need to commit the inode to get 170 */ 171 if (test_and_clear_cflag(COMMIT_Syncli 172 jfs_commit_inode(ip, 0); 173 174 return (0); 175 } 176 177 /* 178 * NAME: extHint() 179 * 180 * FUNCTION: produce an extent allocation h 181 * 182 * PARAMETERS: 183 * ip - the inode of the file. 184 * offset - file offset for which the hi 185 * xp - pointer to the xad that is t 186 * the hint. 187 * 188 * RETURN VALUES: 189 * 0 - success 190 * -EIO - i/o error. 191 */ 192 int extHint(struct inode *ip, s64 offset, xad_ 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 offse 206 * to the page containing the offset. 207 */ 208 prev = ((offset & ~POFFSET) >> JFS_SBI 209 210 /* if the offset is in the first page 211 */ 212 if (prev < 0) 213 goto out; 214 215 rc = xtLookup(ip, prev, nbperpage, &xf 216 217 if ((rc == 0) && xlen) { 218 if (xlen != nbperpage) { 219 jfs_error(ip->i_sb, "c 220 rc = -EIO; 221 } 222 XADaddress(xp, xaddr); 223 XADlength(xp, xlen); 224 XADoffset(xp, prev); 225 /* 226 * only preserve the abnr flag 227 * of the returned hint. 228 */ 229 xp->flag = xflag & XAD_NOTREC 230 } else 231 rc = 0; 232 233 out: 234 return (rc); 235 } 236 237 238 /* 239 * NAME: extRecord() 240 * 241 * FUNCTION: change a page with a file from 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 */ 252 int 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 a 271 * 272 * initially, we will try to allo 273 * requested size (nblocks). if 274 * contiguous free blocks not ava 275 * a smaller number of blocks (pr 276 * this smaller number of blocks 277 * number of blocks rounded down 278 * number (i.e. 16 -> 8). we'll 279 * retry the allocation until the 280 * is smaller than the number of 281 * 282 * PARAMETERS: 283 * ip - the inode of the file. 284 * hint - disk block number to be use 285 * *nblocks - pointer to an s64 value. o 286 * the desired number of block 287 * exit, this value is set to 288 * allocated. 289 * blkno - pointer to a block address 290 * return with the starting bl 291 * allocated block range. 292 * 293 * RETURN VALUES: 294 * 0 - success 295 * -EIO - i/o error. 296 * -ENOSPC - insufficient disk resources. 297 */ 298 static int 299 extBalloc(struct inode *ip, s64 hint, s64 * nb 300 { 301 struct jfs_inode_info *ji = JFS_IP(ip) 302 struct jfs_sb_info *sbi = JFS_SBI(ip-> 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 initial 309 * we'll first try the number of block 310 * number is greater than the maximum 311 * blocks in the map. in that case, we 312 * maximum free. 313 */ 314 315 /* give up if no space left */ 316 if (bmp->db_maxfreebud == -1) 317 return -ENOSPC; 318 319 max = (s64) 1 << bmp->db_maxfreebud; 320 if (*nblocks >= max && *nblocks > nbpe 321 nb = nblks = (max > nbperpage) 322 else 323 nb = nblks = *nblocks; 324 325 /* try to allocate blocks */ 326 while ((rc = dbAlloc(ip, hint, nb, &da 327 /* if something other than an 328 * stop and return this error. 329 */ 330 if (rc != -ENOSPC) 331 return (rc); 332 333 /* decrease the allocation req 334 nb = min(nblks, extRoundDown(n 335 336 /* give up if we cannot cover 337 if (nb < nbperpage) 338 return (rc); 339 } 340 341 *nblocks = nb; 342 *blkno = daddr; 343 344 if (S_ISREG(ip->i_mode) && (ji->filese 345 ag = BLKTOAG(daddr, sbi); 346 spin_lock_irq(&ji->ag_lock); 347 if (ji->active_ag == -1) { 348 atomic_inc(&bmp->db_ac 349 ji->active_ag = ag; 350 } else if (ji->active_ag != ag 351 atomic_dec(&bmp->db_ac 352 atomic_inc(&bmp->db_ac 353 ji->active_ag = ag; 354 } 355 spin_unlock_irq(&ji->ag_lock); 356 } 357 358 return (0); 359 } 360 361 /* 362 * NAME: extRoundDown() 363 * 364 * FUNCTION: round down a specified number 365 * smallest power of 2 number. 366 * 367 * PARAMETERS: 368 * nb - the inode of the file. 369 * 370 * RETURN VALUES: 371 * next smallest power of 2 number. 372 */ 373 static s64 extRoundDown(s64 nb) 374 { 375 int i; 376 u64 m, k; 377 378 for (i = 0, m = (u64) 1 << 63; i < 64; 379 if (m & nb) 380 break; 381 } 382 383 i = 63 - i; 384 k = (u64) 1 << i; 385 k = ((k - 1) & nb) ? k : k >> 1; 386 387 return (k); 388 } 389
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.