Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *   Copyright (C) International Business Machines Corp., 2000-2004
0004  */
0005 
0006 #include <linux/fs.h>
0007 #include <linux/quotaops.h>
0008 #include "jfs_incore.h"
0009 #include "jfs_inode.h"
0010 #include "jfs_superblock.h"
0011 #include "jfs_dmap.h"
0012 #include "jfs_extent.h"
0013 #include "jfs_debug.h"
0014 
0015 /*
0016  * forward references
0017  */
0018 static int extBalloc(struct inode *, s64, s64 *, s64 *);
0019 static s64 extRoundDown(s64 nb);
0020 
0021 #define DPD(a)      (printk("(a): %d\n",(a)))
0022 #define DPC(a)      (printk("(a): %c\n",(a)))
0023 #define DPL1(a)                 \
0024 {                       \
0025     if ((a) >> 32)              \
0026         printk("(a): %x%08x  ",(a));    \
0027     else                    \
0028         printk("(a): %x  ",(a) << 32);  \
0029 }
0030 #define DPL(a)                  \
0031 {                       \
0032     if ((a) >> 32)              \
0033         printk("(a): %x%08x\n",(a));    \
0034     else                    \
0035         printk("(a): %x\n",(a) << 32);  \
0036 }
0037 
0038 #define DPD1(a)     (printk("(a): %d  ",(a)))
0039 #define DPX(a)      (printk("(a): %08x\n",(a)))
0040 #define DPX1(a)     (printk("(a): %08x  ",(a)))
0041 #define DPS(a)      (printk("%s\n",(a)))
0042 #define DPE(a)      (printk("\nENTERING: %s\n",(a)))
0043 #define DPE1(a)     (printk("\nENTERING: %s",(a)))
0044 #define DPS1(a)     (printk("  %s  ",(a)))
0045 
0046 
0047 /*
0048  * NAME:    extAlloc()
0049  *
0050  * FUNCTION:    allocate an extent for a specified page range within a
0051  *      file.
0052  *
0053  * PARAMETERS:
0054  *  ip  - the inode of the file.
0055  *  xlen    - requested extent length.
0056  *  pno - the starting page number with the file.
0057  *  xp  - pointer to an xad.  on entry, xad describes an
0058  *        extent that is used as an allocation hint if the
0059  *        xaddr of the xad is non-zero.  on successful exit,
0060  *        the xad describes the newly allocated extent.
0061  *  abnr    - bool indicating whether the newly allocated extent
0062  *        should be marked as allocated but not recorded.
0063  *
0064  * RETURN VALUES:
0065  *  0   - success
0066  *  -EIO    - i/o error.
0067  *  -ENOSPC - insufficient disk resources.
0068  */
0069 int
0070 extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr)
0071 {
0072     struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
0073     s64 nxlen, nxaddr, xoff, hint, xaddr = 0;
0074     int rc;
0075     int xflag;
0076 
0077     /* This blocks if we are low on resources */
0078     txBeginAnon(ip->i_sb);
0079 
0080     /* Avoid race with jfs_commit_inode() */
0081     mutex_lock(&JFS_IP(ip)->commit_mutex);
0082 
0083     /* validate extent length */
0084     if (xlen > MAXXLEN)
0085         xlen = MAXXLEN;
0086 
0087     /* get the page's starting extent offset */
0088     xoff = pno << sbi->l2nbperpage;
0089 
0090     /* check if an allocation hint was provided */
0091     if ((hint = addressXAD(xp))) {
0092         /* get the size of the extent described by the hint */
0093         nxlen = lengthXAD(xp);
0094 
0095         /* check if the hint is for the portion of the file
0096          * immediately previous to the current allocation
0097          * request and if hint extent has the same abnr
0098          * value as the current request.  if so, we can
0099          * extend the hint extent to include the current
0100          * extent if we can allocate the blocks immediately
0101          * following the hint extent.
0102          */
0103         if (offsetXAD(xp) + nxlen == xoff &&
0104             abnr == ((xp->flag & XAD_NOTRECORDED) ? true : false))
0105             xaddr = hint + nxlen;
0106 
0107         /* adjust the hint to the last block of the extent */
0108         hint += (nxlen - 1);
0109     }
0110 
0111     /* allocate the disk blocks for the extent.  initially, extBalloc()
0112      * will try to allocate disk blocks for the requested size (xlen).
0113      * if this fails (xlen contiguous free blocks not available), it'll
0114      * try to allocate a smaller number of blocks (producing a smaller
0115      * extent), with this smaller number of blocks consisting of the
0116      * requested number of blocks rounded down to the next smaller
0117      * power of 2 number (i.e. 16 -> 8).  it'll continue to round down
0118      * and retry the allocation until the number of blocks to allocate
0119      * is smaller than the number of blocks per page.
0120      */
0121     nxlen = xlen;
0122     if ((rc = extBalloc(ip, hint ? hint : INOHINT(ip), &nxlen, &nxaddr))) {
0123         mutex_unlock(&JFS_IP(ip)->commit_mutex);
0124         return (rc);
0125     }
0126 
0127     /* Allocate blocks to quota. */
0128     rc = dquot_alloc_block(ip, nxlen);
0129     if (rc) {
0130         dbFree(ip, nxaddr, (s64) nxlen);
0131         mutex_unlock(&JFS_IP(ip)->commit_mutex);
0132         return rc;
0133     }
0134 
0135     /* determine the value of the extent flag */
0136     xflag = abnr ? XAD_NOTRECORDED : 0;
0137 
0138     /* if we can extend the hint extent to cover the current request,
0139      * extend it.  otherwise, insert a new extent to
0140      * cover the current request.
0141      */
0142     if (xaddr && xaddr == nxaddr)
0143         rc = xtExtend(0, ip, xoff, (int) nxlen, 0);
0144     else
0145         rc = xtInsert(0, ip, xflag, xoff, (int) nxlen, &nxaddr, 0);
0146 
0147     /* if the extend or insert failed,
0148      * free the newly allocated blocks and return the error.
0149      */
0150     if (rc) {
0151         dbFree(ip, nxaddr, nxlen);
0152         dquot_free_block(ip, nxlen);
0153         mutex_unlock(&JFS_IP(ip)->commit_mutex);
0154         return (rc);
0155     }
0156 
0157     /* set the results of the extent allocation */
0158     XADaddress(xp, nxaddr);
0159     XADlength(xp, nxlen);
0160     XADoffset(xp, xoff);
0161     xp->flag = xflag;
0162 
0163     mark_inode_dirty(ip);
0164 
0165     mutex_unlock(&JFS_IP(ip)->commit_mutex);
0166     /*
0167      * COMMIT_SyncList flags an anonymous tlock on page that is on
0168      * sync list.
0169      * We need to commit the inode to get the page written disk.
0170      */
0171     if (test_and_clear_cflag(COMMIT_Synclist,ip))
0172         jfs_commit_inode(ip, 0);
0173 
0174     return (0);
0175 }
0176 
0177 /*
0178  * NAME:    extHint()
0179  *
0180  * FUNCTION:    produce an extent allocation hint for a file offset.
0181  *
0182  * PARAMETERS:
0183  *  ip  - the inode of the file.
0184  *  offset  - file offset for which the hint is needed.
0185  *  xp  - pointer to the xad that is to be filled in with
0186  *        the hint.
0187  *
0188  * RETURN VALUES:
0189  *  0   - success
0190  *  -EIO    - i/o error.
0191  */
0192 int extHint(struct inode *ip, s64 offset, xad_t * xp)
0193 {
0194     struct super_block *sb = ip->i_sb;
0195     int nbperpage = JFS_SBI(sb)->nbperpage;
0196     s64 prev;
0197     int rc = 0;
0198     s64 xaddr;
0199     int xlen;
0200     int xflag;
0201 
0202     /* init the hint as "no hint provided" */
0203     XADaddress(xp, 0);
0204 
0205     /* determine the starting extent offset of the page previous
0206      * to the page containing the offset.
0207      */
0208     prev = ((offset & ~POFFSET) >> JFS_SBI(sb)->l2bsize) - nbperpage;
0209 
0210     /* if the offset is in the first page of the file, no hint provided.
0211      */
0212     if (prev < 0)
0213         goto out;
0214 
0215     rc = xtLookup(ip, prev, nbperpage, &xflag, &xaddr, &xlen, 0);
0216 
0217     if ((rc == 0) && xlen) {
0218         if (xlen != nbperpage) {
0219             jfs_error(ip->i_sb, "corrupt xtree\n");
0220             rc = -EIO;
0221         }
0222         XADaddress(xp, xaddr);
0223         XADlength(xp, xlen);
0224         XADoffset(xp, prev);
0225         /*
0226          * only preserve the abnr flag within the xad flags
0227          * of the returned hint.
0228          */
0229         xp->flag  = xflag & XAD_NOTRECORDED;
0230     } else
0231         rc = 0;
0232 
0233 out:
0234     return (rc);
0235 }
0236 
0237 
0238 /*
0239  * NAME:    extRecord()
0240  *
0241  * FUNCTION:    change a page with a file from not recorded to recorded.
0242  *
0243  * PARAMETERS:
0244  *  ip  - inode of the file.
0245  *  cp  - cbuf of the file page.
0246  *
0247  * RETURN VALUES:
0248  *  0   - success
0249  *  -EIO    - i/o error.
0250  *  -ENOSPC - insufficient disk resources.
0251  */
0252 int extRecord(struct inode *ip, xad_t * xp)
0253 {
0254     int rc;
0255 
0256     txBeginAnon(ip->i_sb);
0257 
0258     mutex_lock(&JFS_IP(ip)->commit_mutex);
0259 
0260     /* update the extent */
0261     rc = xtUpdate(0, ip, xp);
0262 
0263     mutex_unlock(&JFS_IP(ip)->commit_mutex);
0264     return rc;
0265 }
0266 
0267 /*
0268  * NAME:    extBalloc()
0269  *
0270  * FUNCTION:    allocate disk blocks to form an extent.
0271  *
0272  *      initially, we will try to allocate disk blocks for the
0273  *      requested size (nblocks).  if this fails (nblocks
0274  *      contiguous free blocks not available), we'll try to allocate
0275  *      a smaller number of blocks (producing a smaller extent), with
0276  *      this smaller number of blocks consisting of the requested
0277  *      number of blocks rounded down to the next smaller power of 2
0278  *      number (i.e. 16 -> 8).  we'll continue to round down and
0279  *      retry the allocation until the number of blocks to allocate
0280  *      is smaller than the number of blocks per page.
0281  *
0282  * PARAMETERS:
0283  *  ip   - the inode of the file.
0284  *  hint     - disk block number to be used as an allocation hint.
0285  *  *nblocks - pointer to an s64 value.  on entry, this value specifies
0286  *         the desired number of block to be allocated. on successful
0287  *         exit, this value is set to the number of blocks actually
0288  *         allocated.
0289  *  blkno    - pointer to a block address that is filled in on successful
0290  *         return with the starting block number of the newly
0291  *         allocated block range.
0292  *
0293  * RETURN VALUES:
0294  *  0   - success
0295  *  -EIO    - i/o error.
0296  *  -ENOSPC - insufficient disk resources.
0297  */
0298 static int
0299 extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno)
0300 {
0301     struct jfs_inode_info *ji = JFS_IP(ip);
0302     struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
0303     s64 nb, nblks, daddr, max;
0304     int rc, nbperpage = sbi->nbperpage;
0305     struct bmap *bmp = sbi->bmap;
0306     int ag;
0307 
0308     /* get the number of blocks to initially attempt to allocate.
0309      * we'll first try the number of blocks requested unless this
0310      * number is greater than the maximum number of contiguous free
0311      * blocks in the map. in that case, we'll start off with the
0312      * maximum free.
0313      */
0314     max = (s64) 1 << bmp->db_maxfreebud;
0315     if (*nblocks >= max && *nblocks > nbperpage)
0316         nb = nblks = (max > nbperpage) ? max : nbperpage;
0317     else
0318         nb = nblks = *nblocks;
0319 
0320     /* try to allocate blocks */
0321     while ((rc = dbAlloc(ip, hint, nb, &daddr)) != 0) {
0322         /* if something other than an out of space error,
0323          * stop and return this error.
0324          */
0325         if (rc != -ENOSPC)
0326             return (rc);
0327 
0328         /* decrease the allocation request size */
0329         nb = min(nblks, extRoundDown(nb));
0330 
0331         /* give up if we cannot cover a page */
0332         if (nb < nbperpage)
0333             return (rc);
0334     }
0335 
0336     *nblocks = nb;
0337     *blkno = daddr;
0338 
0339     if (S_ISREG(ip->i_mode) && (ji->fileset == FILESYSTEM_I)) {
0340         ag = BLKTOAG(daddr, sbi);
0341         spin_lock_irq(&ji->ag_lock);
0342         if (ji->active_ag == -1) {
0343             atomic_inc(&bmp->db_active[ag]);
0344             ji->active_ag = ag;
0345         } else if (ji->active_ag != ag) {
0346             atomic_dec(&bmp->db_active[ji->active_ag]);
0347             atomic_inc(&bmp->db_active[ag]);
0348             ji->active_ag = ag;
0349         }
0350         spin_unlock_irq(&ji->ag_lock);
0351     }
0352 
0353     return (0);
0354 }
0355 
0356 /*
0357  * NAME:    extRoundDown()
0358  *
0359  * FUNCTION:    round down a specified number of blocks to the next
0360  *      smallest power of 2 number.
0361  *
0362  * PARAMETERS:
0363  *  nb  - the inode of the file.
0364  *
0365  * RETURN VALUES:
0366  *  next smallest power of 2 number.
0367  */
0368 static s64 extRoundDown(s64 nb)
0369 {
0370     int i;
0371     u64 m, k;
0372 
0373     for (i = 0, m = (u64) 1 << 63; i < 64; i++, m >>= 1) {
0374         if (m & nb)
0375             break;
0376     }
0377 
0378     i = 63 - i;
0379     k = (u64) 1 << i;
0380     k = ((k - 1) & nb) ? k : k >> 1;
0381 
0382     return (k);
0383 }