cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

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}