xref: /kernel/linux/linux-5.10/fs/jfs/jfs_extent.c (revision 8c2ecf20)
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 *);
19#ifdef _NOTYET
20static int extBrealloc(struct inode *, s64, s64, s64 *, s64 *);
21#endif
22static s64 extRoundDown(s64 nb);
23
24#define DPD(a)		(printk("(a): %d\n",(a)))
25#define DPC(a)		(printk("(a): %c\n",(a)))
26#define DPL1(a)					\
27{						\
28	if ((a) >> 32)				\
29		printk("(a): %x%08x  ",(a));	\
30	else					\
31		printk("(a): %x  ",(a) << 32);	\
32}
33#define DPL(a)					\
34{						\
35	if ((a) >> 32)				\
36		printk("(a): %x%08x\n",(a));	\
37	else					\
38		printk("(a): %x\n",(a) << 32);	\
39}
40
41#define DPD1(a)		(printk("(a): %d  ",(a)))
42#define DPX(a)		(printk("(a): %08x\n",(a)))
43#define DPX1(a)		(printk("(a): %08x  ",(a)))
44#define DPS(a)		(printk("%s\n",(a)))
45#define DPE(a)		(printk("\nENTERING: %s\n",(a)))
46#define DPE1(a)		(printk("\nENTERING: %s",(a)))
47#define DPS1(a)		(printk("  %s  ",(a)))
48
49
50/*
51 * NAME:	extAlloc()
52 *
53 * FUNCTION:	allocate an extent for a specified page range within a
54 *		file.
55 *
56 * PARAMETERS:
57 *	ip	- the inode of the file.
58 *	xlen	- requested extent length.
59 *	pno	- the starting page number with the file.
60 *	xp	- pointer to an xad.  on entry, xad describes an
61 *		  extent that is used as an allocation hint if the
62 *		  xaddr of the xad is non-zero.  on successful exit,
63 *		  the xad describes the newly allocated extent.
64 *	abnr	- bool indicating whether the newly allocated extent
65 *		  should be marked as allocated but not recorded.
66 *
67 * RETURN VALUES:
68 *	0	- success
69 *	-EIO	- i/o error.
70 *	-ENOSPC	- insufficient disk resources.
71 */
72int
73extAlloc(struct inode *ip, s64 xlen, s64 pno, xad_t * xp, bool abnr)
74{
75	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
76	s64 nxlen, nxaddr, xoff, hint, xaddr = 0;
77	int rc;
78	int xflag;
79
80	/* This blocks if we are low on resources */
81	txBeginAnon(ip->i_sb);
82
83	/* Avoid race with jfs_commit_inode() */
84	mutex_lock(&JFS_IP(ip)->commit_mutex);
85
86	/* validate extent length */
87	if (xlen > MAXXLEN)
88		xlen = MAXXLEN;
89
90	/* get the page's starting extent offset */
91	xoff = pno << sbi->l2nbperpage;
92
93	/* check if an allocation hint was provided */
94	if ((hint = addressXAD(xp))) {
95		/* get the size of the extent described by the hint */
96		nxlen = lengthXAD(xp);
97
98		/* check if the hint is for the portion of the file
99		 * immediately previous to the current allocation
100		 * request and if hint extent has the same abnr
101		 * value as the current request.  if so, we can
102		 * extend the hint extent to include the current
103		 * extent if we can allocate the blocks immediately
104		 * following the hint extent.
105		 */
106		if (offsetXAD(xp) + nxlen == xoff &&
107		    abnr == ((xp->flag & XAD_NOTRECORDED) ? true : false))
108			xaddr = hint + nxlen;
109
110		/* adjust the hint to the last block of the extent */
111		hint += (nxlen - 1);
112	}
113
114	/* allocate the disk blocks for the extent.  initially, extBalloc()
115	 * will try to allocate disk blocks for the requested size (xlen).
116	 * if this fails (xlen contiguous free blocks not available), it'll
117	 * try to allocate a smaller number of blocks (producing a smaller
118	 * extent), with this smaller number of blocks consisting of the
119	 * requested number of blocks rounded down to the next smaller
120	 * power of 2 number (i.e. 16 -> 8).  it'll continue to round down
121	 * and retry the allocation until the number of blocks to allocate
122	 * is smaller than the number of blocks per page.
123	 */
124	nxlen = xlen;
125	if ((rc = extBalloc(ip, hint ? hint : INOHINT(ip), &nxlen, &nxaddr))) {
126		mutex_unlock(&JFS_IP(ip)->commit_mutex);
127		return (rc);
128	}
129
130	/* Allocate blocks to quota. */
131	rc = dquot_alloc_block(ip, nxlen);
132	if (rc) {
133		dbFree(ip, nxaddr, (s64) nxlen);
134		mutex_unlock(&JFS_IP(ip)->commit_mutex);
135		return rc;
136	}
137
138	/* determine the value of the extent flag */
139	xflag = abnr ? XAD_NOTRECORDED : 0;
140
141	/* if we can extend the hint extent to cover the current request,
142	 * extend it.  otherwise, insert a new extent to
143	 * cover the current request.
144	 */
145	if (xaddr && xaddr == nxaddr)
146		rc = xtExtend(0, ip, xoff, (int) nxlen, 0);
147	else
148		rc = xtInsert(0, ip, xflag, xoff, (int) nxlen, &nxaddr, 0);
149
150	/* if the extend or insert failed,
151	 * free the newly allocated blocks and return the error.
152	 */
153	if (rc) {
154		dbFree(ip, nxaddr, nxlen);
155		dquot_free_block(ip, nxlen);
156		mutex_unlock(&JFS_IP(ip)->commit_mutex);
157		return (rc);
158	}
159
160	/* set the results of the extent allocation */
161	XADaddress(xp, nxaddr);
162	XADlength(xp, nxlen);
163	XADoffset(xp, xoff);
164	xp->flag = xflag;
165
166	mark_inode_dirty(ip);
167
168	mutex_unlock(&JFS_IP(ip)->commit_mutex);
169	/*
170	 * COMMIT_SyncList flags an anonymous tlock on page that is on
171	 * sync list.
172	 * We need to commit the inode to get the page written disk.
173	 */
174	if (test_and_clear_cflag(COMMIT_Synclist,ip))
175		jfs_commit_inode(ip, 0);
176
177	return (0);
178}
179
180
181#ifdef _NOTYET
182/*
183 * NAME:	extRealloc()
184 *
185 * FUNCTION:	extend the allocation of a file extent containing a
186 *		partial back last page.
187 *
188 * PARAMETERS:
189 *	ip	- the inode of the file.
190 *	cp	- cbuf for the partial backed last page.
191 *	xlen	- request size of the resulting extent.
192 *	xp	- pointer to an xad. on successful exit, the xad
193 *		  describes the newly allocated extent.
194 *	abnr	- bool indicating whether the newly allocated extent
195 *		  should be marked as allocated but not recorded.
196 *
197 * RETURN VALUES:
198 *	0	- success
199 *	-EIO	- i/o error.
200 *	-ENOSPC	- insufficient disk resources.
201 */
202int extRealloc(struct inode *ip, s64 nxlen, xad_t * xp, bool abnr)
203{
204	struct super_block *sb = ip->i_sb;
205	s64 xaddr, xlen, nxaddr, delta, xoff;
206	s64 ntail, nextend, ninsert;
207	int rc, nbperpage = JFS_SBI(sb)->nbperpage;
208	int xflag;
209
210	/* This blocks if we are low on resources */
211	txBeginAnon(ip->i_sb);
212
213	mutex_lock(&JFS_IP(ip)->commit_mutex);
214	/* validate extent length */
215	if (nxlen > MAXXLEN)
216		nxlen = MAXXLEN;
217
218	/* get the extend (partial) page's disk block address and
219	 * number of blocks.
220	 */
221	xaddr = addressXAD(xp);
222	xlen = lengthXAD(xp);
223	xoff = offsetXAD(xp);
224
225	/* if the extend page is abnr and if the request is for
226	 * the extent to be allocated and recorded,
227	 * make the page allocated and recorded.
228	 */
229	if ((xp->flag & XAD_NOTRECORDED) && !abnr) {
230		xp->flag = 0;
231		if ((rc = xtUpdate(0, ip, xp)))
232			goto exit;
233	}
234
235	/* try to allocated the request number of blocks for the
236	 * extent.  dbRealloc() first tries to satisfy the request
237	 * by extending the allocation in place. otherwise, it will
238	 * try to allocate a new set of blocks large enough for the
239	 * request.  in satisfying a request, dbReAlloc() may allocate
240	 * less than what was request but will always allocate enough
241	 * space as to satisfy the extend page.
242	 */
243	if ((rc = extBrealloc(ip, xaddr, xlen, &nxlen, &nxaddr)))
244		goto exit;
245
246	/* Allocat blocks to quota. */
247	rc = dquot_alloc_block(ip, nxlen);
248	if (rc) {
249		dbFree(ip, nxaddr, (s64) nxlen);
250		mutex_unlock(&JFS_IP(ip)->commit_mutex);
251		return rc;
252	}
253
254	delta = nxlen - xlen;
255
256	/* check if the extend page is not abnr but the request is abnr
257	 * and the allocated disk space is for more than one page.  if this
258	 * is the case, there is a miss match of abnr between the extend page
259	 * and the one or more pages following the extend page.  as a result,
260	 * two extents will have to be manipulated. the first will be that
261	 * of the extent of the extend page and will be manipulated thru
262	 * an xtExtend() or an xtTailgate(), depending upon whether the
263	 * disk allocation occurred as an inplace extension.  the second
264	 * extent will be manipulated (created) through an xtInsert() and
265	 * will be for the pages following the extend page.
266	 */
267	if (abnr && (!(xp->flag & XAD_NOTRECORDED)) && (nxlen > nbperpage)) {
268		ntail = nbperpage;
269		nextend = ntail - xlen;
270		ninsert = nxlen - nbperpage;
271
272		xflag = XAD_NOTRECORDED;
273	} else {
274		ntail = nxlen;
275		nextend = delta;
276		ninsert = 0;
277
278		xflag = xp->flag;
279	}
280
281	/* if we were able to extend the disk allocation in place,
282	 * extend the extent.  otherwise, move the extent to a
283	 * new disk location.
284	 */
285	if (xaddr == nxaddr) {
286		/* extend the extent */
287		if ((rc = xtExtend(0, ip, xoff + xlen, (int) nextend, 0))) {
288			dbFree(ip, xaddr + xlen, delta);
289			dquot_free_block(ip, nxlen);
290			goto exit;
291		}
292	} else {
293		/*
294		 * move the extent to a new location:
295		 *
296		 * xtTailgate() accounts for relocated tail extent;
297		 */
298		if ((rc = xtTailgate(0, ip, xoff, (int) ntail, nxaddr, 0))) {
299			dbFree(ip, nxaddr, nxlen);
300			dquot_free_block(ip, nxlen);
301			goto exit;
302		}
303	}
304
305
306	/* check if we need to also insert a new extent */
307	if (ninsert) {
308		/* perform the insert.  if it fails, free the blocks
309		 * to be inserted and make it appear that we only did
310		 * the xtExtend() or xtTailgate() above.
311		 */
312		xaddr = nxaddr + ntail;
313		if (xtInsert (0, ip, xflag, xoff + ntail, (int) ninsert,
314			      &xaddr, 0)) {
315			dbFree(ip, xaddr, (s64) ninsert);
316			delta = nextend;
317			nxlen = ntail;
318			xflag = 0;
319		}
320	}
321
322	/* set the return results */
323	XADaddress(xp, nxaddr);
324	XADlength(xp, nxlen);
325	XADoffset(xp, xoff);
326	xp->flag = xflag;
327
328	mark_inode_dirty(ip);
329exit:
330	mutex_unlock(&JFS_IP(ip)->commit_mutex);
331	return (rc);
332}
333#endif			/* _NOTYET */
334
335
336/*
337 * NAME:	extHint()
338 *
339 * FUNCTION:	produce an extent allocation hint for a file offset.
340 *
341 * PARAMETERS:
342 *	ip	- the inode of the file.
343 *	offset  - file offset for which the hint is needed.
344 *	xp	- pointer to the xad that is to be filled in with
345 *		  the hint.
346 *
347 * RETURN VALUES:
348 *	0	- success
349 *	-EIO	- i/o error.
350 */
351int extHint(struct inode *ip, s64 offset, xad_t * xp)
352{
353	struct super_block *sb = ip->i_sb;
354	int nbperpage = JFS_SBI(sb)->nbperpage;
355	s64 prev;
356	int rc = 0;
357	s64 xaddr;
358	int xlen;
359	int xflag;
360
361	/* init the hint as "no hint provided" */
362	XADaddress(xp, 0);
363
364	/* determine the starting extent offset of the page previous
365	 * to the page containing the offset.
366	 */
367	prev = ((offset & ~POFFSET) >> JFS_SBI(sb)->l2bsize) - nbperpage;
368
369	/* if the offset is in the first page of the file, no hint provided.
370	 */
371	if (prev < 0)
372		goto out;
373
374	rc = xtLookup(ip, prev, nbperpage, &xflag, &xaddr, &xlen, 0);
375
376	if ((rc == 0) && xlen) {
377		if (xlen != nbperpage) {
378			jfs_error(ip->i_sb, "corrupt xtree\n");
379			rc = -EIO;
380		}
381		XADaddress(xp, xaddr);
382		XADlength(xp, xlen);
383		XADoffset(xp, prev);
384		/*
385		 * only preserve the abnr flag within the xad flags
386		 * of the returned hint.
387		 */
388		xp->flag  = xflag & XAD_NOTRECORDED;
389	} else
390		rc = 0;
391
392out:
393	return (rc);
394}
395
396
397/*
398 * NAME:	extRecord()
399 *
400 * FUNCTION:	change a page with a file from not recorded to recorded.
401 *
402 * PARAMETERS:
403 *	ip	- inode of the file.
404 *	cp	- cbuf of the file page.
405 *
406 * RETURN VALUES:
407 *	0	- success
408 *	-EIO	- i/o error.
409 *	-ENOSPC	- insufficient disk resources.
410 */
411int extRecord(struct inode *ip, xad_t * xp)
412{
413	int rc;
414
415	txBeginAnon(ip->i_sb);
416
417	mutex_lock(&JFS_IP(ip)->commit_mutex);
418
419	/* update the extent */
420	rc = xtUpdate(0, ip, xp);
421
422	mutex_unlock(&JFS_IP(ip)->commit_mutex);
423	return rc;
424}
425
426
427#ifdef _NOTYET
428/*
429 * NAME:	extFill()
430 *
431 * FUNCTION:	allocate disk space for a file page that represents
432 *		a file hole.
433 *
434 * PARAMETERS:
435 *	ip	- the inode of the file.
436 *	cp	- cbuf of the file page represent the hole.
437 *
438 * RETURN VALUES:
439 *	0	- success
440 *	-EIO	- i/o error.
441 *	-ENOSPC	- insufficient disk resources.
442 */
443int extFill(struct inode *ip, xad_t * xp)
444{
445	int rc, nbperpage = JFS_SBI(ip->i_sb)->nbperpage;
446	s64 blkno = offsetXAD(xp) >> ip->i_blkbits;
447
448//	assert(ISSPARSE(ip));
449
450	/* initialize the extent allocation hint */
451	XADaddress(xp, 0);
452
453	/* allocate an extent to fill the hole */
454	if ((rc = extAlloc(ip, nbperpage, blkno, xp, false)))
455		return (rc);
456
457	assert(lengthPXD(xp) == nbperpage);
458
459	return (0);
460}
461#endif			/* _NOTYET */
462
463
464/*
465 * NAME:	extBalloc()
466 *
467 * FUNCTION:	allocate disk blocks to form an extent.
468 *
469 *		initially, we will try to allocate disk blocks for the
470 *		requested size (nblocks).  if this fails (nblocks
471 *		contiguous free blocks not available), we'll try to allocate
472 *		a smaller number of blocks (producing a smaller extent), with
473 *		this smaller number of blocks consisting of the requested
474 *		number of blocks rounded down to the next smaller power of 2
475 *		number (i.e. 16 -> 8).  we'll continue to round down and
476 *		retry the allocation until the number of blocks to allocate
477 *		is smaller than the number of blocks per page.
478 *
479 * PARAMETERS:
480 *	ip	 - the inode of the file.
481 *	hint	 - disk block number to be used as an allocation hint.
482 *	*nblocks - pointer to an s64 value.  on entry, this value specifies
483 *		   the desired number of block to be allocated. on successful
484 *		   exit, this value is set to the number of blocks actually
485 *		   allocated.
486 *	blkno	 - pointer to a block address that is filled in on successful
487 *		   return with the starting block number of the newly
488 *		   allocated block range.
489 *
490 * RETURN VALUES:
491 *	0	- success
492 *	-EIO	- i/o error.
493 *	-ENOSPC	- insufficient disk resources.
494 */
495static int
496extBalloc(struct inode *ip, s64 hint, s64 * nblocks, s64 * blkno)
497{
498	struct jfs_inode_info *ji = JFS_IP(ip);
499	struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb);
500	s64 nb, nblks, daddr, max;
501	int rc, nbperpage = sbi->nbperpage;
502	struct bmap *bmp = sbi->bmap;
503	int ag;
504
505	/* get the number of blocks to initially attempt to allocate.
506	 * we'll first try the number of blocks requested unless this
507	 * number is greater than the maximum number of contiguous free
508	 * blocks in the map. in that case, we'll start off with the
509	 * maximum free.
510	 */
511
512	/* give up if no space left */
513	if (bmp->db_maxfreebud == -1)
514		return -ENOSPC;
515
516	max = (s64) 1 << bmp->db_maxfreebud;
517	if (*nblocks >= max && *nblocks > nbperpage)
518		nb = nblks = (max > nbperpage) ? max : nbperpage;
519	else
520		nb = nblks = *nblocks;
521
522	/* try to allocate blocks */
523	while ((rc = dbAlloc(ip, hint, nb, &daddr)) != 0) {
524		/* if something other than an out of space error,
525		 * stop and return this error.
526		 */
527		if (rc != -ENOSPC)
528			return (rc);
529
530		/* decrease the allocation request size */
531		nb = min(nblks, extRoundDown(nb));
532
533		/* give up if we cannot cover a page */
534		if (nb < nbperpage)
535			return (rc);
536	}
537
538	*nblocks = nb;
539	*blkno = daddr;
540
541	if (S_ISREG(ip->i_mode) && (ji->fileset == FILESYSTEM_I)) {
542		ag = BLKTOAG(daddr, sbi);
543		spin_lock_irq(&ji->ag_lock);
544		if (ji->active_ag == -1) {
545			atomic_inc(&bmp->db_active[ag]);
546			ji->active_ag = ag;
547		} else if (ji->active_ag != ag) {
548			atomic_dec(&bmp->db_active[ji->active_ag]);
549			atomic_inc(&bmp->db_active[ag]);
550			ji->active_ag = ag;
551		}
552		spin_unlock_irq(&ji->ag_lock);
553	}
554
555	return (0);
556}
557
558
559#ifdef _NOTYET
560/*
561 * NAME:	extBrealloc()
562 *
563 * FUNCTION:	attempt to extend an extent's allocation.
564 *
565 *		Initially, we will try to extend the extent's allocation
566 *		in place.  If this fails, we'll try to move the extent
567 *		to a new set of blocks.  If moving the extent, we initially
568 *		will try to allocate disk blocks for the requested size
569 *		(newnblks).  if this fails (new contiguous free blocks not
570 *		available), we'll try to allocate a smaller number of
571 *		blocks (producing a smaller extent), with this smaller
572 *		number of blocks consisting of the requested number of
573 *		blocks rounded down to the next smaller power of 2
574 *		number (i.e. 16 -> 8).  We'll continue to round down and
575 *		retry the allocation until the number of blocks to allocate
576 *		is smaller than the number of blocks per page.
577 *
578 * PARAMETERS:
579 *	ip	 - the inode of the file.
580 *	blkno	 - starting block number of the extents current allocation.
581 *	nblks	 - number of blocks within the extents current allocation.
582 *	newnblks - pointer to a s64 value.  on entry, this value is the
583 *		   the new desired extent size (number of blocks).  on
584 *		   successful exit, this value is set to the extent's actual
585 *		   new size (new number of blocks).
586 *	newblkno - the starting block number of the extents new allocation.
587 *
588 * RETURN VALUES:
589 *	0	- success
590 *	-EIO	- i/o error.
591 *	-ENOSPC	- insufficient disk resources.
592 */
593static int
594extBrealloc(struct inode *ip,
595	    s64 blkno, s64 nblks, s64 * newnblks, s64 * newblkno)
596{
597	int rc;
598
599	/* try to extend in place */
600	if ((rc = dbExtend(ip, blkno, nblks, *newnblks - nblks)) == 0) {
601		*newblkno = blkno;
602		return (0);
603	} else {
604		if (rc != -ENOSPC)
605			return (rc);
606	}
607
608	/* in place extension not possible.
609	 * try to move the extent to a new set of blocks.
610	 */
611	return (extBalloc(ip, blkno, newnblks, newblkno));
612}
613#endif			/* _NOTYET */
614
615
616/*
617 * NAME:	extRoundDown()
618 *
619 * FUNCTION:	round down a specified number of blocks to the next
620 *		smallest power of 2 number.
621 *
622 * PARAMETERS:
623 *	nb	- the inode of the file.
624 *
625 * RETURN VALUES:
626 *	next smallest power of 2 number.
627 */
628static s64 extRoundDown(s64 nb)
629{
630	int i;
631	u64 m, k;
632
633	for (i = 0, m = (u64) 1 << 63; i < 64; i++, m >>= 1) {
634		if (m & nb)
635			break;
636	}
637
638	i = 63 - i;
639	k = (u64) 1 << i;
640	k = ((k - 1) & nb) ? k : k >> 1;
641
642	return (k);
643}
644