11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Copyright (C) International Business Machines Corp., 2000-2004
41da177e4SLinus Torvalds */
51da177e4SLinus Torvalds
61da177e4SLinus Torvalds #include <linux/fs.h>
71da177e4SLinus Torvalds #include <linux/quotaops.h>
81da177e4SLinus Torvalds #include "jfs_incore.h"
91868f4aaSDave Kleikamp #include "jfs_inode.h"
101da177e4SLinus Torvalds #include "jfs_superblock.h"
111da177e4SLinus Torvalds #include "jfs_dmap.h"
121da177e4SLinus Torvalds #include "jfs_extent.h"
131da177e4SLinus Torvalds #include "jfs_debug.h"
141da177e4SLinus Torvalds
151da177e4SLinus Torvalds /*
161da177e4SLinus Torvalds * forward references
171da177e4SLinus Torvalds */
181da177e4SLinus Torvalds static int extBalloc(struct inode *, s64, s64 *, s64 *);
191da177e4SLinus Torvalds static s64 extRoundDown(s64 nb);
201da177e4SLinus Torvalds
211da177e4SLinus Torvalds #define DPD(a) (printk("(a): %d\n",(a)))
221da177e4SLinus Torvalds #define DPC(a) (printk("(a): %c\n",(a)))
231da177e4SLinus Torvalds #define DPL1(a) \
241da177e4SLinus Torvalds { \
251da177e4SLinus Torvalds if ((a) >> 32) \
261da177e4SLinus Torvalds printk("(a): %x%08x ",(a)); \
271da177e4SLinus Torvalds else \
281da177e4SLinus Torvalds printk("(a): %x ",(a) << 32); \
291da177e4SLinus Torvalds }
301da177e4SLinus Torvalds #define DPL(a) \
311da177e4SLinus Torvalds { \
321da177e4SLinus Torvalds if ((a) >> 32) \
331da177e4SLinus Torvalds printk("(a): %x%08x\n",(a)); \
341da177e4SLinus Torvalds else \
351da177e4SLinus Torvalds printk("(a): %x\n",(a) << 32); \
361da177e4SLinus Torvalds }
371da177e4SLinus Torvalds
381da177e4SLinus Torvalds #define DPD1(a) (printk("(a): %d ",(a)))
391da177e4SLinus Torvalds #define DPX(a) (printk("(a): %08x\n",(a)))
401da177e4SLinus Torvalds #define DPX1(a) (printk("(a): %08x ",(a)))
411da177e4SLinus Torvalds #define DPS(a) (printk("%s\n",(a)))
421da177e4SLinus Torvalds #define DPE(a) (printk("\nENTERING: %s\n",(a)))
431da177e4SLinus Torvalds #define DPE1(a) (printk("\nENTERING: %s",(a)))
441da177e4SLinus Torvalds #define DPS1(a) (printk(" %s ",(a)))
451da177e4SLinus Torvalds
461da177e4SLinus Torvalds
471da177e4SLinus Torvalds /*
481da177e4SLinus Torvalds * NAME: extAlloc()
491da177e4SLinus Torvalds *
501da177e4SLinus Torvalds * FUNCTION: allocate an extent for a specified page range within a
511da177e4SLinus Torvalds * file.
521da177e4SLinus Torvalds *
531da177e4SLinus Torvalds * PARAMETERS:
541da177e4SLinus Torvalds * ip - the inode of the file.
551da177e4SLinus Torvalds * xlen - requested extent length.
561da177e4SLinus Torvalds * pno - the starting page number with the file.
571da177e4SLinus Torvalds * xp - pointer to an xad. on entry, xad describes an
581da177e4SLinus Torvalds * extent that is used as an allocation hint if the
591da177e4SLinus Torvalds * xaddr of the xad is non-zero. on successful exit,
601da177e4SLinus Torvalds * the xad describes the newly allocated extent.
614d81715fSRichard Knutsson * abnr - bool indicating whether the newly allocated extent
621da177e4SLinus Torvalds * should be marked as allocated but not recorded.
631da177e4SLinus Torvalds *
641da177e4SLinus Torvalds * RETURN VALUES:
651da177e4SLinus Torvalds * 0 - success
661da177e4SLinus Torvalds * -EIO - i/o error.
671da177e4SLinus Torvalds * -ENOSPC - insufficient disk resources.
681da177e4SLinus Torvalds */
691da177e4SLinus Torvalds int
extAlloc(struct inode * ip,s64 xlen,s64 pno,xad_t * xp,bool abnr)704d81715fSRichard Knutsson extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr)
711da177e4SLinus Torvalds {
721da177e4SLinus Torvalds struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
731da177e4SLinus Torvalds s64 nxlen, nxaddr, xoff, hint, xaddr = 0;
741da177e4SLinus Torvalds int rc;
751da177e4SLinus Torvalds int xflag;
761da177e4SLinus Torvalds
771da177e4SLinus Torvalds /* This blocks if we are low on resources */
781da177e4SLinus Torvalds txBeginAnon(ip->i_sb);
791da177e4SLinus Torvalds
801da177e4SLinus Torvalds /* Avoid race with jfs_commit_inode() */
811de87444SIngo Molnar mutex_lock(&JFS_IP(ip)->commit_mutex);
821da177e4SLinus Torvalds
831da177e4SLinus Torvalds /* validate extent length */
841da177e4SLinus Torvalds if (xlen > MAXXLEN)
851da177e4SLinus Torvalds xlen = MAXXLEN;
861da177e4SLinus Torvalds
871da177e4SLinus Torvalds /* get the page's starting extent offset */
881da177e4SLinus Torvalds xoff = pno << sbi->l2nbperpage;
891da177e4SLinus Torvalds
901da177e4SLinus Torvalds /* check if an allocation hint was provided */
911da177e4SLinus Torvalds if ((hint = addressXAD(xp))) {
921da177e4SLinus Torvalds /* get the size of the extent described by the hint */
931da177e4SLinus Torvalds nxlen = lengthXAD(xp);
941da177e4SLinus Torvalds
951da177e4SLinus Torvalds /* check if the hint is for the portion of the file
961da177e4SLinus Torvalds * immediately previous to the current allocation
971da177e4SLinus Torvalds * request and if hint extent has the same abnr
981da177e4SLinus Torvalds * value as the current request. if so, we can
991da177e4SLinus Torvalds * extend the hint extent to include the current
1001da177e4SLinus Torvalds * extent if we can allocate the blocks immediately
1011da177e4SLinus Torvalds * following the hint extent.
1021da177e4SLinus Torvalds */
1031da177e4SLinus Torvalds if (offsetXAD(xp) + nxlen == xoff &&
1044d81715fSRichard Knutsson abnr == ((xp->flag & XAD_NOTRECORDED) ? true : false))
1051da177e4SLinus Torvalds xaddr = hint + nxlen;
1061da177e4SLinus Torvalds
1071da177e4SLinus Torvalds /* adjust the hint to the last block of the extent */
1081da177e4SLinus Torvalds hint += (nxlen - 1);
1091da177e4SLinus Torvalds }
1101da177e4SLinus Torvalds
1111da177e4SLinus Torvalds /* allocate the disk blocks for the extent. initially, extBalloc()
1121da177e4SLinus Torvalds * will try to allocate disk blocks for the requested size (xlen).
11325985edcSLucas De Marchi * if this fails (xlen contiguous free blocks not available), it'll
1141da177e4SLinus Torvalds * try to allocate a smaller number of blocks (producing a smaller
1151da177e4SLinus Torvalds * extent), with this smaller number of blocks consisting of the
1161da177e4SLinus Torvalds * requested number of blocks rounded down to the next smaller
1171da177e4SLinus Torvalds * power of 2 number (i.e. 16 -> 8). it'll continue to round down
1181da177e4SLinus Torvalds * and retry the allocation until the number of blocks to allocate
1191da177e4SLinus Torvalds * is smaller than the number of blocks per page.
1201da177e4SLinus Torvalds */
1211da177e4SLinus Torvalds nxlen = xlen;
1221da177e4SLinus Torvalds if ((rc = extBalloc(ip, hint ? hint : INOHINT(ip), &nxlen, &nxaddr))) {
1231de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
1241da177e4SLinus Torvalds return (rc);
1251da177e4SLinus Torvalds }
1261da177e4SLinus Torvalds
1271da177e4SLinus Torvalds /* Allocate blocks to quota. */
1285dd4056dSChristoph Hellwig rc = dquot_alloc_block(ip, nxlen);
1295dd4056dSChristoph Hellwig if (rc) {
1301da177e4SLinus Torvalds dbFree(ip, nxaddr, (s64) nxlen);
1311de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
1325dd4056dSChristoph Hellwig return rc;
1331da177e4SLinus Torvalds }
1341da177e4SLinus Torvalds
1351da177e4SLinus Torvalds /* determine the value of the extent flag */
1364d81715fSRichard Knutsson xflag = abnr ? XAD_NOTRECORDED : 0;
1371da177e4SLinus Torvalds
1381da177e4SLinus Torvalds /* if we can extend the hint extent to cover the current request,
1391da177e4SLinus Torvalds * extend it. otherwise, insert a new extent to
1401da177e4SLinus Torvalds * cover the current request.
1411da177e4SLinus Torvalds */
1421da177e4SLinus Torvalds if (xaddr && xaddr == nxaddr)
1431da177e4SLinus Torvalds rc = xtExtend(0, ip, xoff, (int) nxlen, 0);
1441da177e4SLinus Torvalds else
1451da177e4SLinus Torvalds rc = xtInsert(0, ip, xflag, xoff, (int) nxlen, &nxaddr, 0);
1461da177e4SLinus Torvalds
1471da177e4SLinus Torvalds /* if the extend or insert failed,
1481da177e4SLinus Torvalds * free the newly allocated blocks and return the error.
1491da177e4SLinus Torvalds */
1501da177e4SLinus Torvalds if (rc) {
1511da177e4SLinus Torvalds dbFree(ip, nxaddr, nxlen);
1525dd4056dSChristoph Hellwig dquot_free_block(ip, nxlen);
1531de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
1541da177e4SLinus Torvalds return (rc);
1551da177e4SLinus Torvalds }
1561da177e4SLinus Torvalds
1571da177e4SLinus Torvalds /* set the results of the extent allocation */
1581da177e4SLinus Torvalds XADaddress(xp, nxaddr);
1591da177e4SLinus Torvalds XADlength(xp, nxlen);
1601da177e4SLinus Torvalds XADoffset(xp, xoff);
1611da177e4SLinus Torvalds xp->flag = xflag;
1621da177e4SLinus Torvalds
1631da177e4SLinus Torvalds mark_inode_dirty(ip);
1641da177e4SLinus Torvalds
1651de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
1661da177e4SLinus Torvalds /*
1671da177e4SLinus Torvalds * COMMIT_SyncList flags an anonymous tlock on page that is on
1681da177e4SLinus Torvalds * sync list.
169c67235d0SImmad Mir * We need to commit the inode to get the page written to the disk.
1701da177e4SLinus Torvalds */
1711da177e4SLinus Torvalds if (test_and_clear_cflag(COMMIT_Synclist,ip))
1721da177e4SLinus Torvalds jfs_commit_inode(ip, 0);
1731da177e4SLinus Torvalds
1741da177e4SLinus Torvalds return (0);
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds
1771da177e4SLinus Torvalds /*
1781da177e4SLinus Torvalds * NAME: extHint()
1791da177e4SLinus Torvalds *
1801da177e4SLinus Torvalds * FUNCTION: produce an extent allocation hint for a file offset.
1811da177e4SLinus Torvalds *
1821da177e4SLinus Torvalds * PARAMETERS:
1831da177e4SLinus Torvalds * ip - the inode of the file.
1841da177e4SLinus Torvalds * offset - file offset for which the hint is needed.
1851da177e4SLinus Torvalds * xp - pointer to the xad that is to be filled in with
1861da177e4SLinus Torvalds * the hint.
1871da177e4SLinus Torvalds *
1881da177e4SLinus Torvalds * RETURN VALUES:
1891da177e4SLinus Torvalds * 0 - success
1901da177e4SLinus Torvalds * -EIO - i/o error.
1911da177e4SLinus Torvalds */
extHint(struct inode * ip,s64 offset,xad_t * xp)1921da177e4SLinus Torvalds int extHint(struct inode *ip, s64 offset, xad_t * xp)
1931da177e4SLinus Torvalds {
1941da177e4SLinus Torvalds struct super_block *sb = ip->i_sb;
195fec1878fSDave Kleikamp int nbperpage = JFS_SBI(sb)->nbperpage;
1961da177e4SLinus Torvalds s64 prev;
197fec1878fSDave Kleikamp int rc = 0;
198fec1878fSDave Kleikamp s64 xaddr;
199fec1878fSDave Kleikamp int xlen;
200fec1878fSDave Kleikamp int xflag;
2011da177e4SLinus Torvalds
2021da177e4SLinus Torvalds /* init the hint as "no hint provided" */
2031da177e4SLinus Torvalds XADaddress(xp, 0);
2041da177e4SLinus Torvalds
2051da177e4SLinus Torvalds /* determine the starting extent offset of the page previous
2061da177e4SLinus Torvalds * to the page containing the offset.
2071da177e4SLinus Torvalds */
2081da177e4SLinus Torvalds prev = ((offset & ~POFFSET) >> JFS_SBI(sb)->l2bsize) - nbperpage;
2091da177e4SLinus Torvalds
210fec1878fSDave Kleikamp /* if the offset is in the first page of the file, no hint provided.
2111da177e4SLinus Torvalds */
2121da177e4SLinus Torvalds if (prev < 0)
213fec1878fSDave Kleikamp goto out;
2141da177e4SLinus Torvalds
215fec1878fSDave Kleikamp rc = xtLookup(ip, prev, nbperpage, &xflag, &xaddr, &xlen, 0);
2161da177e4SLinus Torvalds
217fec1878fSDave Kleikamp if ((rc == 0) && xlen) {
218fec1878fSDave Kleikamp if (xlen != nbperpage) {
219eb8630d7SJoe Perches jfs_error(ip->i_sb, "corrupt xtree\n");
220fec1878fSDave Kleikamp rc = -EIO;
2211da177e4SLinus Torvalds }
222fec1878fSDave Kleikamp XADaddress(xp, xaddr);
223fec1878fSDave Kleikamp XADlength(xp, xlen);
224f7c52fd1SDave Kleikamp XADoffset(xp, prev);
225fec1878fSDave Kleikamp /*
226fec1878fSDave Kleikamp * only preserve the abnr flag within the xad flags
2271da177e4SLinus Torvalds * of the returned hint.
2281da177e4SLinus Torvalds */
229fec1878fSDave Kleikamp xp->flag = xflag & XAD_NOTRECORDED;
230fec1878fSDave Kleikamp } else
231fec1878fSDave Kleikamp rc = 0;
2321da177e4SLinus Torvalds
233fec1878fSDave Kleikamp out:
234fec1878fSDave Kleikamp return (rc);
2351da177e4SLinus Torvalds }
2361da177e4SLinus Torvalds
2371da177e4SLinus Torvalds
2381da177e4SLinus Torvalds /*
2391da177e4SLinus Torvalds * NAME: extRecord()
2401da177e4SLinus Torvalds *
2411da177e4SLinus Torvalds * FUNCTION: change a page with a file from not recorded to recorded.
2421da177e4SLinus Torvalds *
2431da177e4SLinus Torvalds * PARAMETERS:
2441da177e4SLinus Torvalds * ip - inode of the file.
2451da177e4SLinus Torvalds * cp - cbuf of the file page.
2461da177e4SLinus Torvalds *
2471da177e4SLinus Torvalds * RETURN VALUES:
2481da177e4SLinus Torvalds * 0 - success
2491da177e4SLinus Torvalds * -EIO - i/o error.
2501da177e4SLinus Torvalds * -ENOSPC - insufficient disk resources.
2511da177e4SLinus Torvalds */
extRecord(struct inode * ip,xad_t * xp)2521da177e4SLinus Torvalds int extRecord(struct inode *ip, xad_t * xp)
2531da177e4SLinus Torvalds {
2541da177e4SLinus Torvalds int rc;
2551da177e4SLinus Torvalds
2561da177e4SLinus Torvalds txBeginAnon(ip->i_sb);
2571da177e4SLinus Torvalds
2581de87444SIngo Molnar mutex_lock(&JFS_IP(ip)->commit_mutex);
2591da177e4SLinus Torvalds
2601da177e4SLinus Torvalds /* update the extent */
2611da177e4SLinus Torvalds rc = xtUpdate(0, ip, xp);
2621da177e4SLinus Torvalds
2631de87444SIngo Molnar mutex_unlock(&JFS_IP(ip)->commit_mutex);
2641da177e4SLinus Torvalds return rc;
2651da177e4SLinus Torvalds }
2661da177e4SLinus Torvalds
2671da177e4SLinus Torvalds /*
2681da177e4SLinus Torvalds * NAME: extBalloc()
2691da177e4SLinus Torvalds *
2701da177e4SLinus Torvalds * FUNCTION: allocate disk blocks to form an extent.
2711da177e4SLinus Torvalds *
2721da177e4SLinus Torvalds * initially, we will try to allocate disk blocks for the
2731da177e4SLinus Torvalds * requested size (nblocks). if this fails (nblocks
27425985edcSLucas De Marchi * contiguous free blocks not available), we'll try to allocate
2751da177e4SLinus Torvalds * a smaller number of blocks (producing a smaller extent), with
2761da177e4SLinus Torvalds * this smaller number of blocks consisting of the requested
2771da177e4SLinus Torvalds * number of blocks rounded down to the next smaller power of 2
2781da177e4SLinus Torvalds * number (i.e. 16 -> 8). we'll continue to round down and
2791da177e4SLinus Torvalds * retry the allocation until the number of blocks to allocate
2801da177e4SLinus Torvalds * is smaller than the number of blocks per page.
2811da177e4SLinus Torvalds *
2821da177e4SLinus Torvalds * PARAMETERS:
2831da177e4SLinus Torvalds * ip - the inode of the file.
2841da177e4SLinus Torvalds * hint - disk block number to be used as an allocation hint.
2851da177e4SLinus Torvalds * *nblocks - pointer to an s64 value. on entry, this value specifies
2861da177e4SLinus Torvalds * the desired number of block to be allocated. on successful
2871da177e4SLinus Torvalds * exit, this value is set to the number of blocks actually
2881da177e4SLinus Torvalds * allocated.
2891da177e4SLinus Torvalds * blkno - pointer to a block address that is filled in on successful
2901da177e4SLinus Torvalds * return with the starting block number of the newly
2911da177e4SLinus Torvalds * allocated block range.
2921da177e4SLinus Torvalds *
2931da177e4SLinus Torvalds * RETURN VALUES:
2941da177e4SLinus Torvalds * 0 - success
2951da177e4SLinus Torvalds * -EIO - i/o error.
2961da177e4SLinus Torvalds * -ENOSPC - insufficient disk resources.
2971da177e4SLinus Torvalds */
2981da177e4SLinus Torvalds static int
extBalloc(struct inode * ip,s64 hint,s64 * nblocks,s64 * blkno)2991da177e4SLinus Torvalds extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno)
3001da177e4SLinus Torvalds {
3011da177e4SLinus Torvalds struct jfs_inode_info *ji = JFS_IP(ip);
3021da177e4SLinus Torvalds struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
3031da177e4SLinus Torvalds s64 nb, nblks, daddr, max;
3041da177e4SLinus Torvalds int rc, nbperpage = sbi->nbperpage;
3051da177e4SLinus Torvalds struct bmap *bmp = sbi->bmap;
3061da177e4SLinus Torvalds int ag;
3071da177e4SLinus Torvalds
3081da177e4SLinus Torvalds /* get the number of blocks to initially attempt to allocate.
3091da177e4SLinus Torvalds * we'll first try the number of blocks requested unless this
310d6e05edcSAndreas Mohr * number is greater than the maximum number of contiguous free
3111da177e4SLinus Torvalds * blocks in the map. in that case, we'll start off with the
3121da177e4SLinus Torvalds * maximum free.
3131da177e4SLinus Torvalds */
314*0225e109SAlexei Filippov
315*0225e109SAlexei Filippov /* give up if no space left */
316*0225e109SAlexei Filippov if (bmp->db_maxfreebud == -1)
317*0225e109SAlexei Filippov return -ENOSPC;
318*0225e109SAlexei Filippov
3191da177e4SLinus Torvalds max = (s64) 1 << bmp->db_maxfreebud;
3201da177e4SLinus Torvalds if (*nblocks >= max && *nblocks > nbperpage)
3211da177e4SLinus Torvalds nb = nblks = (max > nbperpage) ? max : nbperpage;
3221da177e4SLinus Torvalds else
3231da177e4SLinus Torvalds nb = nblks = *nblocks;
3241da177e4SLinus Torvalds
3251da177e4SLinus Torvalds /* try to allocate blocks */
3261da177e4SLinus Torvalds while ((rc = dbAlloc(ip, hint, nb, &daddr)) != 0) {
3271da177e4SLinus Torvalds /* if something other than an out of space error,
3281da177e4SLinus Torvalds * stop and return this error.
3291da177e4SLinus Torvalds */
3301da177e4SLinus Torvalds if (rc != -ENOSPC)
3311da177e4SLinus Torvalds return (rc);
3321da177e4SLinus Torvalds
3331da177e4SLinus Torvalds /* decrease the allocation request size */
3341da177e4SLinus Torvalds nb = min(nblks, extRoundDown(nb));
3351da177e4SLinus Torvalds
3361da177e4SLinus Torvalds /* give up if we cannot cover a page */
3371da177e4SLinus Torvalds if (nb < nbperpage)
3381da177e4SLinus Torvalds return (rc);
3391da177e4SLinus Torvalds }
3401da177e4SLinus Torvalds
3411da177e4SLinus Torvalds *nblocks = nb;
3421da177e4SLinus Torvalds *blkno = daddr;
3431da177e4SLinus Torvalds
3441da177e4SLinus Torvalds if (S_ISREG(ip->i_mode) && (ji->fileset == FILESYSTEM_I)) {
3451da177e4SLinus Torvalds ag = BLKTOAG(daddr, sbi);
3461da177e4SLinus Torvalds spin_lock_irq(&ji->ag_lock);
3471da177e4SLinus Torvalds if (ji->active_ag == -1) {
3481da177e4SLinus Torvalds atomic_inc(&bmp->db_active[ag]);
3491da177e4SLinus Torvalds ji->active_ag = ag;
3501da177e4SLinus Torvalds } else if (ji->active_ag != ag) {
3511da177e4SLinus Torvalds atomic_dec(&bmp->db_active[ji->active_ag]);
3521da177e4SLinus Torvalds atomic_inc(&bmp->db_active[ag]);
3531da177e4SLinus Torvalds ji->active_ag = ag;
3541da177e4SLinus Torvalds }
3551da177e4SLinus Torvalds spin_unlock_irq(&ji->ag_lock);
3561da177e4SLinus Torvalds }
3571da177e4SLinus Torvalds
3581da177e4SLinus Torvalds return (0);
3591da177e4SLinus Torvalds }
3601da177e4SLinus Torvalds
3611da177e4SLinus Torvalds /*
3621da177e4SLinus Torvalds * NAME: extRoundDown()
3631da177e4SLinus Torvalds *
3641da177e4SLinus Torvalds * FUNCTION: round down a specified number of blocks to the next
3651da177e4SLinus Torvalds * smallest power of 2 number.
3661da177e4SLinus Torvalds *
3671da177e4SLinus Torvalds * PARAMETERS:
3681da177e4SLinus Torvalds * nb - the inode of the file.
3691da177e4SLinus Torvalds *
3701da177e4SLinus Torvalds * RETURN VALUES:
3711da177e4SLinus Torvalds * next smallest power of 2 number.
3721da177e4SLinus Torvalds */
extRoundDown(s64 nb)3731da177e4SLinus Torvalds static s64 extRoundDown(s64 nb)
3741da177e4SLinus Torvalds {
3751da177e4SLinus Torvalds int i;
3761da177e4SLinus Torvalds u64 m, k;
3771da177e4SLinus Torvalds
3781da177e4SLinus Torvalds for (i = 0, m = (u64) 1 << 63; i < 64; i++, m >>= 1) {
3791da177e4SLinus Torvalds if (m & nb)
3801da177e4SLinus Torvalds break;
3811da177e4SLinus Torvalds }
3821da177e4SLinus Torvalds
3831da177e4SLinus Torvalds i = 63 - i;
3841da177e4SLinus Torvalds k = (u64) 1 << i;
3851da177e4SLinus Torvalds k = ((k - 1) & nb) ? k : k >> 1;
3861da177e4SLinus Torvalds
3871da177e4SLinus Torvalds return (k);
3881da177e4SLinus Torvalds }
389