11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
36b6bf510SDave Kleikamp * Copyright (C) International Business Machines Corp., 2000-2005
41da177e4SLinus Torvalds */
51da177e4SLinus Torvalds /*
61da177e4SLinus Torvalds * jfs_xtree.c: extent allocation descriptor B+-tree manager
71da177e4SLinus Torvalds */
81da177e4SLinus Torvalds
91da177e4SLinus Torvalds #include <linux/fs.h>
10b2e03ca7SAlexey Dobriyan #include <linux/module.h>
111da177e4SLinus Torvalds #include <linux/quotaops.h>
12b2e03ca7SAlexey Dobriyan #include <linux/seq_file.h>
131da177e4SLinus Torvalds #include "jfs_incore.h"
141da177e4SLinus Torvalds #include "jfs_filsys.h"
151da177e4SLinus Torvalds #include "jfs_metapage.h"
161da177e4SLinus Torvalds #include "jfs_dmap.h"
171da177e4SLinus Torvalds #include "jfs_dinode.h"
181da177e4SLinus Torvalds #include "jfs_superblock.h"
191da177e4SLinus Torvalds #include "jfs_debug.h"
201da177e4SLinus Torvalds
211da177e4SLinus Torvalds /*
221da177e4SLinus Torvalds * xtree local flag
231da177e4SLinus Torvalds */
241da177e4SLinus Torvalds #define XT_INSERT 0x00000001
251da177e4SLinus Torvalds
261da177e4SLinus Torvalds /*
271da177e4SLinus Torvalds * xtree key/entry comparison: extent offset
281da177e4SLinus Torvalds *
291da177e4SLinus Torvalds * return:
301da177e4SLinus Torvalds * -1: k < start of extent
311da177e4SLinus Torvalds * 0: start_of_extent <= k <= end_of_extent
321da177e4SLinus Torvalds * 1: k > end_of_extent
331da177e4SLinus Torvalds */
341da177e4SLinus Torvalds #define XT_CMP(CMP, K, X, OFFSET64)\
351da177e4SLinus Torvalds {\
361da177e4SLinus Torvalds OFFSET64 = offsetXAD(X);\
371da177e4SLinus Torvalds (CMP) = ((K) >= OFFSET64 + lengthXAD(X)) ? 1 :\
381da177e4SLinus Torvalds ((K) < OFFSET64) ? -1 : 0;\
391da177e4SLinus Torvalds }
401da177e4SLinus Torvalds
411da177e4SLinus Torvalds /* write a xad entry */
421da177e4SLinus Torvalds #define XT_PUTENTRY(XAD, FLAG, OFF, LEN, ADDR)\
431da177e4SLinus Torvalds {\
441da177e4SLinus Torvalds (XAD)->flag = (FLAG);\
451da177e4SLinus Torvalds XADoffset((XAD), (OFF));\
461da177e4SLinus Torvalds XADlength((XAD), (LEN));\
471da177e4SLinus Torvalds XADaddress((XAD), (ADDR));\
481da177e4SLinus Torvalds }
491da177e4SLinus Torvalds
501da177e4SLinus Torvalds #define XT_PAGE(IP, MP) BT_PAGE(IP, MP, xtpage_t, i_xtroot)
511da177e4SLinus Torvalds
521da177e4SLinus Torvalds /* get page buffer for specified block address */
531da177e4SLinus Torvalds /* ToDo: Replace this ugly macro with a function */
541da177e4SLinus Torvalds #define XT_GETPAGE(IP, BN, MP, SIZE, P, RC) \
55eb8630d7SJoe Perches do { \
56eb8630d7SJoe Perches BT_GETPAGE(IP, BN, MP, xtpage_t, SIZE, P, RC, i_xtroot); \
57eb8630d7SJoe Perches if (!(RC)) { \
581da177e4SLinus Torvalds if ((le16_to_cpu((P)->header.nextindex) < XTENTRYSTART) || \
59eb8630d7SJoe Perches (le16_to_cpu((P)->header.nextindex) > \
60eb8630d7SJoe Perches le16_to_cpu((P)->header.maxentry)) || \
61eb8630d7SJoe Perches (le16_to_cpu((P)->header.maxentry) > \
62eb8630d7SJoe Perches (((BN) == 0) ? XTROOTMAXSLOT : PSIZE >> L2XTSLOTSIZE))) { \
63eb8630d7SJoe Perches jfs_error((IP)->i_sb, \
64eb8630d7SJoe Perches "XT_GETPAGE: xtree page corrupt\n"); \
651da177e4SLinus Torvalds BT_PUTPAGE(MP); \
661da177e4SLinus Torvalds MP = NULL; \
671da177e4SLinus Torvalds RC = -EIO; \
681da177e4SLinus Torvalds } \
691da177e4SLinus Torvalds } \
70eb8630d7SJoe Perches } while (0)
711da177e4SLinus Torvalds
721da177e4SLinus Torvalds /* for consistency */
731da177e4SLinus Torvalds #define XT_PUTPAGE(MP) BT_PUTPAGE(MP)
741da177e4SLinus Torvalds
751da177e4SLinus Torvalds #define XT_GETSEARCH(IP, LEAF, BN, MP, P, INDEX) \
761da177e4SLinus Torvalds BT_GETSEARCH(IP, LEAF, BN, MP, xtpage_t, P, INDEX, i_xtroot)
771da177e4SLinus Torvalds /* xtree entry parameter descriptor */
781da177e4SLinus Torvalds struct xtsplit {
791da177e4SLinus Torvalds struct metapage *mp;
801da177e4SLinus Torvalds s16 index;
811da177e4SLinus Torvalds u8 flag;
821da177e4SLinus Torvalds s64 off;
831da177e4SLinus Torvalds s64 addr;
841da177e4SLinus Torvalds int len;
851da177e4SLinus Torvalds struct pxdlist *pxdlist;
861da177e4SLinus Torvalds };
871da177e4SLinus Torvalds
881da177e4SLinus Torvalds
891da177e4SLinus Torvalds /*
901da177e4SLinus Torvalds * statistics
911da177e4SLinus Torvalds */
921da177e4SLinus Torvalds #ifdef CONFIG_JFS_STATISTICS
931da177e4SLinus Torvalds static struct {
941da177e4SLinus Torvalds uint search;
951da177e4SLinus Torvalds uint fastSearch;
961da177e4SLinus Torvalds uint split;
971da177e4SLinus Torvalds } xtStat;
981da177e4SLinus Torvalds #endif
991da177e4SLinus Torvalds
1001da177e4SLinus Torvalds
1011da177e4SLinus Torvalds /*
1021da177e4SLinus Torvalds * forward references
1031da177e4SLinus Torvalds */
1046628465eSDave Kleikamp static int xtSearch(struct inode *ip, s64 xoff, s64 *next, int *cmpp,
1056628465eSDave Kleikamp struct btstack * btstack, int flag);
1061da177e4SLinus Torvalds
1071da177e4SLinus Torvalds static int xtSplitUp(tid_t tid,
1081da177e4SLinus Torvalds struct inode *ip,
1091da177e4SLinus Torvalds struct xtsplit * split, struct btstack * btstack);
1101da177e4SLinus Torvalds
1111da177e4SLinus Torvalds static int xtSplitPage(tid_t tid, struct inode *ip, struct xtsplit * split,
1121da177e4SLinus Torvalds struct metapage ** rmpp, s64 * rbnp);
1131da177e4SLinus Torvalds
1141da177e4SLinus Torvalds static int xtSplitRoot(tid_t tid, struct inode *ip,
1151da177e4SLinus Torvalds struct xtsplit * split, struct metapage ** rmpp);
1161da177e4SLinus Torvalds
1171da177e4SLinus Torvalds /*
1181da177e4SLinus Torvalds * xtLookup()
1191da177e4SLinus Torvalds *
1201da177e4SLinus Torvalds * function: map a single page into a physical extent;
1211da177e4SLinus Torvalds */
xtLookup(struct inode * ip,s64 lstart,s64 llen,int * pflag,s64 * paddr,s32 * plen,int no_check)1221da177e4SLinus Torvalds int xtLookup(struct inode *ip, s64 lstart,
1231da177e4SLinus Torvalds s64 llen, int *pflag, s64 * paddr, s32 * plen, int no_check)
1241da177e4SLinus Torvalds {
1251da177e4SLinus Torvalds int rc = 0;
1261da177e4SLinus Torvalds struct btstack btstack;
1271da177e4SLinus Torvalds int cmp;
1281da177e4SLinus Torvalds s64 bn;
1291da177e4SLinus Torvalds struct metapage *mp;
1301da177e4SLinus Torvalds xtpage_t *p;
1311da177e4SLinus Torvalds int index;
1321da177e4SLinus Torvalds xad_t *xad;
1336628465eSDave Kleikamp s64 next, size, xoff, xend;
1341da177e4SLinus Torvalds int xlen;
1351da177e4SLinus Torvalds s64 xaddr;
1361da177e4SLinus Torvalds
1376628465eSDave Kleikamp *paddr = 0;
1386628465eSDave Kleikamp *plen = llen;
1391da177e4SLinus Torvalds
1401da177e4SLinus Torvalds if (!no_check) {
1411da177e4SLinus Torvalds /* is lookup offset beyond eof ? */
1421da177e4SLinus Torvalds size = ((u64) ip->i_size + (JFS_SBI(ip->i_sb)->bsize - 1)) >>
1431da177e4SLinus Torvalds JFS_SBI(ip->i_sb)->l2bsize;
144fec1878fSDave Kleikamp if (lstart >= size)
1451da177e4SLinus Torvalds return 0;
1461da177e4SLinus Torvalds }
1471da177e4SLinus Torvalds
1481da177e4SLinus Torvalds /*
1491da177e4SLinus Torvalds * search for the xad entry covering the logical extent
1501da177e4SLinus Torvalds */
1511da177e4SLinus Torvalds //search:
1526628465eSDave Kleikamp if ((rc = xtSearch(ip, lstart, &next, &cmp, &btstack, 0))) {
1531da177e4SLinus Torvalds jfs_err("xtLookup: xtSearch returned %d", rc);
1541da177e4SLinus Torvalds return rc;
1551da177e4SLinus Torvalds }
1561da177e4SLinus Torvalds
1571da177e4SLinus Torvalds /*
1581da177e4SLinus Torvalds * compute the physical extent covering logical extent
1591da177e4SLinus Torvalds *
1601da177e4SLinus Torvalds * N.B. search may have failed (e.g., hole in sparse file),
1611da177e4SLinus Torvalds * and returned the index of the next entry.
1621da177e4SLinus Torvalds */
1631da177e4SLinus Torvalds /* retrieve search result */
1641da177e4SLinus Torvalds XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
1651da177e4SLinus Torvalds
1661da177e4SLinus Torvalds /* is xad found covering start of logical extent ?
1671da177e4SLinus Torvalds * lstart is a page start address,
1681da177e4SLinus Torvalds * i.e., lstart cannot start in a hole;
1691da177e4SLinus Torvalds */
1706628465eSDave Kleikamp if (cmp) {
1716628465eSDave Kleikamp if (next)
1726628465eSDave Kleikamp *plen = min(next - lstart, llen);
1731da177e4SLinus Torvalds goto out;
1746628465eSDave Kleikamp }
1751da177e4SLinus Torvalds
1761da177e4SLinus Torvalds /*
1771da177e4SLinus Torvalds * lxd covered by xad
1781da177e4SLinus Torvalds */
1791da177e4SLinus Torvalds xad = &p->xad[index];
1801da177e4SLinus Torvalds xoff = offsetXAD(xad);
1811da177e4SLinus Torvalds xlen = lengthXAD(xad);
1821da177e4SLinus Torvalds xend = xoff + xlen;
1831da177e4SLinus Torvalds xaddr = addressXAD(xad);
1841da177e4SLinus Torvalds
1851da177e4SLinus Torvalds /* initialize new pxd */
1861da177e4SLinus Torvalds *pflag = xad->flag;
1871da177e4SLinus Torvalds *paddr = xaddr + (lstart - xoff);
1881da177e4SLinus Torvalds /* a page must be fully covered by an xad */
1891da177e4SLinus Torvalds *plen = min(xend - lstart, llen);
1901da177e4SLinus Torvalds
1911da177e4SLinus Torvalds out:
1921da177e4SLinus Torvalds XT_PUTPAGE(mp);
1931da177e4SLinus Torvalds
1941da177e4SLinus Torvalds return rc;
1951da177e4SLinus Torvalds }
1961da177e4SLinus Torvalds
1971da177e4SLinus Torvalds /*
1981da177e4SLinus Torvalds * xtSearch()
1991da177e4SLinus Torvalds *
2001da177e4SLinus Torvalds * function: search for the xad entry covering specified offset.
2011da177e4SLinus Torvalds *
2021da177e4SLinus Torvalds * parameters:
2031da177e4SLinus Torvalds * ip - file object;
2041da177e4SLinus Torvalds * xoff - extent offset;
2056628465eSDave Kleikamp * nextp - address of next extent (if any) for search miss
2061da177e4SLinus Torvalds * cmpp - comparison result:
2071da177e4SLinus Torvalds * btstack - traverse stack;
2081da177e4SLinus Torvalds * flag - search process flag (XT_INSERT);
2091da177e4SLinus Torvalds *
2101da177e4SLinus Torvalds * returns:
2111da177e4SLinus Torvalds * btstack contains (bn, index) of search path traversed to the entry.
2121da177e4SLinus Torvalds * *cmpp is set to result of comparison with the entry returned.
2131da177e4SLinus Torvalds * the page containing the entry is pinned at exit.
2141da177e4SLinus Torvalds */
xtSearch(struct inode * ip,s64 xoff,s64 * nextp,int * cmpp,struct btstack * btstack,int flag)2156628465eSDave Kleikamp static int xtSearch(struct inode *ip, s64 xoff, s64 *nextp,
2161da177e4SLinus Torvalds int *cmpp, struct btstack * btstack, int flag)
2171da177e4SLinus Torvalds {
2181da177e4SLinus Torvalds struct jfs_inode_info *jfs_ip = JFS_IP(ip);
2191da177e4SLinus Torvalds int rc = 0;
2201da177e4SLinus Torvalds int cmp = 1; /* init for empty page */
2211da177e4SLinus Torvalds s64 bn; /* block number */
2221da177e4SLinus Torvalds struct metapage *mp; /* page buffer */
2231da177e4SLinus Torvalds xtpage_t *p; /* page */
2241da177e4SLinus Torvalds xad_t *xad;
2251da177e4SLinus Torvalds int base, index, lim, btindex;
2261da177e4SLinus Torvalds struct btframe *btsp;
2271da177e4SLinus Torvalds int nsplit = 0; /* number of pages to split */
2281da177e4SLinus Torvalds s64 t64;
2296628465eSDave Kleikamp s64 next = 0;
2301da177e4SLinus Torvalds
2311da177e4SLinus Torvalds INCREMENT(xtStat.search);
2321da177e4SLinus Torvalds
2331da177e4SLinus Torvalds BT_CLR(btstack);
2341da177e4SLinus Torvalds
2351da177e4SLinus Torvalds btstack->nsplit = 0;
2361da177e4SLinus Torvalds
2371da177e4SLinus Torvalds /*
2381da177e4SLinus Torvalds * search down tree from root:
2391da177e4SLinus Torvalds *
2401da177e4SLinus Torvalds * between two consecutive entries of <Ki, Pi> and <Kj, Pj> of
2411da177e4SLinus Torvalds * internal page, child page Pi contains entry with k, Ki <= K < Kj.
2421da177e4SLinus Torvalds *
2431da177e4SLinus Torvalds * if entry with search key K is not found
2441da177e4SLinus Torvalds * internal page search find the entry with largest key Ki
2451da177e4SLinus Torvalds * less than K which point to the child page to search;
2461da177e4SLinus Torvalds * leaf page search find the entry with smallest key Kj
2471da177e4SLinus Torvalds * greater than K so that the returned index is the position of
2481da177e4SLinus Torvalds * the entry to be shifted right for insertion of new entry.
2491da177e4SLinus Torvalds * for empty tree, search key is greater than any key of the tree.
2501da177e4SLinus Torvalds *
2511da177e4SLinus Torvalds * by convention, root bn = 0.
2521da177e4SLinus Torvalds */
2531da177e4SLinus Torvalds for (bn = 0;;) {
2541da177e4SLinus Torvalds /* get/pin the page to search */
2551da177e4SLinus Torvalds XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
2561da177e4SLinus Torvalds if (rc)
2571da177e4SLinus Torvalds return rc;
2581da177e4SLinus Torvalds
2591da177e4SLinus Torvalds /* try sequential access heuristics with the previous
2601da177e4SLinus Torvalds * access entry in target leaf page:
2611da177e4SLinus Torvalds * once search narrowed down into the target leaf,
2621da177e4SLinus Torvalds * key must either match an entry in the leaf or
2631da177e4SLinus Torvalds * key entry does not exist in the tree;
2641da177e4SLinus Torvalds */
2651da177e4SLinus Torvalds //fastSearch:
2661da177e4SLinus Torvalds if ((jfs_ip->btorder & BT_SEQUENTIAL) &&
2671da177e4SLinus Torvalds (p->header.flag & BT_LEAF) &&
2681da177e4SLinus Torvalds (index = jfs_ip->btindex) <
2691da177e4SLinus Torvalds le16_to_cpu(p->header.nextindex)) {
2701da177e4SLinus Torvalds xad = &p->xad[index];
2711da177e4SLinus Torvalds t64 = offsetXAD(xad);
2721da177e4SLinus Torvalds if (xoff < t64 + lengthXAD(xad)) {
2731da177e4SLinus Torvalds if (xoff >= t64) {
2741da177e4SLinus Torvalds *cmpp = 0;
2751da177e4SLinus Torvalds goto out;
2761da177e4SLinus Torvalds }
2771da177e4SLinus Torvalds
2781da177e4SLinus Torvalds /* stop sequential access heuristics */
2791da177e4SLinus Torvalds goto binarySearch;
2801da177e4SLinus Torvalds } else { /* (t64 + lengthXAD(xad)) <= xoff */
2811da177e4SLinus Torvalds
2821da177e4SLinus Torvalds /* try next sequential entry */
2831da177e4SLinus Torvalds index++;
2841da177e4SLinus Torvalds if (index <
2851da177e4SLinus Torvalds le16_to_cpu(p->header.nextindex)) {
2861da177e4SLinus Torvalds xad++;
2871da177e4SLinus Torvalds t64 = offsetXAD(xad);
2881da177e4SLinus Torvalds if (xoff < t64 + lengthXAD(xad)) {
2891da177e4SLinus Torvalds if (xoff >= t64) {
2901da177e4SLinus Torvalds *cmpp = 0;
2911da177e4SLinus Torvalds goto out;
2921da177e4SLinus Torvalds }
2931da177e4SLinus Torvalds
2941da177e4SLinus Torvalds /* miss: key falls between
2951da177e4SLinus Torvalds * previous and this entry
2961da177e4SLinus Torvalds */
2971da177e4SLinus Torvalds *cmpp = 1;
2986628465eSDave Kleikamp next = t64;
2991da177e4SLinus Torvalds goto out;
3001da177e4SLinus Torvalds }
3011da177e4SLinus Torvalds
3021da177e4SLinus Torvalds /* (xoff >= t64 + lengthXAD(xad));
3031da177e4SLinus Torvalds * matching entry may be further out:
3041da177e4SLinus Torvalds * stop heuristic search
3051da177e4SLinus Torvalds */
3061da177e4SLinus Torvalds /* stop sequential access heuristics */
3071da177e4SLinus Torvalds goto binarySearch;
3081da177e4SLinus Torvalds }
3091da177e4SLinus Torvalds
3101da177e4SLinus Torvalds /* (index == p->header.nextindex);
3111da177e4SLinus Torvalds * miss: key entry does not exist in
3121da177e4SLinus Torvalds * the target leaf/tree
3131da177e4SLinus Torvalds */
3141da177e4SLinus Torvalds *cmpp = 1;
3151da177e4SLinus Torvalds goto out;
3161da177e4SLinus Torvalds }
3171da177e4SLinus Torvalds
3181da177e4SLinus Torvalds /*
3191da177e4SLinus Torvalds * if hit, return index of the entry found, and
3201da177e4SLinus Torvalds * if miss, where new entry with search key is
3211da177e4SLinus Torvalds * to be inserted;
3221da177e4SLinus Torvalds */
3231da177e4SLinus Torvalds out:
3241da177e4SLinus Torvalds /* compute number of pages to split */
3251da177e4SLinus Torvalds if (flag & XT_INSERT) {
3261da177e4SLinus Torvalds if (p->header.nextindex == /* little-endian */
3271da177e4SLinus Torvalds p->header.maxentry)
3281da177e4SLinus Torvalds nsplit++;
3291da177e4SLinus Torvalds else
3301da177e4SLinus Torvalds nsplit = 0;
3311da177e4SLinus Torvalds btstack->nsplit = nsplit;
3321da177e4SLinus Torvalds }
3331da177e4SLinus Torvalds
3341da177e4SLinus Torvalds /* save search result */
3351da177e4SLinus Torvalds btsp = btstack->top;
3361da177e4SLinus Torvalds btsp->bn = bn;
3371da177e4SLinus Torvalds btsp->index = index;
3381da177e4SLinus Torvalds btsp->mp = mp;
3391da177e4SLinus Torvalds
3401da177e4SLinus Torvalds /* update sequential access heuristics */
3411da177e4SLinus Torvalds jfs_ip->btindex = index;
3421da177e4SLinus Torvalds
3436628465eSDave Kleikamp if (nextp)
3446628465eSDave Kleikamp *nextp = next;
3456628465eSDave Kleikamp
3461da177e4SLinus Torvalds INCREMENT(xtStat.fastSearch);
3471da177e4SLinus Torvalds return 0;
3481da177e4SLinus Torvalds }
3491da177e4SLinus Torvalds
3501da177e4SLinus Torvalds /* well, ... full search now */
3511da177e4SLinus Torvalds binarySearch:
3521da177e4SLinus Torvalds lim = le16_to_cpu(p->header.nextindex) - XTENTRYSTART;
3531da177e4SLinus Torvalds
3541da177e4SLinus Torvalds /*
3551da177e4SLinus Torvalds * binary search with search key K on the current page
3561da177e4SLinus Torvalds */
3571da177e4SLinus Torvalds for (base = XTENTRYSTART; lim; lim >>= 1) {
3581da177e4SLinus Torvalds index = base + (lim >> 1);
3591da177e4SLinus Torvalds
3601da177e4SLinus Torvalds XT_CMP(cmp, xoff, &p->xad[index], t64);
3611da177e4SLinus Torvalds if (cmp == 0) {
3621da177e4SLinus Torvalds /*
3631da177e4SLinus Torvalds * search hit
3641da177e4SLinus Torvalds */
3651da177e4SLinus Torvalds /* search hit - leaf page:
3661da177e4SLinus Torvalds * return the entry found
3671da177e4SLinus Torvalds */
3681da177e4SLinus Torvalds if (p->header.flag & BT_LEAF) {
3691da177e4SLinus Torvalds *cmpp = cmp;
3701da177e4SLinus Torvalds
3711da177e4SLinus Torvalds /* compute number of pages to split */
3721da177e4SLinus Torvalds if (flag & XT_INSERT) {
3731da177e4SLinus Torvalds if (p->header.nextindex ==
3741da177e4SLinus Torvalds p->header.maxentry)
3751da177e4SLinus Torvalds nsplit++;
3761da177e4SLinus Torvalds else
3771da177e4SLinus Torvalds nsplit = 0;
3781da177e4SLinus Torvalds btstack->nsplit = nsplit;
3791da177e4SLinus Torvalds }
3801da177e4SLinus Torvalds
3811da177e4SLinus Torvalds /* save search result */
3821da177e4SLinus Torvalds btsp = btstack->top;
3831da177e4SLinus Torvalds btsp->bn = bn;
3841da177e4SLinus Torvalds btsp->index = index;
3851da177e4SLinus Torvalds btsp->mp = mp;
3861da177e4SLinus Torvalds
3871da177e4SLinus Torvalds /* init sequential access heuristics */
3881da177e4SLinus Torvalds btindex = jfs_ip->btindex;
3891da177e4SLinus Torvalds if (index == btindex ||
3901da177e4SLinus Torvalds index == btindex + 1)
3911da177e4SLinus Torvalds jfs_ip->btorder = BT_SEQUENTIAL;
3921da177e4SLinus Torvalds else
3931da177e4SLinus Torvalds jfs_ip->btorder = BT_RANDOM;
3941da177e4SLinus Torvalds jfs_ip->btindex = index;
3951da177e4SLinus Torvalds
3961da177e4SLinus Torvalds return 0;
3971da177e4SLinus Torvalds }
3981da177e4SLinus Torvalds /* search hit - internal page:
3991da177e4SLinus Torvalds * descend/search its child page
4001da177e4SLinus Torvalds */
4016b6bf510SDave Kleikamp if (index < le16_to_cpu(p->header.nextindex)-1)
4026628465eSDave Kleikamp next = offsetXAD(&p->xad[index + 1]);
4031da177e4SLinus Torvalds goto next;
4041da177e4SLinus Torvalds }
4051da177e4SLinus Torvalds
4061da177e4SLinus Torvalds if (cmp > 0) {
4071da177e4SLinus Torvalds base = index + 1;
4081da177e4SLinus Torvalds --lim;
4091da177e4SLinus Torvalds }
4101da177e4SLinus Torvalds }
4111da177e4SLinus Torvalds
4121da177e4SLinus Torvalds /*
4131da177e4SLinus Torvalds * search miss
4141da177e4SLinus Torvalds *
4151da177e4SLinus Torvalds * base is the smallest index with key (Kj) greater than
4161da177e4SLinus Torvalds * search key (K) and may be zero or maxentry index.
4171da177e4SLinus Torvalds */
4186b6bf510SDave Kleikamp if (base < le16_to_cpu(p->header.nextindex))
4196628465eSDave Kleikamp next = offsetXAD(&p->xad[base]);
4201da177e4SLinus Torvalds /*
4211da177e4SLinus Torvalds * search miss - leaf page:
4221da177e4SLinus Torvalds *
4231da177e4SLinus Torvalds * return location of entry (base) where new entry with
4241da177e4SLinus Torvalds * search key K is to be inserted.
4251da177e4SLinus Torvalds */
4261da177e4SLinus Torvalds if (p->header.flag & BT_LEAF) {
4271da177e4SLinus Torvalds *cmpp = cmp;
4281da177e4SLinus Torvalds
4291da177e4SLinus Torvalds /* compute number of pages to split */
4301da177e4SLinus Torvalds if (flag & XT_INSERT) {
4311da177e4SLinus Torvalds if (p->header.nextindex ==
4321da177e4SLinus Torvalds p->header.maxentry)
4331da177e4SLinus Torvalds nsplit++;
4341da177e4SLinus Torvalds else
4351da177e4SLinus Torvalds nsplit = 0;
4361da177e4SLinus Torvalds btstack->nsplit = nsplit;
4371da177e4SLinus Torvalds }
4381da177e4SLinus Torvalds
4391da177e4SLinus Torvalds /* save search result */
4401da177e4SLinus Torvalds btsp = btstack->top;
4411da177e4SLinus Torvalds btsp->bn = bn;
4421da177e4SLinus Torvalds btsp->index = base;
4431da177e4SLinus Torvalds btsp->mp = mp;
4441da177e4SLinus Torvalds
4451da177e4SLinus Torvalds /* init sequential access heuristics */
4461da177e4SLinus Torvalds btindex = jfs_ip->btindex;
4471da177e4SLinus Torvalds if (base == btindex || base == btindex + 1)
4481da177e4SLinus Torvalds jfs_ip->btorder = BT_SEQUENTIAL;
4491da177e4SLinus Torvalds else
4501da177e4SLinus Torvalds jfs_ip->btorder = BT_RANDOM;
4511da177e4SLinus Torvalds jfs_ip->btindex = base;
4521da177e4SLinus Torvalds
4536628465eSDave Kleikamp if (nextp)
4546628465eSDave Kleikamp *nextp = next;
4556628465eSDave Kleikamp
4561da177e4SLinus Torvalds return 0;
4571da177e4SLinus Torvalds }
4581da177e4SLinus Torvalds
4591da177e4SLinus Torvalds /*
4601da177e4SLinus Torvalds * search miss - non-leaf page:
4611da177e4SLinus Torvalds *
4621da177e4SLinus Torvalds * if base is non-zero, decrement base by one to get the parent
4631da177e4SLinus Torvalds * entry of the child page to search.
4641da177e4SLinus Torvalds */
4651da177e4SLinus Torvalds index = base ? base - 1 : base;
4661da177e4SLinus Torvalds
4671da177e4SLinus Torvalds /*
4681da177e4SLinus Torvalds * go down to child page
4691da177e4SLinus Torvalds */
4701da177e4SLinus Torvalds next:
4711da177e4SLinus Torvalds /* update number of pages to split */
4721da177e4SLinus Torvalds if (p->header.nextindex == p->header.maxentry)
4731da177e4SLinus Torvalds nsplit++;
4741da177e4SLinus Torvalds else
4751da177e4SLinus Torvalds nsplit = 0;
4761da177e4SLinus Torvalds
4771da177e4SLinus Torvalds /* push (bn, index) of the parent page/entry */
47817e6afc7SDave Kleikamp if (BT_STACK_FULL(btstack)) {
479eb8630d7SJoe Perches jfs_error(ip->i_sb, "stack overrun!\n");
48017e6afc7SDave Kleikamp XT_PUTPAGE(mp);
48117e6afc7SDave Kleikamp return -EIO;
48217e6afc7SDave Kleikamp }
4831da177e4SLinus Torvalds BT_PUSH(btstack, bn, index);
4841da177e4SLinus Torvalds
4851da177e4SLinus Torvalds /* get the child page block number */
4861da177e4SLinus Torvalds bn = addressXAD(&p->xad[index]);
4871da177e4SLinus Torvalds
4881da177e4SLinus Torvalds /* unpin the parent page */
4891da177e4SLinus Torvalds XT_PUTPAGE(mp);
4901da177e4SLinus Torvalds }
4911da177e4SLinus Torvalds }
4921da177e4SLinus Torvalds
4931da177e4SLinus Torvalds /*
4941da177e4SLinus Torvalds * xtInsert()
4951da177e4SLinus Torvalds *
4961da177e4SLinus Torvalds * function:
4971da177e4SLinus Torvalds *
4981da177e4SLinus Torvalds * parameter:
4991da177e4SLinus Torvalds * tid - transaction id;
5001da177e4SLinus Torvalds * ip - file object;
5011da177e4SLinus Torvalds * xflag - extent flag (XAD_NOTRECORDED):
5021da177e4SLinus Torvalds * xoff - extent offset;
5031da177e4SLinus Torvalds * xlen - extent length;
5041da177e4SLinus Torvalds * xaddrp - extent address pointer (in/out):
5051da177e4SLinus Torvalds * if (*xaddrp)
5061da177e4SLinus Torvalds * caller allocated data extent at *xaddrp;
5071da177e4SLinus Torvalds * else
5081da177e4SLinus Torvalds * allocate data extent and return its xaddr;
5091da177e4SLinus Torvalds * flag -
5101da177e4SLinus Torvalds *
5111da177e4SLinus Torvalds * return:
5121da177e4SLinus Torvalds */
xtInsert(tid_t tid,struct inode * ip,int xflag,s64 xoff,s32 xlen,s64 * xaddrp,int flag)5131da177e4SLinus Torvalds int xtInsert(tid_t tid, /* transaction id */
5141da177e4SLinus Torvalds struct inode *ip, int xflag, s64 xoff, s32 xlen, s64 * xaddrp,
5151da177e4SLinus Torvalds int flag)
5161da177e4SLinus Torvalds {
5171da177e4SLinus Torvalds int rc = 0;
5181da177e4SLinus Torvalds s64 xaddr, hint;
5191da177e4SLinus Torvalds struct metapage *mp; /* meta-page buffer */
5201da177e4SLinus Torvalds xtpage_t *p; /* base B+-tree index page */
5211da177e4SLinus Torvalds s64 bn;
5221da177e4SLinus Torvalds int index, nextindex;
5231da177e4SLinus Torvalds struct btstack btstack; /* traverse stack */
5241da177e4SLinus Torvalds struct xtsplit split; /* split information */
5251da177e4SLinus Torvalds xad_t *xad;
5261da177e4SLinus Torvalds int cmp;
5276628465eSDave Kleikamp s64 next;
5281da177e4SLinus Torvalds struct tlock *tlck;
5291da177e4SLinus Torvalds struct xtlock *xtlck;
5301da177e4SLinus Torvalds
5311da177e4SLinus Torvalds jfs_info("xtInsert: nxoff:0x%lx nxlen:0x%x", (ulong) xoff, xlen);
5321da177e4SLinus Torvalds
5331da177e4SLinus Torvalds /*
5341da177e4SLinus Torvalds * search for the entry location at which to insert:
5351da177e4SLinus Torvalds *
5361da177e4SLinus Torvalds * xtFastSearch() and xtSearch() both returns (leaf page
5371da177e4SLinus Torvalds * pinned, index at which to insert).
5381da177e4SLinus Torvalds * n.b. xtSearch() may return index of maxentry of
5391da177e4SLinus Torvalds * the full page.
5401da177e4SLinus Torvalds */
5416628465eSDave Kleikamp if ((rc = xtSearch(ip, xoff, &next, &cmp, &btstack, XT_INSERT)))
5421da177e4SLinus Torvalds return rc;
5431da177e4SLinus Torvalds
5441da177e4SLinus Torvalds /* retrieve search result */
5451da177e4SLinus Torvalds XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
5461da177e4SLinus Torvalds
5471da177e4SLinus Torvalds /* This test must follow XT_GETSEARCH since mp must be valid if
5481da177e4SLinus Torvalds * we branch to out: */
5496628465eSDave Kleikamp if ((cmp == 0) || (next && (xlen > next - xoff))) {
5501da177e4SLinus Torvalds rc = -EEXIST;
5511da177e4SLinus Torvalds goto out;
5521da177e4SLinus Torvalds }
5531da177e4SLinus Torvalds
5541da177e4SLinus Torvalds /*
5551da177e4SLinus Torvalds * allocate data extent requested
5561da177e4SLinus Torvalds *
5571da177e4SLinus Torvalds * allocation hint: last xad
5581da177e4SLinus Torvalds */
5591da177e4SLinus Torvalds if ((xaddr = *xaddrp) == 0) {
5601da177e4SLinus Torvalds if (index > XTENTRYSTART) {
5611da177e4SLinus Torvalds xad = &p->xad[index - 1];
5621da177e4SLinus Torvalds hint = addressXAD(xad) + lengthXAD(xad) - 1;
5631da177e4SLinus Torvalds } else
5641da177e4SLinus Torvalds hint = 0;
5655dd4056dSChristoph Hellwig if ((rc = dquot_alloc_block(ip, xlen)))
5661da177e4SLinus Torvalds goto out;
5671da177e4SLinus Torvalds if ((rc = dbAlloc(ip, hint, (s64) xlen, &xaddr))) {
5685dd4056dSChristoph Hellwig dquot_free_block(ip, xlen);
5691da177e4SLinus Torvalds goto out;
5701da177e4SLinus Torvalds }
5711da177e4SLinus Torvalds }
5721da177e4SLinus Torvalds
5731da177e4SLinus Torvalds /*
5741da177e4SLinus Torvalds * insert entry for new extent
5751da177e4SLinus Torvalds */
5761da177e4SLinus Torvalds xflag |= XAD_NEW;
5771da177e4SLinus Torvalds
5781da177e4SLinus Torvalds /*
5791da177e4SLinus Torvalds * if the leaf page is full, split the page and
5801da177e4SLinus Torvalds * propagate up the router entry for the new page from split
5811da177e4SLinus Torvalds *
5821da177e4SLinus Torvalds * The xtSplitUp() will insert the entry and unpin the leaf page.
5831da177e4SLinus Torvalds */
5841da177e4SLinus Torvalds nextindex = le16_to_cpu(p->header.nextindex);
5851da177e4SLinus Torvalds if (nextindex == le16_to_cpu(p->header.maxentry)) {
5861da177e4SLinus Torvalds split.mp = mp;
5871da177e4SLinus Torvalds split.index = index;
5881da177e4SLinus Torvalds split.flag = xflag;
5891da177e4SLinus Torvalds split.off = xoff;
5901da177e4SLinus Torvalds split.len = xlen;
5911da177e4SLinus Torvalds split.addr = xaddr;
5921da177e4SLinus Torvalds split.pxdlist = NULL;
5931da177e4SLinus Torvalds if ((rc = xtSplitUp(tid, ip, &split, &btstack))) {
5941da177e4SLinus Torvalds /* undo data extent allocation */
5951da177e4SLinus Torvalds if (*xaddrp == 0) {
5961da177e4SLinus Torvalds dbFree(ip, xaddr, (s64) xlen);
5975dd4056dSChristoph Hellwig dquot_free_block(ip, xlen);
5981da177e4SLinus Torvalds }
5991da177e4SLinus Torvalds return rc;
6001da177e4SLinus Torvalds }
6011da177e4SLinus Torvalds
6021da177e4SLinus Torvalds *xaddrp = xaddr;
6031da177e4SLinus Torvalds return 0;
6041da177e4SLinus Torvalds }
6051da177e4SLinus Torvalds
6061da177e4SLinus Torvalds /*
6071da177e4SLinus Torvalds * insert the new entry into the leaf page
6081da177e4SLinus Torvalds */
6091da177e4SLinus Torvalds /*
6101da177e4SLinus Torvalds * acquire a transaction lock on the leaf page;
6111da177e4SLinus Torvalds *
6121da177e4SLinus Torvalds * action: xad insertion/extension;
6131da177e4SLinus Torvalds */
6141da177e4SLinus Torvalds BT_MARK_DIRTY(mp, ip);
6151da177e4SLinus Torvalds
6161da177e4SLinus Torvalds /* if insert into middle, shift right remaining entries. */
6171da177e4SLinus Torvalds if (index < nextindex)
6181da177e4SLinus Torvalds memmove(&p->xad[index + 1], &p->xad[index],
6191da177e4SLinus Torvalds (nextindex - index) * sizeof(xad_t));
6201da177e4SLinus Torvalds
6211da177e4SLinus Torvalds /* insert the new entry: mark the entry NEW */
6221da177e4SLinus Torvalds xad = &p->xad[index];
6231da177e4SLinus Torvalds XT_PUTENTRY(xad, xflag, xoff, xlen, xaddr);
6241da177e4SLinus Torvalds
6251da177e4SLinus Torvalds /* advance next available entry index */
62689145622SMarcin Slusarz le16_add_cpu(&p->header.nextindex, 1);
6271da177e4SLinus Torvalds
6281da177e4SLinus Torvalds /* Don't log it if there are no links to the file */
6291da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
6301da177e4SLinus Torvalds tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
6311da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
6321da177e4SLinus Torvalds xtlck->lwm.offset =
6331da177e4SLinus Torvalds (xtlck->lwm.offset) ? min(index,
6341da177e4SLinus Torvalds (int)xtlck->lwm.offset) : index;
6351da177e4SLinus Torvalds xtlck->lwm.length =
6361da177e4SLinus Torvalds le16_to_cpu(p->header.nextindex) - xtlck->lwm.offset;
6371da177e4SLinus Torvalds }
6381da177e4SLinus Torvalds
6391da177e4SLinus Torvalds *xaddrp = xaddr;
6401da177e4SLinus Torvalds
6411da177e4SLinus Torvalds out:
6421da177e4SLinus Torvalds /* unpin the leaf page */
6431da177e4SLinus Torvalds XT_PUTPAGE(mp);
6441da177e4SLinus Torvalds
6451da177e4SLinus Torvalds return rc;
6461da177e4SLinus Torvalds }
6471da177e4SLinus Torvalds
6481da177e4SLinus Torvalds
6491da177e4SLinus Torvalds /*
6501da177e4SLinus Torvalds * xtSplitUp()
6511da177e4SLinus Torvalds *
6521da177e4SLinus Torvalds * function:
6531da177e4SLinus Torvalds * split full pages as propagating insertion up the tree
6541da177e4SLinus Torvalds *
6551da177e4SLinus Torvalds * parameter:
6561da177e4SLinus Torvalds * tid - transaction id;
6571da177e4SLinus Torvalds * ip - file object;
6581da177e4SLinus Torvalds * split - entry parameter descriptor;
6591da177e4SLinus Torvalds * btstack - traverse stack from xtSearch()
6601da177e4SLinus Torvalds *
6611da177e4SLinus Torvalds * return:
6621da177e4SLinus Torvalds */
6631da177e4SLinus Torvalds static int
xtSplitUp(tid_t tid,struct inode * ip,struct xtsplit * split,struct btstack * btstack)6641da177e4SLinus Torvalds xtSplitUp(tid_t tid,
6651da177e4SLinus Torvalds struct inode *ip, struct xtsplit * split, struct btstack * btstack)
6661da177e4SLinus Torvalds {
6671da177e4SLinus Torvalds int rc = 0;
6681da177e4SLinus Torvalds struct metapage *smp;
6691da177e4SLinus Torvalds xtpage_t *sp; /* split page */
6701da177e4SLinus Torvalds struct metapage *rmp;
6711da177e4SLinus Torvalds s64 rbn; /* new right page block number */
6721da177e4SLinus Torvalds struct metapage *rcmp;
6731da177e4SLinus Torvalds xtpage_t *rcp; /* right child page */
6741da177e4SLinus Torvalds s64 rcbn; /* right child page block number */
6751da177e4SLinus Torvalds int skip; /* index of entry of insertion */
6761da177e4SLinus Torvalds int nextindex; /* next available entry index of p */
6771da177e4SLinus Torvalds struct btframe *parent; /* parent page entry on traverse stack */
6781da177e4SLinus Torvalds xad_t *xad;
6791da177e4SLinus Torvalds s64 xaddr;
6801da177e4SLinus Torvalds int xlen;
6811da177e4SLinus Torvalds int nsplit; /* number of pages split */
6821da177e4SLinus Torvalds struct pxdlist pxdlist;
6831da177e4SLinus Torvalds pxd_t *pxd;
6841da177e4SLinus Torvalds struct tlock *tlck;
6851da177e4SLinus Torvalds struct xtlock *xtlck;
6861da177e4SLinus Torvalds
6871da177e4SLinus Torvalds smp = split->mp;
6881da177e4SLinus Torvalds sp = XT_PAGE(ip, smp);
6891da177e4SLinus Torvalds
6901da177e4SLinus Torvalds /* is inode xtree root extension/inline EA area free ? */
6911da177e4SLinus Torvalds if ((sp->header.flag & BT_ROOT) && (!S_ISDIR(ip->i_mode)) &&
6921da177e4SLinus Torvalds (le16_to_cpu(sp->header.maxentry) < XTROOTMAXSLOT) &&
6931da177e4SLinus Torvalds (JFS_IP(ip)->mode2 & INLINEEA)) {
6941da177e4SLinus Torvalds sp->header.maxentry = cpu_to_le16(XTROOTMAXSLOT);
6951da177e4SLinus Torvalds JFS_IP(ip)->mode2 &= ~INLINEEA;
6961da177e4SLinus Torvalds
6971da177e4SLinus Torvalds BT_MARK_DIRTY(smp, ip);
6981da177e4SLinus Torvalds /*
6991da177e4SLinus Torvalds * acquire a transaction lock on the leaf page;
7001da177e4SLinus Torvalds *
7011da177e4SLinus Torvalds * action: xad insertion/extension;
7021da177e4SLinus Torvalds */
7031da177e4SLinus Torvalds
7041da177e4SLinus Torvalds /* if insert into middle, shift right remaining entries. */
7051da177e4SLinus Torvalds skip = split->index;
7061da177e4SLinus Torvalds nextindex = le16_to_cpu(sp->header.nextindex);
7071da177e4SLinus Torvalds if (skip < nextindex)
7081da177e4SLinus Torvalds memmove(&sp->xad[skip + 1], &sp->xad[skip],
7091da177e4SLinus Torvalds (nextindex - skip) * sizeof(xad_t));
7101da177e4SLinus Torvalds
7111da177e4SLinus Torvalds /* insert the new entry: mark the entry NEW */
7121da177e4SLinus Torvalds xad = &sp->xad[skip];
7131da177e4SLinus Torvalds XT_PUTENTRY(xad, split->flag, split->off, split->len,
7141da177e4SLinus Torvalds split->addr);
7151da177e4SLinus Torvalds
7161da177e4SLinus Torvalds /* advance next available entry index */
71789145622SMarcin Slusarz le16_add_cpu(&sp->header.nextindex, 1);
7181da177e4SLinus Torvalds
7191da177e4SLinus Torvalds /* Don't log it if there are no links to the file */
7201da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
7211da177e4SLinus Torvalds tlck = txLock(tid, ip, smp, tlckXTREE | tlckGROW);
7221da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
7231da177e4SLinus Torvalds xtlck->lwm.offset = (xtlck->lwm.offset) ?
7241da177e4SLinus Torvalds min(skip, (int)xtlck->lwm.offset) : skip;
7251da177e4SLinus Torvalds xtlck->lwm.length =
7261da177e4SLinus Torvalds le16_to_cpu(sp->header.nextindex) -
7271da177e4SLinus Torvalds xtlck->lwm.offset;
7281da177e4SLinus Torvalds }
7291da177e4SLinus Torvalds
7301da177e4SLinus Torvalds return 0;
7311da177e4SLinus Torvalds }
7321da177e4SLinus Torvalds
7331da177e4SLinus Torvalds /*
7341da177e4SLinus Torvalds * allocate new index blocks to cover index page split(s)
7351da177e4SLinus Torvalds *
7361da177e4SLinus Torvalds * allocation hint: ?
7371da177e4SLinus Torvalds */
7381da177e4SLinus Torvalds if (split->pxdlist == NULL) {
7391da177e4SLinus Torvalds nsplit = btstack->nsplit;
7401da177e4SLinus Torvalds split->pxdlist = &pxdlist;
7411da177e4SLinus Torvalds pxdlist.maxnpxd = pxdlist.npxd = 0;
7421da177e4SLinus Torvalds pxd = &pxdlist.pxd[0];
7431da177e4SLinus Torvalds xlen = JFS_SBI(ip->i_sb)->nbperpage;
7441da177e4SLinus Torvalds for (; nsplit > 0; nsplit--, pxd++) {
7451da177e4SLinus Torvalds if ((rc = dbAlloc(ip, (s64) 0, (s64) xlen, &xaddr))
7461da177e4SLinus Torvalds == 0) {
7471da177e4SLinus Torvalds PXDaddress(pxd, xaddr);
7481da177e4SLinus Torvalds PXDlength(pxd, xlen);
7491da177e4SLinus Torvalds
7501da177e4SLinus Torvalds pxdlist.maxnpxd++;
7511da177e4SLinus Torvalds
7521da177e4SLinus Torvalds continue;
7531da177e4SLinus Torvalds }
7541da177e4SLinus Torvalds
7551da177e4SLinus Torvalds /* undo allocation */
7561da177e4SLinus Torvalds
7571da177e4SLinus Torvalds XT_PUTPAGE(smp);
7581da177e4SLinus Torvalds return rc;
7591da177e4SLinus Torvalds }
7601da177e4SLinus Torvalds }
7611da177e4SLinus Torvalds
7621da177e4SLinus Torvalds /*
7631da177e4SLinus Torvalds * Split leaf page <sp> into <sp> and a new right page <rp>.
7641da177e4SLinus Torvalds *
7651da177e4SLinus Torvalds * The split routines insert the new entry into the leaf page,
7661da177e4SLinus Torvalds * and acquire txLock as appropriate.
7671da177e4SLinus Torvalds * return <rp> pinned and its block number <rpbn>.
7681da177e4SLinus Torvalds */
7691da177e4SLinus Torvalds rc = (sp->header.flag & BT_ROOT) ?
7701da177e4SLinus Torvalds xtSplitRoot(tid, ip, split, &rmp) :
7711da177e4SLinus Torvalds xtSplitPage(tid, ip, split, &rmp, &rbn);
7721da177e4SLinus Torvalds
7731da177e4SLinus Torvalds XT_PUTPAGE(smp);
7741da177e4SLinus Torvalds
7751da177e4SLinus Torvalds if (rc)
7761da177e4SLinus Torvalds return -EIO;
7771da177e4SLinus Torvalds /*
7781da177e4SLinus Torvalds * propagate up the router entry for the leaf page just split
7791da177e4SLinus Torvalds *
7801da177e4SLinus Torvalds * insert a router entry for the new page into the parent page,
7811da177e4SLinus Torvalds * propagate the insert/split up the tree by walking back the stack
7821da177e4SLinus Torvalds * of (bn of parent page, index of child page entry in parent page)
7831da177e4SLinus Torvalds * that were traversed during the search for the page that split.
7841da177e4SLinus Torvalds *
7851da177e4SLinus Torvalds * the propagation of insert/split up the tree stops if the root
7861da177e4SLinus Torvalds * splits or the page inserted into doesn't have to split to hold
7871da177e4SLinus Torvalds * the new entry.
7881da177e4SLinus Torvalds *
7891da177e4SLinus Torvalds * the parent entry for the split page remains the same, and
7901da177e4SLinus Torvalds * a new entry is inserted at its right with the first key and
7911da177e4SLinus Torvalds * block number of the new right page.
7921da177e4SLinus Torvalds *
7931da177e4SLinus Torvalds * There are a maximum of 3 pages pinned at any time:
7941da177e4SLinus Torvalds * right child, left parent and right parent (when the parent splits)
7951da177e4SLinus Torvalds * to keep the child page pinned while working on the parent.
7961da177e4SLinus Torvalds * make sure that all pins are released at exit.
7971da177e4SLinus Torvalds */
7981da177e4SLinus Torvalds while ((parent = BT_POP(btstack)) != NULL) {
7991da177e4SLinus Torvalds /* parent page specified by stack frame <parent> */
8001da177e4SLinus Torvalds
8011da177e4SLinus Torvalds /* keep current child pages <rcp> pinned */
8021da177e4SLinus Torvalds rcmp = rmp;
8031da177e4SLinus Torvalds rcbn = rbn;
8041da177e4SLinus Torvalds rcp = XT_PAGE(ip, rcmp);
8051da177e4SLinus Torvalds
8061da177e4SLinus Torvalds /*
8071da177e4SLinus Torvalds * insert router entry in parent for new right child page <rp>
8081da177e4SLinus Torvalds */
8091da177e4SLinus Torvalds /* get/pin the parent page <sp> */
8101da177e4SLinus Torvalds XT_GETPAGE(ip, parent->bn, smp, PSIZE, sp, rc);
8111da177e4SLinus Torvalds if (rc) {
8121da177e4SLinus Torvalds XT_PUTPAGE(rcmp);
8131da177e4SLinus Torvalds return rc;
8141da177e4SLinus Torvalds }
8151da177e4SLinus Torvalds
8161da177e4SLinus Torvalds /*
8171da177e4SLinus Torvalds * The new key entry goes ONE AFTER the index of parent entry,
8181da177e4SLinus Torvalds * because the split was to the right.
8191da177e4SLinus Torvalds */
8201da177e4SLinus Torvalds skip = parent->index + 1;
8211da177e4SLinus Torvalds
8221da177e4SLinus Torvalds /*
8231da177e4SLinus Torvalds * split or shift right remaining entries of the parent page
8241da177e4SLinus Torvalds */
8251da177e4SLinus Torvalds nextindex = le16_to_cpu(sp->header.nextindex);
8261da177e4SLinus Torvalds /*
8271da177e4SLinus Torvalds * parent page is full - split the parent page
8281da177e4SLinus Torvalds */
8291da177e4SLinus Torvalds if (nextindex == le16_to_cpu(sp->header.maxentry)) {
8301da177e4SLinus Torvalds /* init for parent page split */
8311da177e4SLinus Torvalds split->mp = smp;
8321da177e4SLinus Torvalds split->index = skip; /* index at insert */
8331da177e4SLinus Torvalds split->flag = XAD_NEW;
8341da177e4SLinus Torvalds split->off = offsetXAD(&rcp->xad[XTENTRYSTART]);
8351da177e4SLinus Torvalds split->len = JFS_SBI(ip->i_sb)->nbperpage;
8361da177e4SLinus Torvalds split->addr = rcbn;
8371da177e4SLinus Torvalds
8381da177e4SLinus Torvalds /* unpin previous right child page */
8391da177e4SLinus Torvalds XT_PUTPAGE(rcmp);
8401da177e4SLinus Torvalds
8411da177e4SLinus Torvalds /* The split routines insert the new entry,
8421da177e4SLinus Torvalds * and acquire txLock as appropriate.
8431da177e4SLinus Torvalds * return <rp> pinned and its block number <rpbn>.
8441da177e4SLinus Torvalds */
8451da177e4SLinus Torvalds rc = (sp->header.flag & BT_ROOT) ?
8461da177e4SLinus Torvalds xtSplitRoot(tid, ip, split, &rmp) :
8471da177e4SLinus Torvalds xtSplitPage(tid, ip, split, &rmp, &rbn);
8481da177e4SLinus Torvalds if (rc) {
8491da177e4SLinus Torvalds XT_PUTPAGE(smp);
8501da177e4SLinus Torvalds return rc;
8511da177e4SLinus Torvalds }
8521da177e4SLinus Torvalds
8531da177e4SLinus Torvalds XT_PUTPAGE(smp);
8541da177e4SLinus Torvalds /* keep new child page <rp> pinned */
8551da177e4SLinus Torvalds }
8561da177e4SLinus Torvalds /*
8571da177e4SLinus Torvalds * parent page is not full - insert in parent page
8581da177e4SLinus Torvalds */
8591da177e4SLinus Torvalds else {
8601da177e4SLinus Torvalds /*
8611da177e4SLinus Torvalds * insert router entry in parent for the right child
8621da177e4SLinus Torvalds * page from the first entry of the right child page:
8631da177e4SLinus Torvalds */
8641da177e4SLinus Torvalds /*
8651da177e4SLinus Torvalds * acquire a transaction lock on the parent page;
8661da177e4SLinus Torvalds *
8671da177e4SLinus Torvalds * action: router xad insertion;
8681da177e4SLinus Torvalds */
8691da177e4SLinus Torvalds BT_MARK_DIRTY(smp, ip);
8701da177e4SLinus Torvalds
8711da177e4SLinus Torvalds /*
8721da177e4SLinus Torvalds * if insert into middle, shift right remaining entries
8731da177e4SLinus Torvalds */
8741da177e4SLinus Torvalds if (skip < nextindex)
8751da177e4SLinus Torvalds memmove(&sp->xad[skip + 1], &sp->xad[skip],
8761da177e4SLinus Torvalds (nextindex -
8771da177e4SLinus Torvalds skip) << L2XTSLOTSIZE);
8781da177e4SLinus Torvalds
8791da177e4SLinus Torvalds /* insert the router entry */
8801da177e4SLinus Torvalds xad = &sp->xad[skip];
8811da177e4SLinus Torvalds XT_PUTENTRY(xad, XAD_NEW,
8821da177e4SLinus Torvalds offsetXAD(&rcp->xad[XTENTRYSTART]),
8831da177e4SLinus Torvalds JFS_SBI(ip->i_sb)->nbperpage, rcbn);
8841da177e4SLinus Torvalds
8851da177e4SLinus Torvalds /* advance next available entry index. */
88689145622SMarcin Slusarz le16_add_cpu(&sp->header.nextindex, 1);
8871da177e4SLinus Torvalds
8881da177e4SLinus Torvalds /* Don't log it if there are no links to the file */
8891da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
8901da177e4SLinus Torvalds tlck = txLock(tid, ip, smp,
8911da177e4SLinus Torvalds tlckXTREE | tlckGROW);
8921da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
8931da177e4SLinus Torvalds xtlck->lwm.offset = (xtlck->lwm.offset) ?
8941da177e4SLinus Torvalds min(skip, (int)xtlck->lwm.offset) : skip;
8951da177e4SLinus Torvalds xtlck->lwm.length =
8961da177e4SLinus Torvalds le16_to_cpu(sp->header.nextindex) -
8971da177e4SLinus Torvalds xtlck->lwm.offset;
8981da177e4SLinus Torvalds }
8991da177e4SLinus Torvalds
9001da177e4SLinus Torvalds /* unpin parent page */
9011da177e4SLinus Torvalds XT_PUTPAGE(smp);
9021da177e4SLinus Torvalds
9031da177e4SLinus Torvalds /* exit propagate up */
9041da177e4SLinus Torvalds break;
9051da177e4SLinus Torvalds }
9061da177e4SLinus Torvalds }
9071da177e4SLinus Torvalds
9081da177e4SLinus Torvalds /* unpin current right page */
9091da177e4SLinus Torvalds XT_PUTPAGE(rmp);
9101da177e4SLinus Torvalds
9111da177e4SLinus Torvalds return 0;
9121da177e4SLinus Torvalds }
9131da177e4SLinus Torvalds
9141da177e4SLinus Torvalds
9151da177e4SLinus Torvalds /*
9161da177e4SLinus Torvalds * xtSplitPage()
9171da177e4SLinus Torvalds *
9181da177e4SLinus Torvalds * function:
9191da177e4SLinus Torvalds * split a full non-root page into
9201da177e4SLinus Torvalds * original/split/left page and new right page
9211da177e4SLinus Torvalds * i.e., the original/split page remains as left page.
9221da177e4SLinus Torvalds *
9231da177e4SLinus Torvalds * parameter:
9241da177e4SLinus Torvalds * int tid,
9251da177e4SLinus Torvalds * struct inode *ip,
9261da177e4SLinus Torvalds * struct xtsplit *split,
9271da177e4SLinus Torvalds * struct metapage **rmpp,
9281da177e4SLinus Torvalds * u64 *rbnp,
9291da177e4SLinus Torvalds *
9301da177e4SLinus Torvalds * return:
9311da177e4SLinus Torvalds * Pointer to page in which to insert or NULL on error.
9321da177e4SLinus Torvalds */
9331da177e4SLinus Torvalds static int
xtSplitPage(tid_t tid,struct inode * ip,struct xtsplit * split,struct metapage ** rmpp,s64 * rbnp)9341da177e4SLinus Torvalds xtSplitPage(tid_t tid, struct inode *ip,
9351da177e4SLinus Torvalds struct xtsplit * split, struct metapage ** rmpp, s64 * rbnp)
9361da177e4SLinus Torvalds {
9371da177e4SLinus Torvalds int rc = 0;
9381da177e4SLinus Torvalds struct metapage *smp;
9391da177e4SLinus Torvalds xtpage_t *sp;
9401da177e4SLinus Torvalds struct metapage *rmp;
9411da177e4SLinus Torvalds xtpage_t *rp; /* new right page allocated */
9421da177e4SLinus Torvalds s64 rbn; /* new right page block number */
9431da177e4SLinus Torvalds struct metapage *mp;
9441da177e4SLinus Torvalds xtpage_t *p;
9451da177e4SLinus Torvalds s64 nextbn;
9461da177e4SLinus Torvalds int skip, maxentry, middle, righthalf, n;
9471da177e4SLinus Torvalds xad_t *xad;
9481da177e4SLinus Torvalds struct pxdlist *pxdlist;
9491da177e4SLinus Torvalds pxd_t *pxd;
9501da177e4SLinus Torvalds struct tlock *tlck;
9511da177e4SLinus Torvalds struct xtlock *sxtlck = NULL, *rxtlck = NULL;
9521da177e4SLinus Torvalds int quota_allocation = 0;
9531da177e4SLinus Torvalds
9541da177e4SLinus Torvalds smp = split->mp;
9551da177e4SLinus Torvalds sp = XT_PAGE(ip, smp);
9561da177e4SLinus Torvalds
9571da177e4SLinus Torvalds INCREMENT(xtStat.split);
9581da177e4SLinus Torvalds
9591da177e4SLinus Torvalds pxdlist = split->pxdlist;
9601da177e4SLinus Torvalds pxd = &pxdlist->pxd[pxdlist->npxd];
9611da177e4SLinus Torvalds pxdlist->npxd++;
9621da177e4SLinus Torvalds rbn = addressPXD(pxd);
9631da177e4SLinus Torvalds
9641da177e4SLinus Torvalds /* Allocate blocks to quota. */
9655dd4056dSChristoph Hellwig rc = dquot_alloc_block(ip, lengthPXD(pxd));
9665dd4056dSChristoph Hellwig if (rc)
9671da177e4SLinus Torvalds goto clean_up;
9681da177e4SLinus Torvalds
9691da177e4SLinus Torvalds quota_allocation += lengthPXD(pxd);
9701da177e4SLinus Torvalds
9711da177e4SLinus Torvalds /*
9721da177e4SLinus Torvalds * allocate the new right page for the split
9731da177e4SLinus Torvalds */
9741da177e4SLinus Torvalds rmp = get_metapage(ip, rbn, PSIZE, 1);
9751da177e4SLinus Torvalds if (rmp == NULL) {
9761da177e4SLinus Torvalds rc = -EIO;
9771da177e4SLinus Torvalds goto clean_up;
9781da177e4SLinus Torvalds }
9791da177e4SLinus Torvalds
9801da177e4SLinus Torvalds jfs_info("xtSplitPage: ip:0x%p smp:0x%p rmp:0x%p", ip, smp, rmp);
9811da177e4SLinus Torvalds
9821da177e4SLinus Torvalds BT_MARK_DIRTY(rmp, ip);
9831da177e4SLinus Torvalds /*
9841da177e4SLinus Torvalds * action: new page;
9851da177e4SLinus Torvalds */
9861da177e4SLinus Torvalds
9871da177e4SLinus Torvalds rp = (xtpage_t *) rmp->data;
9881da177e4SLinus Torvalds rp->header.self = *pxd;
9891da177e4SLinus Torvalds rp->header.flag = sp->header.flag & BT_TYPE;
9901da177e4SLinus Torvalds rp->header.maxentry = sp->header.maxentry; /* little-endian */
9911da177e4SLinus Torvalds rp->header.nextindex = cpu_to_le16(XTENTRYSTART);
9921da177e4SLinus Torvalds
9931da177e4SLinus Torvalds BT_MARK_DIRTY(smp, ip);
9941da177e4SLinus Torvalds /* Don't log it if there are no links to the file */
9951da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
9961da177e4SLinus Torvalds /*
9971da177e4SLinus Torvalds * acquire a transaction lock on the new right page;
9981da177e4SLinus Torvalds */
9991da177e4SLinus Torvalds tlck = txLock(tid, ip, rmp, tlckXTREE | tlckNEW);
10001da177e4SLinus Torvalds rxtlck = (struct xtlock *) & tlck->lock;
10011da177e4SLinus Torvalds rxtlck->lwm.offset = XTENTRYSTART;
10021da177e4SLinus Torvalds /*
10031da177e4SLinus Torvalds * acquire a transaction lock on the split page
10041da177e4SLinus Torvalds */
10051da177e4SLinus Torvalds tlck = txLock(tid, ip, smp, tlckXTREE | tlckGROW);
10061da177e4SLinus Torvalds sxtlck = (struct xtlock *) & tlck->lock;
10071da177e4SLinus Torvalds }
10081da177e4SLinus Torvalds
10091da177e4SLinus Torvalds /*
10101da177e4SLinus Torvalds * initialize/update sibling pointers of <sp> and <rp>
10111da177e4SLinus Torvalds */
10121da177e4SLinus Torvalds nextbn = le64_to_cpu(sp->header.next);
10131da177e4SLinus Torvalds rp->header.next = cpu_to_le64(nextbn);
10141da177e4SLinus Torvalds rp->header.prev = cpu_to_le64(addressPXD(&sp->header.self));
10151da177e4SLinus Torvalds sp->header.next = cpu_to_le64(rbn);
10161da177e4SLinus Torvalds
10171da177e4SLinus Torvalds skip = split->index;
10181da177e4SLinus Torvalds
10191da177e4SLinus Torvalds /*
10201da177e4SLinus Torvalds * sequential append at tail (after last entry of last page)
10211da177e4SLinus Torvalds *
10221da177e4SLinus Torvalds * if splitting the last page on a level because of appending
10231da177e4SLinus Torvalds * a entry to it (skip is maxentry), it's likely that the access is
10241da177e4SLinus Torvalds * sequential. adding an empty page on the side of the level is less
10251da177e4SLinus Torvalds * work and can push the fill factor much higher than normal.
10261da177e4SLinus Torvalds * if we're wrong it's no big deal - we will do the split the right
10271da177e4SLinus Torvalds * way next time.
10281da177e4SLinus Torvalds * (it may look like it's equally easy to do a similar hack for
10291da177e4SLinus Torvalds * reverse sorted data, that is, split the tree left, but it's not.
10301da177e4SLinus Torvalds * Be my guest.)
10311da177e4SLinus Torvalds */
10321da177e4SLinus Torvalds if (nextbn == 0 && skip == le16_to_cpu(sp->header.maxentry)) {
10331da177e4SLinus Torvalds /*
10341da177e4SLinus Torvalds * acquire a transaction lock on the new/right page;
10351da177e4SLinus Torvalds *
10361da177e4SLinus Torvalds * action: xad insertion;
10371da177e4SLinus Torvalds */
10381da177e4SLinus Torvalds /* insert entry at the first entry of the new right page */
10391da177e4SLinus Torvalds xad = &rp->xad[XTENTRYSTART];
10401da177e4SLinus Torvalds XT_PUTENTRY(xad, split->flag, split->off, split->len,
10411da177e4SLinus Torvalds split->addr);
10421da177e4SLinus Torvalds
10431da177e4SLinus Torvalds rp->header.nextindex = cpu_to_le16(XTENTRYSTART + 1);
10441da177e4SLinus Torvalds
10451da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
10461da177e4SLinus Torvalds /* rxtlck->lwm.offset = XTENTRYSTART; */
10471da177e4SLinus Torvalds rxtlck->lwm.length = 1;
10481da177e4SLinus Torvalds }
10491da177e4SLinus Torvalds
10501da177e4SLinus Torvalds *rmpp = rmp;
10511da177e4SLinus Torvalds *rbnp = rbn;
10521da177e4SLinus Torvalds
10531da177e4SLinus Torvalds jfs_info("xtSplitPage: sp:0x%p rp:0x%p", sp, rp);
10541da177e4SLinus Torvalds return 0;
10551da177e4SLinus Torvalds }
10561da177e4SLinus Torvalds
10571da177e4SLinus Torvalds /*
10581da177e4SLinus Torvalds * non-sequential insert (at possibly middle page)
10591da177e4SLinus Torvalds */
10601da177e4SLinus Torvalds
10611da177e4SLinus Torvalds /*
10621da177e4SLinus Torvalds * update previous pointer of old next/right page of <sp>
10631da177e4SLinus Torvalds */
10641da177e4SLinus Torvalds if (nextbn != 0) {
10651da177e4SLinus Torvalds XT_GETPAGE(ip, nextbn, mp, PSIZE, p, rc);
10661da177e4SLinus Torvalds if (rc) {
10671da177e4SLinus Torvalds XT_PUTPAGE(rmp);
10681da177e4SLinus Torvalds goto clean_up;
10691da177e4SLinus Torvalds }
10701da177e4SLinus Torvalds
10711da177e4SLinus Torvalds BT_MARK_DIRTY(mp, ip);
10721da177e4SLinus Torvalds /*
10731da177e4SLinus Torvalds * acquire a transaction lock on the next page;
10741da177e4SLinus Torvalds *
10751da177e4SLinus Torvalds * action:sibling pointer update;
10761da177e4SLinus Torvalds */
10771da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip))
10781da177e4SLinus Torvalds tlck = txLock(tid, ip, mp, tlckXTREE | tlckRELINK);
10791da177e4SLinus Torvalds
10801da177e4SLinus Torvalds p->header.prev = cpu_to_le64(rbn);
10811da177e4SLinus Torvalds
10821da177e4SLinus Torvalds /* sibling page may have been updated previously, or
10831da177e4SLinus Torvalds * it may be updated later;
10841da177e4SLinus Torvalds */
10851da177e4SLinus Torvalds
10861da177e4SLinus Torvalds XT_PUTPAGE(mp);
10871da177e4SLinus Torvalds }
10881da177e4SLinus Torvalds
10891da177e4SLinus Torvalds /*
10901da177e4SLinus Torvalds * split the data between the split and new/right pages
10911da177e4SLinus Torvalds */
10921da177e4SLinus Torvalds maxentry = le16_to_cpu(sp->header.maxentry);
10931da177e4SLinus Torvalds middle = maxentry >> 1;
10941da177e4SLinus Torvalds righthalf = maxentry - middle;
10951da177e4SLinus Torvalds
10961da177e4SLinus Torvalds /*
10971da177e4SLinus Torvalds * skip index in old split/left page - insert into left page:
10981da177e4SLinus Torvalds */
10991da177e4SLinus Torvalds if (skip <= middle) {
11001da177e4SLinus Torvalds /* move right half of split page to the new right page */
11011da177e4SLinus Torvalds memmove(&rp->xad[XTENTRYSTART], &sp->xad[middle],
11021da177e4SLinus Torvalds righthalf << L2XTSLOTSIZE);
11031da177e4SLinus Torvalds
11041da177e4SLinus Torvalds /* shift right tail of left half to make room for new entry */
11051da177e4SLinus Torvalds if (skip < middle)
11061da177e4SLinus Torvalds memmove(&sp->xad[skip + 1], &sp->xad[skip],
11071da177e4SLinus Torvalds (middle - skip) << L2XTSLOTSIZE);
11081da177e4SLinus Torvalds
11091da177e4SLinus Torvalds /* insert new entry */
11101da177e4SLinus Torvalds xad = &sp->xad[skip];
11111da177e4SLinus Torvalds XT_PUTENTRY(xad, split->flag, split->off, split->len,
11121da177e4SLinus Torvalds split->addr);
11131da177e4SLinus Torvalds
11141da177e4SLinus Torvalds /* update page header */
11151da177e4SLinus Torvalds sp->header.nextindex = cpu_to_le16(middle + 1);
11161da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
11171da177e4SLinus Torvalds sxtlck->lwm.offset = (sxtlck->lwm.offset) ?
11181da177e4SLinus Torvalds min(skip, (int)sxtlck->lwm.offset) : skip;
11191da177e4SLinus Torvalds }
11201da177e4SLinus Torvalds
11211da177e4SLinus Torvalds rp->header.nextindex =
11221da177e4SLinus Torvalds cpu_to_le16(XTENTRYSTART + righthalf);
11231da177e4SLinus Torvalds }
11241da177e4SLinus Torvalds /*
11251da177e4SLinus Torvalds * skip index in new right page - insert into right page:
11261da177e4SLinus Torvalds */
11271da177e4SLinus Torvalds else {
11281da177e4SLinus Torvalds /* move left head of right half to right page */
11291da177e4SLinus Torvalds n = skip - middle;
11301da177e4SLinus Torvalds memmove(&rp->xad[XTENTRYSTART], &sp->xad[middle],
11311da177e4SLinus Torvalds n << L2XTSLOTSIZE);
11321da177e4SLinus Torvalds
11331da177e4SLinus Torvalds /* insert new entry */
11341da177e4SLinus Torvalds n += XTENTRYSTART;
11351da177e4SLinus Torvalds xad = &rp->xad[n];
11361da177e4SLinus Torvalds XT_PUTENTRY(xad, split->flag, split->off, split->len,
11371da177e4SLinus Torvalds split->addr);
11381da177e4SLinus Torvalds
11391da177e4SLinus Torvalds /* move right tail of right half to right page */
11401da177e4SLinus Torvalds if (skip < maxentry)
11411da177e4SLinus Torvalds memmove(&rp->xad[n + 1], &sp->xad[skip],
11421da177e4SLinus Torvalds (maxentry - skip) << L2XTSLOTSIZE);
11431da177e4SLinus Torvalds
11441da177e4SLinus Torvalds /* update page header */
11451da177e4SLinus Torvalds sp->header.nextindex = cpu_to_le16(middle);
11461da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
11471da177e4SLinus Torvalds sxtlck->lwm.offset = (sxtlck->lwm.offset) ?
11481da177e4SLinus Torvalds min(middle, (int)sxtlck->lwm.offset) : middle;
11491da177e4SLinus Torvalds }
11501da177e4SLinus Torvalds
11511da177e4SLinus Torvalds rp->header.nextindex = cpu_to_le16(XTENTRYSTART +
11521da177e4SLinus Torvalds righthalf + 1);
11531da177e4SLinus Torvalds }
11541da177e4SLinus Torvalds
11551da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
11561da177e4SLinus Torvalds sxtlck->lwm.length = le16_to_cpu(sp->header.nextindex) -
11571da177e4SLinus Torvalds sxtlck->lwm.offset;
11581da177e4SLinus Torvalds
11591da177e4SLinus Torvalds /* rxtlck->lwm.offset = XTENTRYSTART; */
11601da177e4SLinus Torvalds rxtlck->lwm.length = le16_to_cpu(rp->header.nextindex) -
11611da177e4SLinus Torvalds XTENTRYSTART;
11621da177e4SLinus Torvalds }
11631da177e4SLinus Torvalds
11641da177e4SLinus Torvalds *rmpp = rmp;
11651da177e4SLinus Torvalds *rbnp = rbn;
11661da177e4SLinus Torvalds
11671da177e4SLinus Torvalds jfs_info("xtSplitPage: sp:0x%p rp:0x%p", sp, rp);
11681da177e4SLinus Torvalds return rc;
11691da177e4SLinus Torvalds
11701da177e4SLinus Torvalds clean_up:
11711da177e4SLinus Torvalds
11721da177e4SLinus Torvalds /* Rollback quota allocation. */
11731da177e4SLinus Torvalds if (quota_allocation)
11745dd4056dSChristoph Hellwig dquot_free_block(ip, quota_allocation);
11751da177e4SLinus Torvalds
11761da177e4SLinus Torvalds return (rc);
11771da177e4SLinus Torvalds }
11781da177e4SLinus Torvalds
11791da177e4SLinus Torvalds
11801da177e4SLinus Torvalds /*
11811da177e4SLinus Torvalds * xtSplitRoot()
11821da177e4SLinus Torvalds *
11831da177e4SLinus Torvalds * function:
1184f720e3baSDave Kleikamp * split the full root page into original/root/split page and new
1185f720e3baSDave Kleikamp * right page
1186f720e3baSDave Kleikamp * i.e., root remains fixed in tree anchor (inode) and the root is
1187f720e3baSDave Kleikamp * copied to a single new right child page since root page <<
1188f720e3baSDave Kleikamp * non-root page, and the split root page contains a single entry
1189f720e3baSDave Kleikamp * for the new right child page.
11901da177e4SLinus Torvalds *
11911da177e4SLinus Torvalds * parameter:
11921da177e4SLinus Torvalds * int tid,
11931da177e4SLinus Torvalds * struct inode *ip,
11941da177e4SLinus Torvalds * struct xtsplit *split,
11951da177e4SLinus Torvalds * struct metapage **rmpp)
11961da177e4SLinus Torvalds *
11971da177e4SLinus Torvalds * return:
11981da177e4SLinus Torvalds * Pointer to page in which to insert or NULL on error.
11991da177e4SLinus Torvalds */
12001da177e4SLinus Torvalds static int
xtSplitRoot(tid_t tid,struct inode * ip,struct xtsplit * split,struct metapage ** rmpp)12011da177e4SLinus Torvalds xtSplitRoot(tid_t tid,
12021da177e4SLinus Torvalds struct inode *ip, struct xtsplit * split, struct metapage ** rmpp)
12031da177e4SLinus Torvalds {
12041da177e4SLinus Torvalds xtpage_t *sp;
12051da177e4SLinus Torvalds struct metapage *rmp;
12061da177e4SLinus Torvalds xtpage_t *rp;
12071da177e4SLinus Torvalds s64 rbn;
12081da177e4SLinus Torvalds int skip, nextindex;
12091da177e4SLinus Torvalds xad_t *xad;
12101da177e4SLinus Torvalds pxd_t *pxd;
12111da177e4SLinus Torvalds struct pxdlist *pxdlist;
12121da177e4SLinus Torvalds struct tlock *tlck;
12131da177e4SLinus Torvalds struct xtlock *xtlck;
12145dd4056dSChristoph Hellwig int rc;
12151da177e4SLinus Torvalds
1216*2ff51719SDave Kleikamp sp = (xtpage_t *) &JFS_IP(ip)->i_xtroot;
12171da177e4SLinus Torvalds
12181da177e4SLinus Torvalds INCREMENT(xtStat.split);
12191da177e4SLinus Torvalds
12201da177e4SLinus Torvalds /*
12211da177e4SLinus Torvalds * allocate a single (right) child page
12221da177e4SLinus Torvalds */
12231da177e4SLinus Torvalds pxdlist = split->pxdlist;
12241da177e4SLinus Torvalds pxd = &pxdlist->pxd[pxdlist->npxd];
12251da177e4SLinus Torvalds pxdlist->npxd++;
12261da177e4SLinus Torvalds rbn = addressPXD(pxd);
12271da177e4SLinus Torvalds rmp = get_metapage(ip, rbn, PSIZE, 1);
12281da177e4SLinus Torvalds if (rmp == NULL)
12291da177e4SLinus Torvalds return -EIO;
12301da177e4SLinus Torvalds
12311da177e4SLinus Torvalds /* Allocate blocks to quota. */
12325dd4056dSChristoph Hellwig rc = dquot_alloc_block(ip, lengthPXD(pxd));
12335dd4056dSChristoph Hellwig if (rc) {
12341da177e4SLinus Torvalds release_metapage(rmp);
12355dd4056dSChristoph Hellwig return rc;
12361da177e4SLinus Torvalds }
12371da177e4SLinus Torvalds
12381da177e4SLinus Torvalds jfs_info("xtSplitRoot: ip:0x%p rmp:0x%p", ip, rmp);
12391da177e4SLinus Torvalds
12401da177e4SLinus Torvalds /*
12411da177e4SLinus Torvalds * acquire a transaction lock on the new right page;
12421da177e4SLinus Torvalds *
12431da177e4SLinus Torvalds * action: new page;
12441da177e4SLinus Torvalds */
12451da177e4SLinus Torvalds BT_MARK_DIRTY(rmp, ip);
12461da177e4SLinus Torvalds
12471da177e4SLinus Torvalds rp = (xtpage_t *) rmp->data;
12481da177e4SLinus Torvalds rp->header.flag =
12491da177e4SLinus Torvalds (sp->header.flag & BT_LEAF) ? BT_LEAF : BT_INTERNAL;
12501da177e4SLinus Torvalds rp->header.self = *pxd;
12511da177e4SLinus Torvalds rp->header.nextindex = cpu_to_le16(XTENTRYSTART);
12521da177e4SLinus Torvalds rp->header.maxentry = cpu_to_le16(PSIZE >> L2XTSLOTSIZE);
12531da177e4SLinus Torvalds
12541da177e4SLinus Torvalds /* initialize sibling pointers */
12551da177e4SLinus Torvalds rp->header.next = 0;
12561da177e4SLinus Torvalds rp->header.prev = 0;
12571da177e4SLinus Torvalds
12581da177e4SLinus Torvalds /*
12591da177e4SLinus Torvalds * copy the in-line root page into new right page extent
12601da177e4SLinus Torvalds */
12611da177e4SLinus Torvalds nextindex = le16_to_cpu(sp->header.maxentry);
12621da177e4SLinus Torvalds memmove(&rp->xad[XTENTRYSTART], &sp->xad[XTENTRYSTART],
12631da177e4SLinus Torvalds (nextindex - XTENTRYSTART) << L2XTSLOTSIZE);
12641da177e4SLinus Torvalds
12651da177e4SLinus Torvalds /*
12661da177e4SLinus Torvalds * insert the new entry into the new right/child page
12671da177e4SLinus Torvalds * (skip index in the new right page will not change)
12681da177e4SLinus Torvalds */
12691da177e4SLinus Torvalds skip = split->index;
12701da177e4SLinus Torvalds /* if insert into middle, shift right remaining entries */
12711da177e4SLinus Torvalds if (skip != nextindex)
12721da177e4SLinus Torvalds memmove(&rp->xad[skip + 1], &rp->xad[skip],
12731da177e4SLinus Torvalds (nextindex - skip) * sizeof(xad_t));
12741da177e4SLinus Torvalds
12751da177e4SLinus Torvalds xad = &rp->xad[skip];
12761da177e4SLinus Torvalds XT_PUTENTRY(xad, split->flag, split->off, split->len, split->addr);
12771da177e4SLinus Torvalds
12781da177e4SLinus Torvalds /* update page header */
12791da177e4SLinus Torvalds rp->header.nextindex = cpu_to_le16(nextindex + 1);
12801da177e4SLinus Torvalds
12811da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
12821da177e4SLinus Torvalds tlck = txLock(tid, ip, rmp, tlckXTREE | tlckNEW);
12831da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
12841da177e4SLinus Torvalds xtlck->lwm.offset = XTENTRYSTART;
12851da177e4SLinus Torvalds xtlck->lwm.length = le16_to_cpu(rp->header.nextindex) -
12861da177e4SLinus Torvalds XTENTRYSTART;
12871da177e4SLinus Torvalds }
12881da177e4SLinus Torvalds
12891da177e4SLinus Torvalds /*
12901da177e4SLinus Torvalds * reset the root
12911da177e4SLinus Torvalds *
12921da177e4SLinus Torvalds * init root with the single entry for the new right page
12931da177e4SLinus Torvalds * set the 1st entry offset to 0, which force the left-most key
12941da177e4SLinus Torvalds * at any level of the tree to be less than any search key.
12951da177e4SLinus Torvalds */
12961da177e4SLinus Torvalds /*
12971da177e4SLinus Torvalds * acquire a transaction lock on the root page (in-memory inode);
12981da177e4SLinus Torvalds *
12991da177e4SLinus Torvalds * action: root split;
13001da177e4SLinus Torvalds */
13011da177e4SLinus Torvalds BT_MARK_DIRTY(split->mp, ip);
13021da177e4SLinus Torvalds
13031da177e4SLinus Torvalds xad = &sp->xad[XTENTRYSTART];
13041da177e4SLinus Torvalds XT_PUTENTRY(xad, XAD_NEW, 0, JFS_SBI(ip->i_sb)->nbperpage, rbn);
13051da177e4SLinus Torvalds
13061da177e4SLinus Torvalds /* update page header of root */
13071da177e4SLinus Torvalds sp->header.flag &= ~BT_LEAF;
13081da177e4SLinus Torvalds sp->header.flag |= BT_INTERNAL;
13091da177e4SLinus Torvalds
13101da177e4SLinus Torvalds sp->header.nextindex = cpu_to_le16(XTENTRYSTART + 1);
13111da177e4SLinus Torvalds
13121da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
13131da177e4SLinus Torvalds tlck = txLock(tid, ip, split->mp, tlckXTREE | tlckGROW);
13141da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
13151da177e4SLinus Torvalds xtlck->lwm.offset = XTENTRYSTART;
13161da177e4SLinus Torvalds xtlck->lwm.length = 1;
13171da177e4SLinus Torvalds }
13181da177e4SLinus Torvalds
13191da177e4SLinus Torvalds *rmpp = rmp;
13201da177e4SLinus Torvalds
13211da177e4SLinus Torvalds jfs_info("xtSplitRoot: sp:0x%p rp:0x%p", sp, rp);
13221da177e4SLinus Torvalds return 0;
13231da177e4SLinus Torvalds }
13241da177e4SLinus Torvalds
13251da177e4SLinus Torvalds
13261da177e4SLinus Torvalds /*
13271da177e4SLinus Torvalds * xtExtend()
13281da177e4SLinus Torvalds *
13291da177e4SLinus Torvalds * function: extend in-place;
13301da177e4SLinus Torvalds *
13311da177e4SLinus Torvalds * note: existing extent may or may not have been committed.
13321da177e4SLinus Torvalds * caller is responsible for pager buffer cache update, and
13331da177e4SLinus Torvalds * working block allocation map update;
13341da177e4SLinus Torvalds * update pmap: alloc whole extended extent;
13351da177e4SLinus Torvalds */
xtExtend(tid_t tid,struct inode * ip,s64 xoff,s32 xlen,int flag)13361da177e4SLinus Torvalds int xtExtend(tid_t tid, /* transaction id */
13371da177e4SLinus Torvalds struct inode *ip, s64 xoff, /* delta extent offset */
13381da177e4SLinus Torvalds s32 xlen, /* delta extent length */
13391da177e4SLinus Torvalds int flag)
13401da177e4SLinus Torvalds {
13411da177e4SLinus Torvalds int rc = 0;
13421da177e4SLinus Torvalds int cmp;
13431da177e4SLinus Torvalds struct metapage *mp; /* meta-page buffer */
13441da177e4SLinus Torvalds xtpage_t *p; /* base B+-tree index page */
13451da177e4SLinus Torvalds s64 bn;
13461da177e4SLinus Torvalds int index, nextindex, len;
13471da177e4SLinus Torvalds struct btstack btstack; /* traverse stack */
13481da177e4SLinus Torvalds struct xtsplit split; /* split information */
13491da177e4SLinus Torvalds xad_t *xad;
13501da177e4SLinus Torvalds s64 xaddr;
13511da177e4SLinus Torvalds struct tlock *tlck;
13521da177e4SLinus Torvalds struct xtlock *xtlck = NULL;
13531da177e4SLinus Torvalds
13541da177e4SLinus Torvalds jfs_info("xtExtend: nxoff:0x%lx nxlen:0x%x", (ulong) xoff, xlen);
13551da177e4SLinus Torvalds
13561da177e4SLinus Torvalds /* there must exist extent to be extended */
13576628465eSDave Kleikamp if ((rc = xtSearch(ip, xoff - 1, NULL, &cmp, &btstack, XT_INSERT)))
13581da177e4SLinus Torvalds return rc;
13591da177e4SLinus Torvalds
13601da177e4SLinus Torvalds /* retrieve search result */
13611da177e4SLinus Torvalds XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
13621da177e4SLinus Torvalds
13631da177e4SLinus Torvalds if (cmp != 0) {
13641da177e4SLinus Torvalds XT_PUTPAGE(mp);
1365eb8630d7SJoe Perches jfs_error(ip->i_sb, "xtSearch did not find extent\n");
13661da177e4SLinus Torvalds return -EIO;
13671da177e4SLinus Torvalds }
13681da177e4SLinus Torvalds
13691da177e4SLinus Torvalds /* extension must be contiguous */
13701da177e4SLinus Torvalds xad = &p->xad[index];
13711da177e4SLinus Torvalds if ((offsetXAD(xad) + lengthXAD(xad)) != xoff) {
13721da177e4SLinus Torvalds XT_PUTPAGE(mp);
1373eb8630d7SJoe Perches jfs_error(ip->i_sb, "extension is not contiguous\n");
13741da177e4SLinus Torvalds return -EIO;
13751da177e4SLinus Torvalds }
13761da177e4SLinus Torvalds
13771da177e4SLinus Torvalds /*
13781da177e4SLinus Torvalds * acquire a transaction lock on the leaf page;
13791da177e4SLinus Torvalds *
13801da177e4SLinus Torvalds * action: xad insertion/extension;
13811da177e4SLinus Torvalds */
13821da177e4SLinus Torvalds BT_MARK_DIRTY(mp, ip);
13831da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
13841da177e4SLinus Torvalds tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
13851da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
13861da177e4SLinus Torvalds }
13871da177e4SLinus Torvalds
13881da177e4SLinus Torvalds /* extend will overflow extent ? */
13891da177e4SLinus Torvalds xlen = lengthXAD(xad) + xlen;
13901da177e4SLinus Torvalds if ((len = xlen - MAXXLEN) <= 0)
13911da177e4SLinus Torvalds goto extendOld;
13921da177e4SLinus Torvalds
13931da177e4SLinus Torvalds /*
13941da177e4SLinus Torvalds * extent overflow: insert entry for new extent
13951da177e4SLinus Torvalds */
13961da177e4SLinus Torvalds //insertNew:
13971da177e4SLinus Torvalds xoff = offsetXAD(xad) + MAXXLEN;
13981da177e4SLinus Torvalds xaddr = addressXAD(xad) + MAXXLEN;
13991da177e4SLinus Torvalds nextindex = le16_to_cpu(p->header.nextindex);
14001da177e4SLinus Torvalds
14011da177e4SLinus Torvalds /*
14021da177e4SLinus Torvalds * if the leaf page is full, insert the new entry and
14031da177e4SLinus Torvalds * propagate up the router entry for the new page from split
14041da177e4SLinus Torvalds *
14051da177e4SLinus Torvalds * The xtSplitUp() will insert the entry and unpin the leaf page.
14061da177e4SLinus Torvalds */
14071da177e4SLinus Torvalds if (nextindex == le16_to_cpu(p->header.maxentry)) {
14081da177e4SLinus Torvalds /* xtSpliUp() unpins leaf pages */
14091da177e4SLinus Torvalds split.mp = mp;
14101da177e4SLinus Torvalds split.index = index + 1;
14111da177e4SLinus Torvalds split.flag = XAD_NEW;
14121da177e4SLinus Torvalds split.off = xoff; /* split offset */
14131da177e4SLinus Torvalds split.len = len;
14141da177e4SLinus Torvalds split.addr = xaddr;
14151da177e4SLinus Torvalds split.pxdlist = NULL;
14161da177e4SLinus Torvalds if ((rc = xtSplitUp(tid, ip, &split, &btstack)))
14171da177e4SLinus Torvalds return rc;
14181da177e4SLinus Torvalds
14191da177e4SLinus Torvalds /* get back old page */
14201da177e4SLinus Torvalds XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
14211da177e4SLinus Torvalds if (rc)
14221da177e4SLinus Torvalds return rc;
14231da177e4SLinus Torvalds /*
14241da177e4SLinus Torvalds * if leaf root has been split, original root has been
14251da177e4SLinus Torvalds * copied to new child page, i.e., original entry now
14261da177e4SLinus Torvalds * resides on the new child page;
14271da177e4SLinus Torvalds */
14281da177e4SLinus Torvalds if (p->header.flag & BT_INTERNAL) {
14291da177e4SLinus Torvalds ASSERT(p->header.nextindex ==
14301da177e4SLinus Torvalds cpu_to_le16(XTENTRYSTART + 1));
14311da177e4SLinus Torvalds xad = &p->xad[XTENTRYSTART];
14321da177e4SLinus Torvalds bn = addressXAD(xad);
14331da177e4SLinus Torvalds XT_PUTPAGE(mp);
14341da177e4SLinus Torvalds
14351da177e4SLinus Torvalds /* get new child page */
14361da177e4SLinus Torvalds XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
14371da177e4SLinus Torvalds if (rc)
14381da177e4SLinus Torvalds return rc;
14391da177e4SLinus Torvalds
14401da177e4SLinus Torvalds BT_MARK_DIRTY(mp, ip);
14411da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
14421da177e4SLinus Torvalds tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW);
14431da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
14441da177e4SLinus Torvalds }
14451da177e4SLinus Torvalds }
14461da177e4SLinus Torvalds }
14471da177e4SLinus Torvalds /*
14481da177e4SLinus Torvalds * insert the new entry into the leaf page
14491da177e4SLinus Torvalds */
14501da177e4SLinus Torvalds else {
14511da177e4SLinus Torvalds /* insert the new entry: mark the entry NEW */
14521da177e4SLinus Torvalds xad = &p->xad[index + 1];
14531da177e4SLinus Torvalds XT_PUTENTRY(xad, XAD_NEW, xoff, len, xaddr);
14541da177e4SLinus Torvalds
14551da177e4SLinus Torvalds /* advance next available entry index */
145689145622SMarcin Slusarz le16_add_cpu(&p->header.nextindex, 1);
14571da177e4SLinus Torvalds }
14581da177e4SLinus Torvalds
14591da177e4SLinus Torvalds /* get back old entry */
14601da177e4SLinus Torvalds xad = &p->xad[index];
14611da177e4SLinus Torvalds xlen = MAXXLEN;
14621da177e4SLinus Torvalds
14631da177e4SLinus Torvalds /*
14641da177e4SLinus Torvalds * extend old extent
14651da177e4SLinus Torvalds */
14661da177e4SLinus Torvalds extendOld:
14671da177e4SLinus Torvalds XADlength(xad, xlen);
14681da177e4SLinus Torvalds if (!(xad->flag & XAD_NEW))
14691da177e4SLinus Torvalds xad->flag |= XAD_EXTENDED;
14701da177e4SLinus Torvalds
14711da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
14721da177e4SLinus Torvalds xtlck->lwm.offset =
14731da177e4SLinus Torvalds (xtlck->lwm.offset) ? min(index,
14741da177e4SLinus Torvalds (int)xtlck->lwm.offset) : index;
14751da177e4SLinus Torvalds xtlck->lwm.length =
14761da177e4SLinus Torvalds le16_to_cpu(p->header.nextindex) - xtlck->lwm.offset;
14771da177e4SLinus Torvalds }
14781da177e4SLinus Torvalds
14791da177e4SLinus Torvalds /* unpin the leaf page */
14801da177e4SLinus Torvalds XT_PUTPAGE(mp);
14811da177e4SLinus Torvalds
14821da177e4SLinus Torvalds return rc;
14831da177e4SLinus Torvalds }
14841da177e4SLinus Torvalds
14851da177e4SLinus Torvalds /*
14861da177e4SLinus Torvalds * xtUpdate()
14871da177e4SLinus Torvalds *
14881da177e4SLinus Torvalds * function: update XAD;
14891da177e4SLinus Torvalds *
14901da177e4SLinus Torvalds * update extent for allocated_but_not_recorded or
14911da177e4SLinus Torvalds * compressed extent;
14921da177e4SLinus Torvalds *
14931da177e4SLinus Torvalds * parameter:
14941da177e4SLinus Torvalds * nxad - new XAD;
14951da177e4SLinus Torvalds * logical extent of the specified XAD must be completely
14961da177e4SLinus Torvalds * contained by an existing XAD;
14971da177e4SLinus Torvalds */
xtUpdate(tid_t tid,struct inode * ip,xad_t * nxad)14981da177e4SLinus Torvalds int xtUpdate(tid_t tid, struct inode *ip, xad_t * nxad)
14991da177e4SLinus Torvalds { /* new XAD */
15001da177e4SLinus Torvalds int rc = 0;
15011da177e4SLinus Torvalds int cmp;
15021da177e4SLinus Torvalds struct metapage *mp; /* meta-page buffer */
15031da177e4SLinus Torvalds xtpage_t *p; /* base B+-tree index page */
15041da177e4SLinus Torvalds s64 bn;
15051da177e4SLinus Torvalds int index0, index, newindex, nextindex;
15061da177e4SLinus Torvalds struct btstack btstack; /* traverse stack */
15071da177e4SLinus Torvalds struct xtsplit split; /* split information */
15081da177e4SLinus Torvalds xad_t *xad, *lxad, *rxad;
15091da177e4SLinus Torvalds int xflag;
15101da177e4SLinus Torvalds s64 nxoff, xoff;
15111da177e4SLinus Torvalds int nxlen, xlen, lxlen, rxlen;
15121da177e4SLinus Torvalds s64 nxaddr, xaddr;
15131da177e4SLinus Torvalds struct tlock *tlck;
15141da177e4SLinus Torvalds struct xtlock *xtlck = NULL;
15151da177e4SLinus Torvalds int newpage = 0;
15161da177e4SLinus Torvalds
15171da177e4SLinus Torvalds /* there must exist extent to be tailgated */
15181da177e4SLinus Torvalds nxoff = offsetXAD(nxad);
15191da177e4SLinus Torvalds nxlen = lengthXAD(nxad);
15201da177e4SLinus Torvalds nxaddr = addressXAD(nxad);
15211da177e4SLinus Torvalds
15226628465eSDave Kleikamp if ((rc = xtSearch(ip, nxoff, NULL, &cmp, &btstack, XT_INSERT)))
15231da177e4SLinus Torvalds return rc;
15241da177e4SLinus Torvalds
15251da177e4SLinus Torvalds /* retrieve search result */
15261da177e4SLinus Torvalds XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0);
15271da177e4SLinus Torvalds
15281da177e4SLinus Torvalds if (cmp != 0) {
15291da177e4SLinus Torvalds XT_PUTPAGE(mp);
1530eb8630d7SJoe Perches jfs_error(ip->i_sb, "Could not find extent\n");
15311da177e4SLinus Torvalds return -EIO;
15321da177e4SLinus Torvalds }
15331da177e4SLinus Torvalds
15341da177e4SLinus Torvalds BT_MARK_DIRTY(mp, ip);
15351da177e4SLinus Torvalds /*
15361da177e4SLinus Torvalds * acquire tlock of the leaf page containing original entry
15371da177e4SLinus Torvalds */
15381da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
15391da177e4SLinus Torvalds tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
15401da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
15411da177e4SLinus Torvalds }
15421da177e4SLinus Torvalds
15431da177e4SLinus Torvalds xad = &p->xad[index0];
15441da177e4SLinus Torvalds xflag = xad->flag;
15451da177e4SLinus Torvalds xoff = offsetXAD(xad);
15461da177e4SLinus Torvalds xlen = lengthXAD(xad);
15471da177e4SLinus Torvalds xaddr = addressXAD(xad);
15481da177e4SLinus Torvalds
15491da177e4SLinus Torvalds /* nXAD must be completely contained within XAD */
15501da177e4SLinus Torvalds if ((xoff > nxoff) ||
15511da177e4SLinus Torvalds (nxoff + nxlen > xoff + xlen)) {
15521da177e4SLinus Torvalds XT_PUTPAGE(mp);
15531da177e4SLinus Torvalds jfs_error(ip->i_sb,
1554eb8630d7SJoe Perches "nXAD in not completely contained within XAD\n");
15551da177e4SLinus Torvalds return -EIO;
15561da177e4SLinus Torvalds }
15571da177e4SLinus Torvalds
15581da177e4SLinus Torvalds index = index0;
15591da177e4SLinus Torvalds newindex = index + 1;
15601da177e4SLinus Torvalds nextindex = le16_to_cpu(p->header.nextindex);
15611da177e4SLinus Torvalds
15621da177e4SLinus Torvalds if (xoff < nxoff)
15631da177e4SLinus Torvalds goto coalesceRight;
15641da177e4SLinus Torvalds
15651da177e4SLinus Torvalds /*
15661da177e4SLinus Torvalds * coalesce with left XAD
15671da177e4SLinus Torvalds */
15681da177e4SLinus Torvalds /* is XAD first entry of page ? */
15691da177e4SLinus Torvalds if (index == XTENTRYSTART)
15701da177e4SLinus Torvalds goto replace;
15711da177e4SLinus Torvalds
15721da177e4SLinus Torvalds /* is nXAD logically and physically contiguous with lXAD ? */
15731da177e4SLinus Torvalds lxad = &p->xad[index - 1];
15741da177e4SLinus Torvalds lxlen = lengthXAD(lxad);
15751da177e4SLinus Torvalds if (!(lxad->flag & XAD_NOTRECORDED) &&
15761da177e4SLinus Torvalds (nxoff == offsetXAD(lxad) + lxlen) &&
15771da177e4SLinus Torvalds (nxaddr == addressXAD(lxad) + lxlen) &&
15781da177e4SLinus Torvalds (lxlen + nxlen < MAXXLEN)) {
15791da177e4SLinus Torvalds /* extend right lXAD */
15801da177e4SLinus Torvalds index0 = index - 1;
15811da177e4SLinus Torvalds XADlength(lxad, lxlen + nxlen);
15821da177e4SLinus Torvalds
15831da177e4SLinus Torvalds /* If we just merged two extents together, need to make sure the
15841da177e4SLinus Torvalds * right extent gets logged. If the left one is marked XAD_NEW,
15851da177e4SLinus Torvalds * then we know it will be logged. Otherwise, mark as
15861da177e4SLinus Torvalds * XAD_EXTENDED
15871da177e4SLinus Torvalds */
15881da177e4SLinus Torvalds if (!(lxad->flag & XAD_NEW))
15891da177e4SLinus Torvalds lxad->flag |= XAD_EXTENDED;
15901da177e4SLinus Torvalds
15911da177e4SLinus Torvalds if (xlen > nxlen) {
15921da177e4SLinus Torvalds /* truncate XAD */
15931da177e4SLinus Torvalds XADoffset(xad, xoff + nxlen);
15941da177e4SLinus Torvalds XADlength(xad, xlen - nxlen);
15951da177e4SLinus Torvalds XADaddress(xad, xaddr + nxlen);
15961da177e4SLinus Torvalds goto out;
15971da177e4SLinus Torvalds } else { /* (xlen == nxlen) */
15981da177e4SLinus Torvalds
15991da177e4SLinus Torvalds /* remove XAD */
16001da177e4SLinus Torvalds if (index < nextindex - 1)
16011da177e4SLinus Torvalds memmove(&p->xad[index], &p->xad[index + 1],
16021da177e4SLinus Torvalds (nextindex - index -
16031da177e4SLinus Torvalds 1) << L2XTSLOTSIZE);
16041da177e4SLinus Torvalds
16051da177e4SLinus Torvalds p->header.nextindex =
16061da177e4SLinus Torvalds cpu_to_le16(le16_to_cpu(p->header.nextindex) -
16071da177e4SLinus Torvalds 1);
16081da177e4SLinus Torvalds
16091da177e4SLinus Torvalds index = index0;
16101da177e4SLinus Torvalds newindex = index + 1;
16111da177e4SLinus Torvalds nextindex = le16_to_cpu(p->header.nextindex);
16121da177e4SLinus Torvalds xoff = nxoff = offsetXAD(lxad);
16131da177e4SLinus Torvalds xlen = nxlen = lxlen + nxlen;
16141da177e4SLinus Torvalds xaddr = nxaddr = addressXAD(lxad);
16151da177e4SLinus Torvalds goto coalesceRight;
16161da177e4SLinus Torvalds }
16171da177e4SLinus Torvalds }
16181da177e4SLinus Torvalds
16191da177e4SLinus Torvalds /*
16201da177e4SLinus Torvalds * replace XAD with nXAD
16211da177e4SLinus Torvalds */
16221da177e4SLinus Torvalds replace: /* (nxoff == xoff) */
16231da177e4SLinus Torvalds if (nxlen == xlen) {
16241da177e4SLinus Torvalds /* replace XAD with nXAD:recorded */
16251da177e4SLinus Torvalds *xad = *nxad;
16261da177e4SLinus Torvalds xad->flag = xflag & ~XAD_NOTRECORDED;
16271da177e4SLinus Torvalds
16281da177e4SLinus Torvalds goto coalesceRight;
16291da177e4SLinus Torvalds } else /* (nxlen < xlen) */
16301da177e4SLinus Torvalds goto updateLeft;
16311da177e4SLinus Torvalds
16321da177e4SLinus Torvalds /*
16331da177e4SLinus Torvalds * coalesce with right XAD
16341da177e4SLinus Torvalds */
16351da177e4SLinus Torvalds coalesceRight: /* (xoff <= nxoff) */
16361da177e4SLinus Torvalds /* is XAD last entry of page ? */
16371da177e4SLinus Torvalds if (newindex == nextindex) {
16381da177e4SLinus Torvalds if (xoff == nxoff)
16391da177e4SLinus Torvalds goto out;
16401da177e4SLinus Torvalds goto updateRight;
16411da177e4SLinus Torvalds }
16421da177e4SLinus Torvalds
16431da177e4SLinus Torvalds /* is nXAD logically and physically contiguous with rXAD ? */
16441da177e4SLinus Torvalds rxad = &p->xad[index + 1];
16451da177e4SLinus Torvalds rxlen = lengthXAD(rxad);
16461da177e4SLinus Torvalds if (!(rxad->flag & XAD_NOTRECORDED) &&
16471da177e4SLinus Torvalds (nxoff + nxlen == offsetXAD(rxad)) &&
16481da177e4SLinus Torvalds (nxaddr + nxlen == addressXAD(rxad)) &&
16491da177e4SLinus Torvalds (rxlen + nxlen < MAXXLEN)) {
16501da177e4SLinus Torvalds /* extend left rXAD */
16511da177e4SLinus Torvalds XADoffset(rxad, nxoff);
16521da177e4SLinus Torvalds XADlength(rxad, rxlen + nxlen);
16531da177e4SLinus Torvalds XADaddress(rxad, nxaddr);
16541da177e4SLinus Torvalds
16551da177e4SLinus Torvalds /* If we just merged two extents together, need to make sure
16561da177e4SLinus Torvalds * the left extent gets logged. If the right one is marked
16571da177e4SLinus Torvalds * XAD_NEW, then we know it will be logged. Otherwise, mark as
16581da177e4SLinus Torvalds * XAD_EXTENDED
16591da177e4SLinus Torvalds */
16601da177e4SLinus Torvalds if (!(rxad->flag & XAD_NEW))
16611da177e4SLinus Torvalds rxad->flag |= XAD_EXTENDED;
16621da177e4SLinus Torvalds
16631da177e4SLinus Torvalds if (xlen > nxlen)
16641da177e4SLinus Torvalds /* truncate XAD */
16651da177e4SLinus Torvalds XADlength(xad, xlen - nxlen);
16661da177e4SLinus Torvalds else { /* (xlen == nxlen) */
16671da177e4SLinus Torvalds
16681da177e4SLinus Torvalds /* remove XAD */
16691da177e4SLinus Torvalds memmove(&p->xad[index], &p->xad[index + 1],
16701da177e4SLinus Torvalds (nextindex - index - 1) << L2XTSLOTSIZE);
16711da177e4SLinus Torvalds
16721da177e4SLinus Torvalds p->header.nextindex =
16731da177e4SLinus Torvalds cpu_to_le16(le16_to_cpu(p->header.nextindex) -
16741da177e4SLinus Torvalds 1);
16751da177e4SLinus Torvalds }
16761da177e4SLinus Torvalds
16771da177e4SLinus Torvalds goto out;
16781da177e4SLinus Torvalds } else if (xoff == nxoff)
16791da177e4SLinus Torvalds goto out;
16801da177e4SLinus Torvalds
16811da177e4SLinus Torvalds if (xoff >= nxoff) {
16821da177e4SLinus Torvalds XT_PUTPAGE(mp);
1683eb8630d7SJoe Perches jfs_error(ip->i_sb, "xoff >= nxoff\n");
16841da177e4SLinus Torvalds return -EIO;
16851da177e4SLinus Torvalds }
16861da177e4SLinus Torvalds
16871da177e4SLinus Torvalds /*
16881da177e4SLinus Torvalds * split XAD into (lXAD, nXAD):
16891da177e4SLinus Torvalds *
16901da177e4SLinus Torvalds * |---nXAD--->
16911da177e4SLinus Torvalds * --|----------XAD----------|--
16921da177e4SLinus Torvalds * |-lXAD-|
16931da177e4SLinus Torvalds */
16941da177e4SLinus Torvalds updateRight: /* (xoff < nxoff) */
16951da177e4SLinus Torvalds /* truncate old XAD as lXAD:not_recorded */
16961da177e4SLinus Torvalds xad = &p->xad[index];
16971da177e4SLinus Torvalds XADlength(xad, nxoff - xoff);
16981da177e4SLinus Torvalds
16991da177e4SLinus Torvalds /* insert nXAD:recorded */
17001da177e4SLinus Torvalds if (nextindex == le16_to_cpu(p->header.maxentry)) {
17011da177e4SLinus Torvalds
17021da177e4SLinus Torvalds /* xtSpliUp() unpins leaf pages */
17031da177e4SLinus Torvalds split.mp = mp;
17041da177e4SLinus Torvalds split.index = newindex;
17051da177e4SLinus Torvalds split.flag = xflag & ~XAD_NOTRECORDED;
17061da177e4SLinus Torvalds split.off = nxoff;
17071da177e4SLinus Torvalds split.len = nxlen;
17081da177e4SLinus Torvalds split.addr = nxaddr;
17091da177e4SLinus Torvalds split.pxdlist = NULL;
17101da177e4SLinus Torvalds if ((rc = xtSplitUp(tid, ip, &split, &btstack)))
17111da177e4SLinus Torvalds return rc;
17121da177e4SLinus Torvalds
17131da177e4SLinus Torvalds /* get back old page */
17141da177e4SLinus Torvalds XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
17151da177e4SLinus Torvalds if (rc)
17161da177e4SLinus Torvalds return rc;
17171da177e4SLinus Torvalds /*
17181da177e4SLinus Torvalds * if leaf root has been split, original root has been
17191da177e4SLinus Torvalds * copied to new child page, i.e., original entry now
17201da177e4SLinus Torvalds * resides on the new child page;
17211da177e4SLinus Torvalds */
17221da177e4SLinus Torvalds if (p->header.flag & BT_INTERNAL) {
17231da177e4SLinus Torvalds ASSERT(p->header.nextindex ==
17241da177e4SLinus Torvalds cpu_to_le16(XTENTRYSTART + 1));
17251da177e4SLinus Torvalds xad = &p->xad[XTENTRYSTART];
17261da177e4SLinus Torvalds bn = addressXAD(xad);
17271da177e4SLinus Torvalds XT_PUTPAGE(mp);
17281da177e4SLinus Torvalds
17291da177e4SLinus Torvalds /* get new child page */
17301da177e4SLinus Torvalds XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
17311da177e4SLinus Torvalds if (rc)
17321da177e4SLinus Torvalds return rc;
17331da177e4SLinus Torvalds
17341da177e4SLinus Torvalds BT_MARK_DIRTY(mp, ip);
17351da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
17361da177e4SLinus Torvalds tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW);
17371da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
17381da177e4SLinus Torvalds }
17391da177e4SLinus Torvalds } else {
17401da177e4SLinus Torvalds /* is nXAD on new page ? */
17411da177e4SLinus Torvalds if (newindex >
17421da177e4SLinus Torvalds (le16_to_cpu(p->header.maxentry) >> 1)) {
17431da177e4SLinus Torvalds newindex =
17441da177e4SLinus Torvalds newindex -
17451da177e4SLinus Torvalds le16_to_cpu(p->header.nextindex) +
17461da177e4SLinus Torvalds XTENTRYSTART;
17471da177e4SLinus Torvalds newpage = 1;
17481da177e4SLinus Torvalds }
17491da177e4SLinus Torvalds }
17501da177e4SLinus Torvalds } else {
17511da177e4SLinus Torvalds /* if insert into middle, shift right remaining entries */
17521da177e4SLinus Torvalds if (newindex < nextindex)
17531da177e4SLinus Torvalds memmove(&p->xad[newindex + 1], &p->xad[newindex],
17541da177e4SLinus Torvalds (nextindex - newindex) << L2XTSLOTSIZE);
17551da177e4SLinus Torvalds
17561da177e4SLinus Torvalds /* insert the entry */
17571da177e4SLinus Torvalds xad = &p->xad[newindex];
17581da177e4SLinus Torvalds *xad = *nxad;
17591da177e4SLinus Torvalds xad->flag = xflag & ~XAD_NOTRECORDED;
17601da177e4SLinus Torvalds
17611da177e4SLinus Torvalds /* advance next available entry index. */
17621da177e4SLinus Torvalds p->header.nextindex =
17631da177e4SLinus Torvalds cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
17641da177e4SLinus Torvalds }
17651da177e4SLinus Torvalds
17661da177e4SLinus Torvalds /*
17671da177e4SLinus Torvalds * does nXAD force 3-way split ?
17681da177e4SLinus Torvalds *
17691da177e4SLinus Torvalds * |---nXAD--->|
17701da177e4SLinus Torvalds * --|----------XAD-------------|--
17711da177e4SLinus Torvalds * |-lXAD-| |-rXAD -|
17721da177e4SLinus Torvalds */
17731da177e4SLinus Torvalds if (nxoff + nxlen == xoff + xlen)
17741da177e4SLinus Torvalds goto out;
17751da177e4SLinus Torvalds
17761da177e4SLinus Torvalds /* reorient nXAD as XAD for further split XAD into (nXAD, rXAD) */
17771da177e4SLinus Torvalds if (newpage) {
17781da177e4SLinus Torvalds /* close out old page */
17791da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
17801da177e4SLinus Torvalds xtlck->lwm.offset = (xtlck->lwm.offset) ?
17811da177e4SLinus Torvalds min(index0, (int)xtlck->lwm.offset) : index0;
17821da177e4SLinus Torvalds xtlck->lwm.length =
17831da177e4SLinus Torvalds le16_to_cpu(p->header.nextindex) -
17841da177e4SLinus Torvalds xtlck->lwm.offset;
17851da177e4SLinus Torvalds }
17861da177e4SLinus Torvalds
17871da177e4SLinus Torvalds bn = le64_to_cpu(p->header.next);
17881da177e4SLinus Torvalds XT_PUTPAGE(mp);
17891da177e4SLinus Torvalds
17901da177e4SLinus Torvalds /* get new right page */
17911da177e4SLinus Torvalds XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
17921da177e4SLinus Torvalds if (rc)
17931da177e4SLinus Torvalds return rc;
17941da177e4SLinus Torvalds
17951da177e4SLinus Torvalds BT_MARK_DIRTY(mp, ip);
17961da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
17971da177e4SLinus Torvalds tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
17981da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
17991da177e4SLinus Torvalds }
18001da177e4SLinus Torvalds
18011da177e4SLinus Torvalds index0 = index = newindex;
18021da177e4SLinus Torvalds } else
18031da177e4SLinus Torvalds index++;
18041da177e4SLinus Torvalds
18051da177e4SLinus Torvalds newindex = index + 1;
18061da177e4SLinus Torvalds nextindex = le16_to_cpu(p->header.nextindex);
18071da177e4SLinus Torvalds xlen = xlen - (nxoff - xoff);
18081da177e4SLinus Torvalds xoff = nxoff;
18091da177e4SLinus Torvalds xaddr = nxaddr;
18101da177e4SLinus Torvalds
18111da177e4SLinus Torvalds /* recompute split pages */
18121da177e4SLinus Torvalds if (nextindex == le16_to_cpu(p->header.maxentry)) {
18131da177e4SLinus Torvalds XT_PUTPAGE(mp);
18141da177e4SLinus Torvalds
18156628465eSDave Kleikamp if ((rc = xtSearch(ip, nxoff, NULL, &cmp, &btstack, XT_INSERT)))
18161da177e4SLinus Torvalds return rc;
18171da177e4SLinus Torvalds
18181da177e4SLinus Torvalds /* retrieve search result */
18191da177e4SLinus Torvalds XT_GETSEARCH(ip, btstack.top, bn, mp, p, index0);
18201da177e4SLinus Torvalds
18211da177e4SLinus Torvalds if (cmp != 0) {
18221da177e4SLinus Torvalds XT_PUTPAGE(mp);
1823eb8630d7SJoe Perches jfs_error(ip->i_sb, "xtSearch failed\n");
18241da177e4SLinus Torvalds return -EIO;
18251da177e4SLinus Torvalds }
18261da177e4SLinus Torvalds
18271da177e4SLinus Torvalds if (index0 != index) {
18281da177e4SLinus Torvalds XT_PUTPAGE(mp);
1829eb8630d7SJoe Perches jfs_error(ip->i_sb, "unexpected value of index\n");
18301da177e4SLinus Torvalds return -EIO;
18311da177e4SLinus Torvalds }
18321da177e4SLinus Torvalds }
18331da177e4SLinus Torvalds
18341da177e4SLinus Torvalds /*
18351da177e4SLinus Torvalds * split XAD into (nXAD, rXAD)
18361da177e4SLinus Torvalds *
18371da177e4SLinus Torvalds * ---nXAD---|
18381da177e4SLinus Torvalds * --|----------XAD----------|--
18391da177e4SLinus Torvalds * |-rXAD-|
18401da177e4SLinus Torvalds */
18411da177e4SLinus Torvalds updateLeft: /* (nxoff == xoff) && (nxlen < xlen) */
18421da177e4SLinus Torvalds /* update old XAD with nXAD:recorded */
18431da177e4SLinus Torvalds xad = &p->xad[index];
18441da177e4SLinus Torvalds *xad = *nxad;
18451da177e4SLinus Torvalds xad->flag = xflag & ~XAD_NOTRECORDED;
18461da177e4SLinus Torvalds
18471da177e4SLinus Torvalds /* insert rXAD:not_recorded */
18481da177e4SLinus Torvalds xoff = xoff + nxlen;
18491da177e4SLinus Torvalds xlen = xlen - nxlen;
18501da177e4SLinus Torvalds xaddr = xaddr + nxlen;
18511da177e4SLinus Torvalds if (nextindex == le16_to_cpu(p->header.maxentry)) {
18521da177e4SLinus Torvalds /*
18531da177e4SLinus Torvalds printf("xtUpdate.updateLeft.split p:0x%p\n", p);
18541da177e4SLinus Torvalds */
18551da177e4SLinus Torvalds /* xtSpliUp() unpins leaf pages */
18561da177e4SLinus Torvalds split.mp = mp;
18571da177e4SLinus Torvalds split.index = newindex;
18581da177e4SLinus Torvalds split.flag = xflag;
18591da177e4SLinus Torvalds split.off = xoff;
18601da177e4SLinus Torvalds split.len = xlen;
18611da177e4SLinus Torvalds split.addr = xaddr;
18621da177e4SLinus Torvalds split.pxdlist = NULL;
18631da177e4SLinus Torvalds if ((rc = xtSplitUp(tid, ip, &split, &btstack)))
18641da177e4SLinus Torvalds return rc;
18651da177e4SLinus Torvalds
18661da177e4SLinus Torvalds /* get back old page */
18671da177e4SLinus Torvalds XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
18681da177e4SLinus Torvalds if (rc)
18691da177e4SLinus Torvalds return rc;
18701da177e4SLinus Torvalds
18711da177e4SLinus Torvalds /*
18721da177e4SLinus Torvalds * if leaf root has been split, original root has been
18731da177e4SLinus Torvalds * copied to new child page, i.e., original entry now
18741da177e4SLinus Torvalds * resides on the new child page;
18751da177e4SLinus Torvalds */
18761da177e4SLinus Torvalds if (p->header.flag & BT_INTERNAL) {
18771da177e4SLinus Torvalds ASSERT(p->header.nextindex ==
18781da177e4SLinus Torvalds cpu_to_le16(XTENTRYSTART + 1));
18791da177e4SLinus Torvalds xad = &p->xad[XTENTRYSTART];
18801da177e4SLinus Torvalds bn = addressXAD(xad);
18811da177e4SLinus Torvalds XT_PUTPAGE(mp);
18821da177e4SLinus Torvalds
18831da177e4SLinus Torvalds /* get new child page */
18841da177e4SLinus Torvalds XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
18851da177e4SLinus Torvalds if (rc)
18861da177e4SLinus Torvalds return rc;
18871da177e4SLinus Torvalds
18881da177e4SLinus Torvalds BT_MARK_DIRTY(mp, ip);
18891da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
18901da177e4SLinus Torvalds tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW);
18911da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
18921da177e4SLinus Torvalds }
18931da177e4SLinus Torvalds }
18941da177e4SLinus Torvalds } else {
18951da177e4SLinus Torvalds /* if insert into middle, shift right remaining entries */
18961da177e4SLinus Torvalds if (newindex < nextindex)
18971da177e4SLinus Torvalds memmove(&p->xad[newindex + 1], &p->xad[newindex],
18981da177e4SLinus Torvalds (nextindex - newindex) << L2XTSLOTSIZE);
18991da177e4SLinus Torvalds
19001da177e4SLinus Torvalds /* insert the entry */
19011da177e4SLinus Torvalds xad = &p->xad[newindex];
19021da177e4SLinus Torvalds XT_PUTENTRY(xad, xflag, xoff, xlen, xaddr);
19031da177e4SLinus Torvalds
19041da177e4SLinus Torvalds /* advance next available entry index. */
19051da177e4SLinus Torvalds p->header.nextindex =
19061da177e4SLinus Torvalds cpu_to_le16(le16_to_cpu(p->header.nextindex) + 1);
19071da177e4SLinus Torvalds }
19081da177e4SLinus Torvalds
19091da177e4SLinus Torvalds out:
19101da177e4SLinus Torvalds if (!test_cflag(COMMIT_Nolink, ip)) {
19111da177e4SLinus Torvalds xtlck->lwm.offset = (xtlck->lwm.offset) ?
19121da177e4SLinus Torvalds min(index0, (int)xtlck->lwm.offset) : index0;
19131da177e4SLinus Torvalds xtlck->lwm.length = le16_to_cpu(p->header.nextindex) -
19141da177e4SLinus Torvalds xtlck->lwm.offset;
19151da177e4SLinus Torvalds }
19161da177e4SLinus Torvalds
19171da177e4SLinus Torvalds /* unpin the leaf page */
19181da177e4SLinus Torvalds XT_PUTPAGE(mp);
19191da177e4SLinus Torvalds
19201da177e4SLinus Torvalds return rc;
19211da177e4SLinus Torvalds }
19221da177e4SLinus Torvalds
19231da177e4SLinus Torvalds
19241da177e4SLinus Torvalds /*
19251da177e4SLinus Torvalds * xtAppend()
19261da177e4SLinus Torvalds *
19271da177e4SLinus Torvalds * function: grow in append mode from contiguous region specified ;
19281da177e4SLinus Torvalds *
19291da177e4SLinus Torvalds * parameter:
19301da177e4SLinus Torvalds * tid - transaction id;
19311da177e4SLinus Torvalds * ip - file object;
19321da177e4SLinus Torvalds * xflag - extent flag:
19331da177e4SLinus Torvalds * xoff - extent offset;
19341da177e4SLinus Torvalds * maxblocks - max extent length;
19351da177e4SLinus Torvalds * xlen - extent length (in/out);
19361da177e4SLinus Torvalds * xaddrp - extent address pointer (in/out):
19371da177e4SLinus Torvalds * flag -
19381da177e4SLinus Torvalds *
19391da177e4SLinus Torvalds * return:
19401da177e4SLinus Torvalds */
xtAppend(tid_t tid,struct inode * ip,int xflag,s64 xoff,s32 maxblocks,s32 * xlenp,s64 * xaddrp,int flag)19411da177e4SLinus Torvalds int xtAppend(tid_t tid, /* transaction id */
19421da177e4SLinus Torvalds struct inode *ip, int xflag, s64 xoff, s32 maxblocks,
19431da177e4SLinus Torvalds s32 * xlenp, /* (in/out) */
19441da177e4SLinus Torvalds s64 * xaddrp, /* (in/out) */
19451da177e4SLinus Torvalds int flag)
19461da177e4SLinus Torvalds {
19471da177e4SLinus Torvalds int rc = 0;
19481da177e4SLinus Torvalds struct metapage *mp; /* meta-page buffer */
19491da177e4SLinus Torvalds xtpage_t *p; /* base B+-tree index page */
19501da177e4SLinus Torvalds s64 bn, xaddr;
19511da177e4SLinus Torvalds int index, nextindex;
19521da177e4SLinus Torvalds struct btstack btstack; /* traverse stack */
19531da177e4SLinus Torvalds struct xtsplit split; /* split information */
19541da177e4SLinus Torvalds xad_t *xad;
19551da177e4SLinus Torvalds int cmp;
19561da177e4SLinus Torvalds struct tlock *tlck;
19571da177e4SLinus Torvalds struct xtlock *xtlck;
19581da177e4SLinus Torvalds int nsplit, nblocks, xlen;
19591da177e4SLinus Torvalds struct pxdlist pxdlist;
19601da177e4SLinus Torvalds pxd_t *pxd;
19616628465eSDave Kleikamp s64 next;
19621da177e4SLinus Torvalds
19631da177e4SLinus Torvalds xaddr = *xaddrp;
19641da177e4SLinus Torvalds xlen = *xlenp;
19651da177e4SLinus Torvalds jfs_info("xtAppend: xoff:0x%lx maxblocks:%d xlen:%d xaddr:0x%lx",
19661da177e4SLinus Torvalds (ulong) xoff, maxblocks, xlen, (ulong) xaddr);
19671da177e4SLinus Torvalds
19681da177e4SLinus Torvalds /*
19691da177e4SLinus Torvalds * search for the entry location at which to insert:
19701da177e4SLinus Torvalds *
19711da177e4SLinus Torvalds * xtFastSearch() and xtSearch() both returns (leaf page
19721da177e4SLinus Torvalds * pinned, index at which to insert).
19731da177e4SLinus Torvalds * n.b. xtSearch() may return index of maxentry of
19741da177e4SLinus Torvalds * the full page.
19751da177e4SLinus Torvalds */
19766628465eSDave Kleikamp if ((rc = xtSearch(ip, xoff, &next, &cmp, &btstack, XT_INSERT)))
19771da177e4SLinus Torvalds return rc;
19781da177e4SLinus Torvalds
19791da177e4SLinus Torvalds /* retrieve search result */
19801da177e4SLinus Torvalds XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
19811da177e4SLinus Torvalds
19821da177e4SLinus Torvalds if (cmp == 0) {
19831da177e4SLinus Torvalds rc = -EEXIST;
19841da177e4SLinus Torvalds goto out;
19851da177e4SLinus Torvalds }
19866628465eSDave Kleikamp
19876628465eSDave Kleikamp if (next)
19886628465eSDave Kleikamp xlen = min(xlen, (int)(next - xoff));
19891da177e4SLinus Torvalds //insert:
19901da177e4SLinus Torvalds /*
19911da177e4SLinus Torvalds * insert entry for new extent
19921da177e4SLinus Torvalds */
19931da177e4SLinus Torvalds xflag |= XAD_NEW;
19941da177e4SLinus Torvalds
19951da177e4SLinus Torvalds /*
19961da177e4SLinus Torvalds * if the leaf page is full, split the page and
19971da177e4SLinus Torvalds * propagate up the router entry for the new page from split
19981da177e4SLinus Torvalds *
19991da177e4SLinus Torvalds * The xtSplitUp() will insert the entry and unpin the leaf page.
20001da177e4SLinus Torvalds */
20011da177e4SLinus Torvalds nextindex = le16_to_cpu(p->header.nextindex);
20021da177e4SLinus Torvalds if (nextindex < le16_to_cpu(p->header.maxentry))
20031da177e4SLinus Torvalds goto insertLeaf;
20041da177e4SLinus Torvalds
20051da177e4SLinus Torvalds /*
20061da177e4SLinus Torvalds * allocate new index blocks to cover index page split(s)
20071da177e4SLinus Torvalds */
20081da177e4SLinus Torvalds nsplit = btstack.nsplit;
20091da177e4SLinus Torvalds split.pxdlist = &pxdlist;
20101da177e4SLinus Torvalds pxdlist.maxnpxd = pxdlist.npxd = 0;
20111da177e4SLinus Torvalds pxd = &pxdlist.pxd[0];
20121da177e4SLinus Torvalds nblocks = JFS_SBI(ip->i_sb)->nbperpage;
20131da177e4SLinus Torvalds for (; nsplit > 0; nsplit--, pxd++, xaddr += nblocks, maxblocks -= nblocks) {
20141da177e4SLinus Torvalds if ((rc = dbAllocBottomUp(ip, xaddr, (s64) nblocks)) == 0) {
20151da177e4SLinus Torvalds PXDaddress(pxd, xaddr);
20161da177e4SLinus Torvalds PXDlength(pxd, nblocks);
20171da177e4SLinus Torvalds
20181da177e4SLinus Torvalds pxdlist.maxnpxd++;
20191da177e4SLinus Torvalds
20201da177e4SLinus Torvalds continue;
20211da177e4SLinus Torvalds }
20221da177e4SLinus Torvalds
20231da177e4SLinus Torvalds /* undo allocation */
20241da177e4SLinus Torvalds
20251da177e4SLinus Torvalds goto out;
20261da177e4SLinus Torvalds }
20271da177e4SLinus Torvalds
20281da177e4SLinus Torvalds xlen = min(xlen, maxblocks);
20291da177e4SLinus Torvalds
20301da177e4SLinus Torvalds /*
20311da177e4SLinus Torvalds * allocate data extent requested
20321da177e4SLinus Torvalds */
20331da177e4SLinus Torvalds if ((rc = dbAllocBottomUp(ip, xaddr, (s64) xlen)))
20341da177e4SLinus Torvalds goto out;
20351da177e4SLinus Torvalds
20361da177e4SLinus Torvalds split.mp = mp;
20371da177e4SLinus Torvalds split.index = index;
20381da177e4SLinus Torvalds split.flag = xflag;
20391da177e4SLinus Torvalds split.off = xoff;
20401da177e4SLinus Torvalds split.len = xlen;
20411da177e4SLinus Torvalds split.addr = xaddr;
20421da177e4SLinus Torvalds if ((rc = xtSplitUp(tid, ip, &split, &btstack))) {
20431da177e4SLinus Torvalds /* undo data extent allocation */
20441da177e4SLinus Torvalds dbFree(ip, *xaddrp, (s64) * xlenp);
20451da177e4SLinus Torvalds
20461da177e4SLinus Torvalds return rc;
20471da177e4SLinus Torvalds }
20481da177e4SLinus Torvalds
20491da177e4SLinus Torvalds *xaddrp = xaddr;
20501da177e4SLinus Torvalds *xlenp = xlen;
20511da177e4SLinus Torvalds return 0;
20521da177e4SLinus Torvalds
20531da177e4SLinus Torvalds /*
20541da177e4SLinus Torvalds * insert the new entry into the leaf page
20551da177e4SLinus Torvalds */
20561da177e4SLinus Torvalds insertLeaf:
20571da177e4SLinus Torvalds /*
20581da177e4SLinus Torvalds * allocate data extent requested
20591da177e4SLinus Torvalds */
20601da177e4SLinus Torvalds if ((rc = dbAllocBottomUp(ip, xaddr, (s64) xlen)))
20611da177e4SLinus Torvalds goto out;
20621da177e4SLinus Torvalds
20631da177e4SLinus Torvalds BT_MARK_DIRTY(mp, ip);
20641da177e4SLinus Torvalds /*
20651da177e4SLinus Torvalds * acquire a transaction lock on the leaf page;
20661da177e4SLinus Torvalds *
20671da177e4SLinus Torvalds * action: xad insertion/extension;
20681da177e4SLinus Torvalds */
20691da177e4SLinus Torvalds tlck = txLock(tid, ip, mp, tlckXTREE | tlckGROW);
20701da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
20711da177e4SLinus Torvalds
20721da177e4SLinus Torvalds /* insert the new entry: mark the entry NEW */
20731da177e4SLinus Torvalds xad = &p->xad[index];
20741da177e4SLinus Torvalds XT_PUTENTRY(xad, xflag, xoff, xlen, xaddr);
20751da177e4SLinus Torvalds
20761da177e4SLinus Torvalds /* advance next available entry index */
207789145622SMarcin Slusarz le16_add_cpu(&p->header.nextindex, 1);
20781da177e4SLinus Torvalds
20791da177e4SLinus Torvalds xtlck->lwm.offset =
20801da177e4SLinus Torvalds (xtlck->lwm.offset) ? min(index,(int) xtlck->lwm.offset) : index;
20811da177e4SLinus Torvalds xtlck->lwm.length = le16_to_cpu(p->header.nextindex) -
20821da177e4SLinus Torvalds xtlck->lwm.offset;
20831da177e4SLinus Torvalds
20841da177e4SLinus Torvalds *xaddrp = xaddr;
20851da177e4SLinus Torvalds *xlenp = xlen;
20861da177e4SLinus Torvalds
20871da177e4SLinus Torvalds out:
20881da177e4SLinus Torvalds /* unpin the leaf page */
20891da177e4SLinus Torvalds XT_PUTPAGE(mp);
20901da177e4SLinus Torvalds
20911da177e4SLinus Torvalds return rc;
20921da177e4SLinus Torvalds }
20931da177e4SLinus Torvalds
20941da177e4SLinus Torvalds /*
20951da177e4SLinus Torvalds * xtInitRoot()
20961da177e4SLinus Torvalds *
20971da177e4SLinus Torvalds * initialize file root (inline in inode)
20981da177e4SLinus Torvalds */
xtInitRoot(tid_t tid,struct inode * ip)20991da177e4SLinus Torvalds void xtInitRoot(tid_t tid, struct inode *ip)
21001da177e4SLinus Torvalds {
2101*2ff51719SDave Kleikamp xtroot_t *p;
21021da177e4SLinus Torvalds
21031da177e4SLinus Torvalds /*
21041da177e4SLinus Torvalds * acquire a transaction lock on the root
21051da177e4SLinus Torvalds *
21061da177e4SLinus Torvalds * action:
21071da177e4SLinus Torvalds */
21081da177e4SLinus Torvalds txLock(tid, ip, (struct metapage *) &JFS_IP(ip)->bxflag,
21091da177e4SLinus Torvalds tlckXTREE | tlckNEW);
21101da177e4SLinus Torvalds p = &JFS_IP(ip)->i_xtroot;
21111da177e4SLinus Torvalds
21121da177e4SLinus Torvalds p->header.flag = DXD_INDEX | BT_ROOT | BT_LEAF;
21131da177e4SLinus Torvalds p->header.nextindex = cpu_to_le16(XTENTRYSTART);
21141da177e4SLinus Torvalds
21151da177e4SLinus Torvalds if (S_ISDIR(ip->i_mode))
21161da177e4SLinus Torvalds p->header.maxentry = cpu_to_le16(XTROOTINITSLOT_DIR);
21171da177e4SLinus Torvalds else {
21181da177e4SLinus Torvalds p->header.maxentry = cpu_to_le16(XTROOTINITSLOT);
21191da177e4SLinus Torvalds ip->i_size = 0;
21201da177e4SLinus Torvalds }
21211da177e4SLinus Torvalds
21221da177e4SLinus Torvalds
21231da177e4SLinus Torvalds return;
21241da177e4SLinus Torvalds }
21251da177e4SLinus Torvalds
21261da177e4SLinus Torvalds
21271da177e4SLinus Torvalds /*
21281da177e4SLinus Torvalds * We can run into a deadlock truncating a file with a large number of
21291da177e4SLinus Torvalds * xtree pages (large fragmented file). A robust fix would entail a
21301da177e4SLinus Torvalds * reservation system where we would reserve a number of metadata pages
21311da177e4SLinus Torvalds * and tlocks which we would be guaranteed without a deadlock. Without
21321da177e4SLinus Torvalds * this, a partial fix is to limit number of metadata pages we will lock
21331da177e4SLinus Torvalds * in a single transaction. Currently we will truncate the file so that
21341da177e4SLinus Torvalds * no more than 50 leaf pages will be locked. The caller of xtTruncate
21351da177e4SLinus Torvalds * will be responsible for ensuring that the current transaction gets
21361da177e4SLinus Torvalds * committed, and that subsequent transactions are created to truncate
21371da177e4SLinus Torvalds * the file further if needed.
21381da177e4SLinus Torvalds */
21391da177e4SLinus Torvalds #define MAX_TRUNCATE_LEAVES 50
21401da177e4SLinus Torvalds
21411da177e4SLinus Torvalds /*
21421da177e4SLinus Torvalds * xtTruncate()
21431da177e4SLinus Torvalds *
21441da177e4SLinus Torvalds * function:
21451da177e4SLinus Torvalds * traverse for truncation logging backward bottom up;
21461da177e4SLinus Torvalds * terminate at the last extent entry at the current subtree
21471da177e4SLinus Torvalds * root page covering new down size.
21481da177e4SLinus Torvalds * truncation may occur within the last extent entry.
21491da177e4SLinus Torvalds *
21501da177e4SLinus Torvalds * parameter:
21511da177e4SLinus Torvalds * int tid,
21521da177e4SLinus Torvalds * struct inode *ip,
21531da177e4SLinus Torvalds * s64 newsize,
21541da177e4SLinus Torvalds * int type) {PWMAP, PMAP, WMAP; DELETE, TRUNCATE}
21551da177e4SLinus Torvalds *
21561da177e4SLinus Torvalds * return:
21571da177e4SLinus Torvalds *
21581da177e4SLinus Torvalds * note:
21591da177e4SLinus Torvalds * PWMAP:
21601da177e4SLinus Torvalds * 1. truncate (non-COMMIT_NOLINK file)
21611da177e4SLinus Torvalds * by jfs_truncate() or jfs_open(O_TRUNC):
21621da177e4SLinus Torvalds * xtree is updated;
21631da177e4SLinus Torvalds * 2. truncate index table of directory when last entry removed
21641da177e4SLinus Torvalds * map update via tlock at commit time;
21651da177e4SLinus Torvalds * PMAP:
21661da177e4SLinus Torvalds * Call xtTruncate_pmap instead
21671da177e4SLinus Torvalds * WMAP:
21681da177e4SLinus Torvalds * 1. remove (free zero link count) on last reference release
21691da177e4SLinus Torvalds * (pmap has been freed at commit zero link count);
21701da177e4SLinus Torvalds * 2. truncate (COMMIT_NOLINK file, i.e., tmp file):
21711da177e4SLinus Torvalds * xtree is updated;
21721da177e4SLinus Torvalds * map update directly at truncation time;
21731da177e4SLinus Torvalds *
21741da177e4SLinus Torvalds * if (DELETE)
21751da177e4SLinus Torvalds * no LOG_NOREDOPAGE is required (NOREDOFILE is sufficient);
21761da177e4SLinus Torvalds * else if (TRUNCATE)
21771da177e4SLinus Torvalds * must write LOG_NOREDOPAGE for deleted index page;
21781da177e4SLinus Torvalds *
21791da177e4SLinus Torvalds * pages may already have been tlocked by anonymous transactions
21801da177e4SLinus Torvalds * during file growth (i.e., write) before truncation;
21811da177e4SLinus Torvalds *
21821da177e4SLinus Torvalds * except last truncated entry, deleted entries remains as is
21831da177e4SLinus Torvalds * in the page (nextindex is updated) for other use
21841da177e4SLinus Torvalds * (e.g., log/update allocation map): this avoid copying the page
21851da177e4SLinus Torvalds * info but delay free of pages;
21861da177e4SLinus Torvalds *
21871da177e4SLinus Torvalds */
xtTruncate(tid_t tid,struct inode * ip,s64 newsize,int flag)21881da177e4SLinus Torvalds s64 xtTruncate(tid_t tid, struct inode *ip, s64 newsize, int flag)
21891da177e4SLinus Torvalds {
21901da177e4SLinus Torvalds int rc = 0;
21911da177e4SLinus Torvalds s64 teof;
21921da177e4SLinus Torvalds struct metapage *mp;
21931da177e4SLinus Torvalds xtpage_t *p;
21941da177e4SLinus Torvalds s64 bn;
21951da177e4SLinus Torvalds int index, nextindex;
21961da177e4SLinus Torvalds xad_t *xad;
21971da177e4SLinus Torvalds s64 xoff, xaddr;
21981da177e4SLinus Torvalds int xlen, len, freexlen;
21991da177e4SLinus Torvalds struct btstack btstack;
22001da177e4SLinus Torvalds struct btframe *parent;
22011da177e4SLinus Torvalds struct tblock *tblk = NULL;
22021da177e4SLinus Torvalds struct tlock *tlck = NULL;
22031da177e4SLinus Torvalds struct xtlock *xtlck = NULL;
22041da177e4SLinus Torvalds struct xdlistlock xadlock; /* maplock for COMMIT_WMAP */
22051da177e4SLinus Torvalds struct pxd_lock *pxdlock; /* maplock for COMMIT_WMAP */
22061da177e4SLinus Torvalds s64 nfreed;
22071da177e4SLinus Torvalds int freed, log;
22081da177e4SLinus Torvalds int locked_leaves = 0;
22091da177e4SLinus Torvalds
22101da177e4SLinus Torvalds /* save object truncation type */
22111da177e4SLinus Torvalds if (tid) {
22121da177e4SLinus Torvalds tblk = tid_to_tblock(tid);
22131da177e4SLinus Torvalds tblk->xflag |= flag;
22141da177e4SLinus Torvalds }
22151da177e4SLinus Torvalds
22161da177e4SLinus Torvalds nfreed = 0;
22171da177e4SLinus Torvalds
22181da177e4SLinus Torvalds flag &= COMMIT_MAP;
22191da177e4SLinus Torvalds assert(flag != COMMIT_PMAP);
22201da177e4SLinus Torvalds
22211da177e4SLinus Torvalds if (flag == COMMIT_PWMAP)
22221da177e4SLinus Torvalds log = 1;
22231da177e4SLinus Torvalds else {
22241da177e4SLinus Torvalds log = 0;
22251da177e4SLinus Torvalds xadlock.flag = mlckFREEXADLIST;
22261da177e4SLinus Torvalds xadlock.index = 1;
22271da177e4SLinus Torvalds }
22281da177e4SLinus Torvalds
22291da177e4SLinus Torvalds /*
22301da177e4SLinus Torvalds * if the newsize is not an integral number of pages,
22311da177e4SLinus Torvalds * the file between newsize and next page boundary will
22321da177e4SLinus Torvalds * be cleared.
22331da177e4SLinus Torvalds * if truncating into a file hole, it will cause
22341da177e4SLinus Torvalds * a full block to be allocated for the logical block.
22351da177e4SLinus Torvalds */
22361da177e4SLinus Torvalds
22371da177e4SLinus Torvalds /*
22381da177e4SLinus Torvalds * release page blocks of truncated region <teof, eof>
22391da177e4SLinus Torvalds *
22401da177e4SLinus Torvalds * free the data blocks from the leaf index blocks.
22411da177e4SLinus Torvalds * delete the parent index entries corresponding to
22421da177e4SLinus Torvalds * the freed child data/index blocks.
22431da177e4SLinus Torvalds * free the index blocks themselves which aren't needed
22441da177e4SLinus Torvalds * in new sized file.
22451da177e4SLinus Torvalds *
22461da177e4SLinus Torvalds * index blocks are updated only if the blocks are to be
22471da177e4SLinus Torvalds * retained in the new sized file.
22481da177e4SLinus Torvalds * if type is PMAP, the data and index pages are NOT
22491da177e4SLinus Torvalds * freed, and the data and index blocks are NOT freed
22501da177e4SLinus Torvalds * from working map.
22511da177e4SLinus Torvalds * (this will allow continued access of data/index of
22521da177e4SLinus Torvalds * temporary file (zerolink count file truncated to zero-length)).
22531da177e4SLinus Torvalds */
22541da177e4SLinus Torvalds teof = (newsize + (JFS_SBI(ip->i_sb)->bsize - 1)) >>
22551da177e4SLinus Torvalds JFS_SBI(ip->i_sb)->l2bsize;
22561da177e4SLinus Torvalds
22571da177e4SLinus Torvalds /* clear stack */
22581da177e4SLinus Torvalds BT_CLR(&btstack);
22591da177e4SLinus Torvalds
22601da177e4SLinus Torvalds /*
22611da177e4SLinus Torvalds * start with root
22621da177e4SLinus Torvalds *
22631da177e4SLinus Torvalds * root resides in the inode
22641da177e4SLinus Torvalds */
22651da177e4SLinus Torvalds bn = 0;
22661da177e4SLinus Torvalds
22671da177e4SLinus Torvalds /*
22681da177e4SLinus Torvalds * first access of each page:
22691da177e4SLinus Torvalds */
22701da177e4SLinus Torvalds getPage:
22711da177e4SLinus Torvalds XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
22721da177e4SLinus Torvalds if (rc)
22731da177e4SLinus Torvalds return rc;
22741da177e4SLinus Torvalds
22751da177e4SLinus Torvalds /* process entries backward from last index */
22761da177e4SLinus Torvalds index = le16_to_cpu(p->header.nextindex) - 1;
22771da177e4SLinus Torvalds
22781da177e4SLinus Torvalds
22797038f1cbSDave Kleikamp /* Since this is the rightmost page at this level, and we may have
22807038f1cbSDave Kleikamp * already freed a page that was formerly to the right, let's make
22817038f1cbSDave Kleikamp * sure that the next pointer is zero.
22821da177e4SLinus Torvalds */
22831da177e4SLinus Torvalds if (p->header.next) {
22841da177e4SLinus Torvalds if (log)
22851da177e4SLinus Torvalds /*
22861da177e4SLinus Torvalds * Make sure this change to the header is logged.
22871da177e4SLinus Torvalds * If we really truncate this leaf, the flag
22881da177e4SLinus Torvalds * will be changed to tlckTRUNCATE
22891da177e4SLinus Torvalds */
22901da177e4SLinus Torvalds tlck = txLock(tid, ip, mp, tlckXTREE|tlckGROW);
22911da177e4SLinus Torvalds BT_MARK_DIRTY(mp, ip);
22921da177e4SLinus Torvalds p->header.next = 0;
22931da177e4SLinus Torvalds }
22941da177e4SLinus Torvalds
22957038f1cbSDave Kleikamp if (p->header.flag & BT_INTERNAL)
22967038f1cbSDave Kleikamp goto getChild;
22977038f1cbSDave Kleikamp
22987038f1cbSDave Kleikamp /*
22997038f1cbSDave Kleikamp * leaf page
23007038f1cbSDave Kleikamp */
23011da177e4SLinus Torvalds freed = 0;
23021da177e4SLinus Torvalds
23031da177e4SLinus Torvalds /* does region covered by leaf page precede Teof ? */
23041da177e4SLinus Torvalds xad = &p->xad[index];
23051da177e4SLinus Torvalds xoff = offsetXAD(xad);
23061da177e4SLinus Torvalds xlen = lengthXAD(xad);
23071da177e4SLinus Torvalds if (teof >= xoff + xlen) {
23081da177e4SLinus Torvalds XT_PUTPAGE(mp);
23091da177e4SLinus Torvalds goto getParent;
23101da177e4SLinus Torvalds }
23111da177e4SLinus Torvalds
23121da177e4SLinus Torvalds /* (re)acquire tlock of the leaf page */
23131da177e4SLinus Torvalds if (log) {
23141da177e4SLinus Torvalds if (++locked_leaves > MAX_TRUNCATE_LEAVES) {
23151da177e4SLinus Torvalds /*
23161da177e4SLinus Torvalds * We need to limit the size of the transaction
23171da177e4SLinus Torvalds * to avoid exhausting pagecache & tlocks
23181da177e4SLinus Torvalds */
23191da177e4SLinus Torvalds XT_PUTPAGE(mp);
23201da177e4SLinus Torvalds newsize = (xoff + xlen) << JFS_SBI(ip->i_sb)->l2bsize;
23211da177e4SLinus Torvalds goto getParent;
23221da177e4SLinus Torvalds }
23231da177e4SLinus Torvalds tlck = txLock(tid, ip, mp, tlckXTREE);
23241da177e4SLinus Torvalds tlck->type = tlckXTREE | tlckTRUNCATE;
23251da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
23261da177e4SLinus Torvalds xtlck->hwm.offset = le16_to_cpu(p->header.nextindex) - 1;
23271da177e4SLinus Torvalds }
23281da177e4SLinus Torvalds BT_MARK_DIRTY(mp, ip);
23291da177e4SLinus Torvalds
23301da177e4SLinus Torvalds /*
23311da177e4SLinus Torvalds * scan backward leaf page entries
23321da177e4SLinus Torvalds */
23331da177e4SLinus Torvalds for (; index >= XTENTRYSTART; index--) {
23341da177e4SLinus Torvalds xad = &p->xad[index];
23351da177e4SLinus Torvalds xoff = offsetXAD(xad);
23361da177e4SLinus Torvalds xlen = lengthXAD(xad);
23371da177e4SLinus Torvalds xaddr = addressXAD(xad);
23381da177e4SLinus Torvalds
23391da177e4SLinus Torvalds /*
23401da177e4SLinus Torvalds * The "data" for a directory is indexed by the block
23411da177e4SLinus Torvalds * device's address space. This metadata must be invalidated
23421da177e4SLinus Torvalds * here
23431da177e4SLinus Torvalds */
23441da177e4SLinus Torvalds if (S_ISDIR(ip->i_mode) && (teof == 0))
23451da177e4SLinus Torvalds invalidate_xad_metapages(ip, *xad);
23461da177e4SLinus Torvalds /*
23471da177e4SLinus Torvalds * entry beyond eof: continue scan of current page
23481da177e4SLinus Torvalds * xad
23491da177e4SLinus Torvalds * ---|---=======------->
23501da177e4SLinus Torvalds * eof
23511da177e4SLinus Torvalds */
23521da177e4SLinus Torvalds if (teof < xoff) {
23531da177e4SLinus Torvalds nfreed += xlen;
23541da177e4SLinus Torvalds continue;
23551da177e4SLinus Torvalds }
23561da177e4SLinus Torvalds
23571da177e4SLinus Torvalds /*
23581da177e4SLinus Torvalds * (xoff <= teof): last entry to be deleted from page;
23591da177e4SLinus Torvalds * If other entries remain in page: keep and update the page.
23601da177e4SLinus Torvalds */
23611da177e4SLinus Torvalds
23621da177e4SLinus Torvalds /*
23631da177e4SLinus Torvalds * eof == entry_start: delete the entry
23641da177e4SLinus Torvalds * xad
23651da177e4SLinus Torvalds * -------|=======------->
23661da177e4SLinus Torvalds * eof
23671da177e4SLinus Torvalds *
23681da177e4SLinus Torvalds */
23691da177e4SLinus Torvalds if (teof == xoff) {
23701da177e4SLinus Torvalds nfreed += xlen;
23711da177e4SLinus Torvalds
23721da177e4SLinus Torvalds if (index == XTENTRYSTART)
23731da177e4SLinus Torvalds break;
23741da177e4SLinus Torvalds
23751da177e4SLinus Torvalds nextindex = index;
23761da177e4SLinus Torvalds }
23771da177e4SLinus Torvalds /*
23781da177e4SLinus Torvalds * eof within the entry: truncate the entry.
23791da177e4SLinus Torvalds * xad
23801da177e4SLinus Torvalds * -------===|===------->
23811da177e4SLinus Torvalds * eof
23821da177e4SLinus Torvalds */
23831da177e4SLinus Torvalds else if (teof < xoff + xlen) {
23841da177e4SLinus Torvalds /* update truncated entry */
23851da177e4SLinus Torvalds len = teof - xoff;
23861da177e4SLinus Torvalds freexlen = xlen - len;
23871da177e4SLinus Torvalds XADlength(xad, len);
23881da177e4SLinus Torvalds
23891da177e4SLinus Torvalds /* save pxd of truncated extent in tlck */
23901da177e4SLinus Torvalds xaddr += len;
23911da177e4SLinus Torvalds if (log) { /* COMMIT_PWMAP */
23921da177e4SLinus Torvalds xtlck->lwm.offset = (xtlck->lwm.offset) ?
23931da177e4SLinus Torvalds min(index, (int)xtlck->lwm.offset) : index;
23941da177e4SLinus Torvalds xtlck->lwm.length = index + 1 -
23951da177e4SLinus Torvalds xtlck->lwm.offset;
23961da177e4SLinus Torvalds xtlck->twm.offset = index;
23971da177e4SLinus Torvalds pxdlock = (struct pxd_lock *) & xtlck->pxdlock;
23981da177e4SLinus Torvalds pxdlock->flag = mlckFREEPXD;
23991da177e4SLinus Torvalds PXDaddress(&pxdlock->pxd, xaddr);
24001da177e4SLinus Torvalds PXDlength(&pxdlock->pxd, freexlen);
24011da177e4SLinus Torvalds }
24021da177e4SLinus Torvalds /* free truncated extent */
24031da177e4SLinus Torvalds else { /* COMMIT_WMAP */
24041da177e4SLinus Torvalds
24051da177e4SLinus Torvalds pxdlock = (struct pxd_lock *) & xadlock;
24061da177e4SLinus Torvalds pxdlock->flag = mlckFREEPXD;
24071da177e4SLinus Torvalds PXDaddress(&pxdlock->pxd, xaddr);
24081da177e4SLinus Torvalds PXDlength(&pxdlock->pxd, freexlen);
24091da177e4SLinus Torvalds txFreeMap(ip, pxdlock, NULL, COMMIT_WMAP);
24101da177e4SLinus Torvalds
24111da177e4SLinus Torvalds /* reset map lock */
24121da177e4SLinus Torvalds xadlock.flag = mlckFREEXADLIST;
24131da177e4SLinus Torvalds }
24141da177e4SLinus Torvalds
24151da177e4SLinus Torvalds /* current entry is new last entry; */
24161da177e4SLinus Torvalds nextindex = index + 1;
24171da177e4SLinus Torvalds
24181da177e4SLinus Torvalds nfreed += freexlen;
24191da177e4SLinus Torvalds }
24201da177e4SLinus Torvalds /*
24211da177e4SLinus Torvalds * eof beyond the entry:
24221da177e4SLinus Torvalds * xad
24231da177e4SLinus Torvalds * -------=======---|--->
24241da177e4SLinus Torvalds * eof
24251da177e4SLinus Torvalds */
24261da177e4SLinus Torvalds else { /* (xoff + xlen < teof) */
24271da177e4SLinus Torvalds
24281da177e4SLinus Torvalds nextindex = index + 1;
24291da177e4SLinus Torvalds }
24301da177e4SLinus Torvalds
24311da177e4SLinus Torvalds if (nextindex < le16_to_cpu(p->header.nextindex)) {
24321da177e4SLinus Torvalds if (!log) { /* COMMIT_WAMP */
24331da177e4SLinus Torvalds xadlock.xdlist = &p->xad[nextindex];
24341da177e4SLinus Torvalds xadlock.count =
24351da177e4SLinus Torvalds le16_to_cpu(p->header.nextindex) -
24361da177e4SLinus Torvalds nextindex;
24371da177e4SLinus Torvalds txFreeMap(ip, (struct maplock *) & xadlock,
24381da177e4SLinus Torvalds NULL, COMMIT_WMAP);
24391da177e4SLinus Torvalds }
24401da177e4SLinus Torvalds p->header.nextindex = cpu_to_le16(nextindex);
24411da177e4SLinus Torvalds }
24421da177e4SLinus Torvalds
24431da177e4SLinus Torvalds XT_PUTPAGE(mp);
24441da177e4SLinus Torvalds
24451da177e4SLinus Torvalds /* assert(freed == 0); */
24461da177e4SLinus Torvalds goto getParent;
24471da177e4SLinus Torvalds } /* end scan of leaf page entries */
24481da177e4SLinus Torvalds
24491da177e4SLinus Torvalds freed = 1;
24501da177e4SLinus Torvalds
24511da177e4SLinus Torvalds /*
24521da177e4SLinus Torvalds * leaf page become empty: free the page if type != PMAP
24531da177e4SLinus Torvalds */
24541da177e4SLinus Torvalds if (log) { /* COMMIT_PWMAP */
24551da177e4SLinus Torvalds /* txCommit() with tlckFREE:
24561da177e4SLinus Torvalds * free data extents covered by leaf [XTENTRYSTART:hwm);
24571da177e4SLinus Torvalds * invalidate leaf if COMMIT_PWMAP;
24581da177e4SLinus Torvalds * if (TRUNCATE), will write LOG_NOREDOPAGE;
24591da177e4SLinus Torvalds */
24601da177e4SLinus Torvalds tlck->type = tlckXTREE | tlckFREE;
24611da177e4SLinus Torvalds } else { /* COMMIT_WAMP */
24621da177e4SLinus Torvalds
24631da177e4SLinus Torvalds /* free data extents covered by leaf */
24641da177e4SLinus Torvalds xadlock.xdlist = &p->xad[XTENTRYSTART];
24651da177e4SLinus Torvalds xadlock.count =
24661da177e4SLinus Torvalds le16_to_cpu(p->header.nextindex) - XTENTRYSTART;
24671da177e4SLinus Torvalds txFreeMap(ip, (struct maplock *) & xadlock, NULL, COMMIT_WMAP);
24681da177e4SLinus Torvalds }
24691da177e4SLinus Torvalds
24701da177e4SLinus Torvalds if (p->header.flag & BT_ROOT) {
24711da177e4SLinus Torvalds p->header.flag &= ~BT_INTERNAL;
24721da177e4SLinus Torvalds p->header.flag |= BT_LEAF;
24731da177e4SLinus Torvalds p->header.nextindex = cpu_to_le16(XTENTRYSTART);
24741da177e4SLinus Torvalds
24751da177e4SLinus Torvalds XT_PUTPAGE(mp); /* debug */
24761da177e4SLinus Torvalds goto out;
24771da177e4SLinus Torvalds } else {
24781da177e4SLinus Torvalds if (log) { /* COMMIT_PWMAP */
24791da177e4SLinus Torvalds /* page will be invalidated at tx completion
24801da177e4SLinus Torvalds */
24811da177e4SLinus Torvalds XT_PUTPAGE(mp);
24821da177e4SLinus Torvalds } else { /* COMMIT_WMAP */
24831da177e4SLinus Torvalds
24841da177e4SLinus Torvalds if (mp->lid)
24851da177e4SLinus Torvalds lid_to_tlock(mp->lid)->flag |= tlckFREELOCK;
24861da177e4SLinus Torvalds
24871da177e4SLinus Torvalds /* invalidate empty leaf page */
24881da177e4SLinus Torvalds discard_metapage(mp);
24891da177e4SLinus Torvalds }
24901da177e4SLinus Torvalds }
24911da177e4SLinus Torvalds
24921da177e4SLinus Torvalds /*
24931da177e4SLinus Torvalds * the leaf page become empty: delete the parent entry
24941da177e4SLinus Torvalds * for the leaf page if the parent page is to be kept
24951da177e4SLinus Torvalds * in the new sized file.
24961da177e4SLinus Torvalds */
24971da177e4SLinus Torvalds
24981da177e4SLinus Torvalds /*
24991da177e4SLinus Torvalds * go back up to the parent page
25001da177e4SLinus Torvalds */
25011da177e4SLinus Torvalds getParent:
25021da177e4SLinus Torvalds /* pop/restore parent entry for the current child page */
25031da177e4SLinus Torvalds if ((parent = BT_POP(&btstack)) == NULL)
25041da177e4SLinus Torvalds /* current page must have been root */
25051da177e4SLinus Torvalds goto out;
25061da177e4SLinus Torvalds
25071da177e4SLinus Torvalds /* get back the parent page */
25081da177e4SLinus Torvalds bn = parent->bn;
25091da177e4SLinus Torvalds XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
25101da177e4SLinus Torvalds if (rc)
25111da177e4SLinus Torvalds return rc;
25121da177e4SLinus Torvalds
25131da177e4SLinus Torvalds index = parent->index;
25141da177e4SLinus Torvalds
25151da177e4SLinus Torvalds /*
25161da177e4SLinus Torvalds * child page was not empty:
25171da177e4SLinus Torvalds */
25181da177e4SLinus Torvalds if (freed == 0) {
25191da177e4SLinus Torvalds /* has any entry deleted from parent ? */
25201da177e4SLinus Torvalds if (index < le16_to_cpu(p->header.nextindex) - 1) {
25211da177e4SLinus Torvalds /* (re)acquire tlock on the parent page */
25221da177e4SLinus Torvalds if (log) { /* COMMIT_PWMAP */
25231da177e4SLinus Torvalds /* txCommit() with tlckTRUNCATE:
25241da177e4SLinus Torvalds * free child extents covered by parent [);
25251da177e4SLinus Torvalds */
25261da177e4SLinus Torvalds tlck = txLock(tid, ip, mp, tlckXTREE);
25271da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
25281da177e4SLinus Torvalds if (!(tlck->type & tlckTRUNCATE)) {
25291da177e4SLinus Torvalds xtlck->hwm.offset =
25301da177e4SLinus Torvalds le16_to_cpu(p->header.
25311da177e4SLinus Torvalds nextindex) - 1;
25321da177e4SLinus Torvalds tlck->type =
25331da177e4SLinus Torvalds tlckXTREE | tlckTRUNCATE;
25341da177e4SLinus Torvalds }
25351da177e4SLinus Torvalds } else { /* COMMIT_WMAP */
25361da177e4SLinus Torvalds
25371da177e4SLinus Torvalds /* free child extents covered by parent */
25381da177e4SLinus Torvalds xadlock.xdlist = &p->xad[index + 1];
25391da177e4SLinus Torvalds xadlock.count =
25401da177e4SLinus Torvalds le16_to_cpu(p->header.nextindex) -
25411da177e4SLinus Torvalds index - 1;
25421da177e4SLinus Torvalds txFreeMap(ip, (struct maplock *) & xadlock,
25431da177e4SLinus Torvalds NULL, COMMIT_WMAP);
25441da177e4SLinus Torvalds }
25451da177e4SLinus Torvalds BT_MARK_DIRTY(mp, ip);
25461da177e4SLinus Torvalds
25471da177e4SLinus Torvalds p->header.nextindex = cpu_to_le16(index + 1);
25481da177e4SLinus Torvalds }
25491da177e4SLinus Torvalds XT_PUTPAGE(mp);
25501da177e4SLinus Torvalds goto getParent;
25511da177e4SLinus Torvalds }
25521da177e4SLinus Torvalds
25531da177e4SLinus Torvalds /*
25541da177e4SLinus Torvalds * child page was empty:
25551da177e4SLinus Torvalds */
25561da177e4SLinus Torvalds nfreed += lengthXAD(&p->xad[index]);
25571da177e4SLinus Torvalds
25581da177e4SLinus Torvalds /*
25591da177e4SLinus Torvalds * During working map update, child page's tlock must be handled
25601da177e4SLinus Torvalds * before parent's. This is because the parent's tlock will cause
25611da177e4SLinus Torvalds * the child's disk space to be marked available in the wmap, so
25621da177e4SLinus Torvalds * it's important that the child page be released by that time.
25631da177e4SLinus Torvalds *
25641da177e4SLinus Torvalds * ToDo: tlocks should be on doubly-linked list, so we can
25651da177e4SLinus Torvalds * quickly remove it and add it to the end.
25661da177e4SLinus Torvalds */
25671da177e4SLinus Torvalds
25681da177e4SLinus Torvalds /*
25691da177e4SLinus Torvalds * Move parent page's tlock to the end of the tid's tlock list
25701da177e4SLinus Torvalds */
25711da177e4SLinus Torvalds if (log && mp->lid && (tblk->last != mp->lid) &&
25721da177e4SLinus Torvalds lid_to_tlock(mp->lid)->tid) {
25731da177e4SLinus Torvalds lid_t lid = mp->lid;
25741da177e4SLinus Torvalds struct tlock *prev;
25751da177e4SLinus Torvalds
25761da177e4SLinus Torvalds tlck = lid_to_tlock(lid);
25771da177e4SLinus Torvalds
25781da177e4SLinus Torvalds if (tblk->next == lid)
25791da177e4SLinus Torvalds tblk->next = tlck->next;
25801da177e4SLinus Torvalds else {
25811da177e4SLinus Torvalds for (prev = lid_to_tlock(tblk->next);
25821da177e4SLinus Torvalds prev->next != lid;
25831da177e4SLinus Torvalds prev = lid_to_tlock(prev->next)) {
25841da177e4SLinus Torvalds assert(prev->next);
25851da177e4SLinus Torvalds }
25861da177e4SLinus Torvalds prev->next = tlck->next;
25871da177e4SLinus Torvalds }
25881da177e4SLinus Torvalds lid_to_tlock(tblk->last)->next = lid;
25891da177e4SLinus Torvalds tlck->next = 0;
25901da177e4SLinus Torvalds tblk->last = lid;
25911da177e4SLinus Torvalds }
25921da177e4SLinus Torvalds
25931da177e4SLinus Torvalds /*
25941da177e4SLinus Torvalds * parent page become empty: free the page
25951da177e4SLinus Torvalds */
25961da177e4SLinus Torvalds if (index == XTENTRYSTART) {
25971da177e4SLinus Torvalds if (log) { /* COMMIT_PWMAP */
25981da177e4SLinus Torvalds /* txCommit() with tlckFREE:
25991da177e4SLinus Torvalds * free child extents covered by parent;
26001da177e4SLinus Torvalds * invalidate parent if COMMIT_PWMAP;
26011da177e4SLinus Torvalds */
26021da177e4SLinus Torvalds tlck = txLock(tid, ip, mp, tlckXTREE);
26031da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
26041da177e4SLinus Torvalds xtlck->hwm.offset =
26051da177e4SLinus Torvalds le16_to_cpu(p->header.nextindex) - 1;
26061da177e4SLinus Torvalds tlck->type = tlckXTREE | tlckFREE;
26071da177e4SLinus Torvalds } else { /* COMMIT_WMAP */
26081da177e4SLinus Torvalds
26091da177e4SLinus Torvalds /* free child extents covered by parent */
26101da177e4SLinus Torvalds xadlock.xdlist = &p->xad[XTENTRYSTART];
26111da177e4SLinus Torvalds xadlock.count =
26121da177e4SLinus Torvalds le16_to_cpu(p->header.nextindex) -
26131da177e4SLinus Torvalds XTENTRYSTART;
26141da177e4SLinus Torvalds txFreeMap(ip, (struct maplock *) & xadlock, NULL,
26151da177e4SLinus Torvalds COMMIT_WMAP);
26161da177e4SLinus Torvalds }
26171da177e4SLinus Torvalds BT_MARK_DIRTY(mp, ip);
26181da177e4SLinus Torvalds
26191da177e4SLinus Torvalds if (p->header.flag & BT_ROOT) {
26201da177e4SLinus Torvalds p->header.flag &= ~BT_INTERNAL;
26211da177e4SLinus Torvalds p->header.flag |= BT_LEAF;
26221da177e4SLinus Torvalds p->header.nextindex = cpu_to_le16(XTENTRYSTART);
26231da177e4SLinus Torvalds if (le16_to_cpu(p->header.maxentry) == XTROOTMAXSLOT) {
26241da177e4SLinus Torvalds /*
26251da177e4SLinus Torvalds * Shrink root down to allow inline
26261da177e4SLinus Torvalds * EA (otherwise fsck complains)
26271da177e4SLinus Torvalds */
26281da177e4SLinus Torvalds p->header.maxentry =
26291da177e4SLinus Torvalds cpu_to_le16(XTROOTINITSLOT);
26301da177e4SLinus Torvalds JFS_IP(ip)->mode2 |= INLINEEA;
26311da177e4SLinus Torvalds }
26321da177e4SLinus Torvalds
26331da177e4SLinus Torvalds XT_PUTPAGE(mp); /* debug */
26341da177e4SLinus Torvalds goto out;
26351da177e4SLinus Torvalds } else {
26361da177e4SLinus Torvalds if (log) { /* COMMIT_PWMAP */
26371da177e4SLinus Torvalds /* page will be invalidated at tx completion
26381da177e4SLinus Torvalds */
26391da177e4SLinus Torvalds XT_PUTPAGE(mp);
26401da177e4SLinus Torvalds } else { /* COMMIT_WMAP */
26411da177e4SLinus Torvalds
26421da177e4SLinus Torvalds if (mp->lid)
26431da177e4SLinus Torvalds lid_to_tlock(mp->lid)->flag |=
26441da177e4SLinus Torvalds tlckFREELOCK;
26451da177e4SLinus Torvalds
26461da177e4SLinus Torvalds /* invalidate parent page */
26471da177e4SLinus Torvalds discard_metapage(mp);
26481da177e4SLinus Torvalds }
26491da177e4SLinus Torvalds
26501da177e4SLinus Torvalds /* parent has become empty and freed:
26511da177e4SLinus Torvalds * go back up to its parent page
26521da177e4SLinus Torvalds */
26531da177e4SLinus Torvalds /* freed = 1; */
26541da177e4SLinus Torvalds goto getParent;
26551da177e4SLinus Torvalds }
26561da177e4SLinus Torvalds }
26571da177e4SLinus Torvalds /*
26581da177e4SLinus Torvalds * parent page still has entries for front region;
26591da177e4SLinus Torvalds */
26601da177e4SLinus Torvalds else {
26611da177e4SLinus Torvalds /* try truncate region covered by preceding entry
26621da177e4SLinus Torvalds * (process backward)
26631da177e4SLinus Torvalds */
26641da177e4SLinus Torvalds index--;
26651da177e4SLinus Torvalds
26661da177e4SLinus Torvalds /* go back down to the child page corresponding
26671da177e4SLinus Torvalds * to the entry
26681da177e4SLinus Torvalds */
26691da177e4SLinus Torvalds goto getChild;
26701da177e4SLinus Torvalds }
26711da177e4SLinus Torvalds
26721da177e4SLinus Torvalds /*
26731da177e4SLinus Torvalds * internal page: go down to child page of current entry
26741da177e4SLinus Torvalds */
26751da177e4SLinus Torvalds getChild:
26761da177e4SLinus Torvalds /* save current parent entry for the child page */
267717e6afc7SDave Kleikamp if (BT_STACK_FULL(&btstack)) {
2678eb8630d7SJoe Perches jfs_error(ip->i_sb, "stack overrun!\n");
267917e6afc7SDave Kleikamp XT_PUTPAGE(mp);
268017e6afc7SDave Kleikamp return -EIO;
268117e6afc7SDave Kleikamp }
26821da177e4SLinus Torvalds BT_PUSH(&btstack, bn, index);
26831da177e4SLinus Torvalds
26841da177e4SLinus Torvalds /* get child page */
26851da177e4SLinus Torvalds xad = &p->xad[index];
26861da177e4SLinus Torvalds bn = addressXAD(xad);
26871da177e4SLinus Torvalds
26881da177e4SLinus Torvalds /*
26891da177e4SLinus Torvalds * first access of each internal entry:
26901da177e4SLinus Torvalds */
26911da177e4SLinus Torvalds /* release parent page */
26921da177e4SLinus Torvalds XT_PUTPAGE(mp);
26931da177e4SLinus Torvalds
26941da177e4SLinus Torvalds /* process the child page */
26951da177e4SLinus Torvalds goto getPage;
26961da177e4SLinus Torvalds
26971da177e4SLinus Torvalds out:
26981da177e4SLinus Torvalds /*
26991da177e4SLinus Torvalds * update file resource stat
27001da177e4SLinus Torvalds */
27011da177e4SLinus Torvalds /* set size
27021da177e4SLinus Torvalds */
27031da177e4SLinus Torvalds if (S_ISDIR(ip->i_mode) && !newsize)
27041da177e4SLinus Torvalds ip->i_size = 1; /* fsck hates zero-length directories */
27051da177e4SLinus Torvalds else
27061da177e4SLinus Torvalds ip->i_size = newsize;
27071da177e4SLinus Torvalds
27081da177e4SLinus Torvalds /* update quota allocation to reflect freed blocks */
27095dd4056dSChristoph Hellwig dquot_free_block(ip, nfreed);
27101da177e4SLinus Torvalds
27111da177e4SLinus Torvalds /*
27121da177e4SLinus Torvalds * free tlock of invalidated pages
27131da177e4SLinus Torvalds */
27141da177e4SLinus Torvalds if (flag == COMMIT_WMAP)
27151da177e4SLinus Torvalds txFreelock(ip);
27161da177e4SLinus Torvalds
27171da177e4SLinus Torvalds return newsize;
27181da177e4SLinus Torvalds }
27191da177e4SLinus Torvalds
27201da177e4SLinus Torvalds
27211da177e4SLinus Torvalds /*
27221da177e4SLinus Torvalds * xtTruncate_pmap()
27231da177e4SLinus Torvalds *
27241da177e4SLinus Torvalds * function:
2725efad798bSPaulius Zaleckas * Perform truncate to zero length for deleted file, leaving the
2726ed1c9a7aSRandy Dunlap * xtree and working map untouched. This allows the file to
27271da177e4SLinus Torvalds * be accessed via open file handles, while the delete of the file
27281da177e4SLinus Torvalds * is committed to disk.
27291da177e4SLinus Torvalds *
27301da177e4SLinus Torvalds * parameter:
27311da177e4SLinus Torvalds * tid_t tid,
27321da177e4SLinus Torvalds * struct inode *ip,
27331da177e4SLinus Torvalds * s64 committed_size)
27341da177e4SLinus Torvalds *
27351da177e4SLinus Torvalds * return: new committed size
27361da177e4SLinus Torvalds *
27371da177e4SLinus Torvalds * note:
27381da177e4SLinus Torvalds *
27391da177e4SLinus Torvalds * To avoid deadlock by holding too many transaction locks, the
27401da177e4SLinus Torvalds * truncation may be broken up into multiple transactions.
27411da177e4SLinus Torvalds * The committed_size keeps track of part of the file has been
27421da177e4SLinus Torvalds * freed from the pmaps.
27431da177e4SLinus Torvalds */
xtTruncate_pmap(tid_t tid,struct inode * ip,s64 committed_size)27441da177e4SLinus Torvalds s64 xtTruncate_pmap(tid_t tid, struct inode *ip, s64 committed_size)
27451da177e4SLinus Torvalds {
27461da177e4SLinus Torvalds s64 bn;
27471da177e4SLinus Torvalds struct btstack btstack;
27481da177e4SLinus Torvalds int cmp;
27491da177e4SLinus Torvalds int index;
27501da177e4SLinus Torvalds int locked_leaves = 0;
27511da177e4SLinus Torvalds struct metapage *mp;
27521da177e4SLinus Torvalds xtpage_t *p;
27531da177e4SLinus Torvalds struct btframe *parent;
27541da177e4SLinus Torvalds int rc;
27551da177e4SLinus Torvalds struct tblock *tblk;
27561da177e4SLinus Torvalds struct tlock *tlck = NULL;
27571da177e4SLinus Torvalds xad_t *xad;
27581da177e4SLinus Torvalds int xlen;
27591da177e4SLinus Torvalds s64 xoff;
27601da177e4SLinus Torvalds struct xtlock *xtlck = NULL;
27611da177e4SLinus Torvalds
27621da177e4SLinus Torvalds /* save object truncation type */
27631da177e4SLinus Torvalds tblk = tid_to_tblock(tid);
27641da177e4SLinus Torvalds tblk->xflag |= COMMIT_PMAP;
27651da177e4SLinus Torvalds
27661da177e4SLinus Torvalds /* clear stack */
27671da177e4SLinus Torvalds BT_CLR(&btstack);
27681da177e4SLinus Torvalds
27691da177e4SLinus Torvalds if (committed_size) {
27701da177e4SLinus Torvalds xoff = (committed_size >> JFS_SBI(ip->i_sb)->l2bsize) - 1;
27716628465eSDave Kleikamp rc = xtSearch(ip, xoff, NULL, &cmp, &btstack, 0);
27721da177e4SLinus Torvalds if (rc)
27731da177e4SLinus Torvalds return rc;
27741da177e4SLinus Torvalds
27751da177e4SLinus Torvalds XT_GETSEARCH(ip, btstack.top, bn, mp, p, index);
27761da177e4SLinus Torvalds
27771da177e4SLinus Torvalds if (cmp != 0) {
27781da177e4SLinus Torvalds XT_PUTPAGE(mp);
2779eb8630d7SJoe Perches jfs_error(ip->i_sb, "did not find extent\n");
27801da177e4SLinus Torvalds return -EIO;
27811da177e4SLinus Torvalds }
27821da177e4SLinus Torvalds } else {
27831da177e4SLinus Torvalds /*
27841da177e4SLinus Torvalds * start with root
27851da177e4SLinus Torvalds *
27861da177e4SLinus Torvalds * root resides in the inode
27871da177e4SLinus Torvalds */
27881da177e4SLinus Torvalds bn = 0;
27891da177e4SLinus Torvalds
27901da177e4SLinus Torvalds /*
27911da177e4SLinus Torvalds * first access of each page:
27921da177e4SLinus Torvalds */
27931da177e4SLinus Torvalds getPage:
27941da177e4SLinus Torvalds XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
27951da177e4SLinus Torvalds if (rc)
27961da177e4SLinus Torvalds return rc;
27971da177e4SLinus Torvalds
27981da177e4SLinus Torvalds /* process entries backward from last index */
27991da177e4SLinus Torvalds index = le16_to_cpu(p->header.nextindex) - 1;
28001da177e4SLinus Torvalds
28011da177e4SLinus Torvalds if (p->header.flag & BT_INTERNAL)
28021da177e4SLinus Torvalds goto getChild;
28031da177e4SLinus Torvalds }
28041da177e4SLinus Torvalds
28051da177e4SLinus Torvalds /*
28061da177e4SLinus Torvalds * leaf page
28071da177e4SLinus Torvalds */
28081da177e4SLinus Torvalds
28091da177e4SLinus Torvalds if (++locked_leaves > MAX_TRUNCATE_LEAVES) {
28101da177e4SLinus Torvalds /*
28111da177e4SLinus Torvalds * We need to limit the size of the transaction
28121da177e4SLinus Torvalds * to avoid exhausting pagecache & tlocks
28131da177e4SLinus Torvalds */
28141da177e4SLinus Torvalds xad = &p->xad[index];
28151da177e4SLinus Torvalds xoff = offsetXAD(xad);
28161da177e4SLinus Torvalds xlen = lengthXAD(xad);
28171da177e4SLinus Torvalds XT_PUTPAGE(mp);
28181da177e4SLinus Torvalds return (xoff + xlen) << JFS_SBI(ip->i_sb)->l2bsize;
28191da177e4SLinus Torvalds }
28201da177e4SLinus Torvalds tlck = txLock(tid, ip, mp, tlckXTREE);
28211da177e4SLinus Torvalds tlck->type = tlckXTREE | tlckFREE;
28221da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
28231da177e4SLinus Torvalds xtlck->hwm.offset = index;
28241da177e4SLinus Torvalds
28251da177e4SLinus Torvalds
28261da177e4SLinus Torvalds XT_PUTPAGE(mp);
28271da177e4SLinus Torvalds
28281da177e4SLinus Torvalds /*
28291da177e4SLinus Torvalds * go back up to the parent page
28301da177e4SLinus Torvalds */
28311da177e4SLinus Torvalds getParent:
28321da177e4SLinus Torvalds /* pop/restore parent entry for the current child page */
28331da177e4SLinus Torvalds if ((parent = BT_POP(&btstack)) == NULL)
28341da177e4SLinus Torvalds /* current page must have been root */
28351da177e4SLinus Torvalds goto out;
28361da177e4SLinus Torvalds
28371da177e4SLinus Torvalds /* get back the parent page */
28381da177e4SLinus Torvalds bn = parent->bn;
28391da177e4SLinus Torvalds XT_GETPAGE(ip, bn, mp, PSIZE, p, rc);
28401da177e4SLinus Torvalds if (rc)
28411da177e4SLinus Torvalds return rc;
28421da177e4SLinus Torvalds
28431da177e4SLinus Torvalds index = parent->index;
28441da177e4SLinus Torvalds
28451da177e4SLinus Torvalds /*
28461da177e4SLinus Torvalds * parent page become empty: free the page
28471da177e4SLinus Torvalds */
28481da177e4SLinus Torvalds if (index == XTENTRYSTART) {
28491da177e4SLinus Torvalds /* txCommit() with tlckFREE:
28501da177e4SLinus Torvalds * free child extents covered by parent;
28511da177e4SLinus Torvalds * invalidate parent if COMMIT_PWMAP;
28521da177e4SLinus Torvalds */
28531da177e4SLinus Torvalds tlck = txLock(tid, ip, mp, tlckXTREE);
28541da177e4SLinus Torvalds xtlck = (struct xtlock *) & tlck->lock;
2855f720e3baSDave Kleikamp xtlck->hwm.offset = le16_to_cpu(p->header.nextindex) - 1;
28561da177e4SLinus Torvalds tlck->type = tlckXTREE | tlckFREE;
28571da177e4SLinus Torvalds
28581da177e4SLinus Torvalds XT_PUTPAGE(mp);
28591da177e4SLinus Torvalds
28601da177e4SLinus Torvalds if (p->header.flag & BT_ROOT) {
28611da177e4SLinus Torvalds
28621da177e4SLinus Torvalds goto out;
28631da177e4SLinus Torvalds } else {
28641da177e4SLinus Torvalds goto getParent;
28651da177e4SLinus Torvalds }
28661da177e4SLinus Torvalds }
28671da177e4SLinus Torvalds /*
28681da177e4SLinus Torvalds * parent page still has entries for front region;
28691da177e4SLinus Torvalds */
28701da177e4SLinus Torvalds else
28711da177e4SLinus Torvalds index--;
28721da177e4SLinus Torvalds /*
28731da177e4SLinus Torvalds * internal page: go down to child page of current entry
28741da177e4SLinus Torvalds */
28751da177e4SLinus Torvalds getChild:
28761da177e4SLinus Torvalds /* save current parent entry for the child page */
287717e6afc7SDave Kleikamp if (BT_STACK_FULL(&btstack)) {
2878eb8630d7SJoe Perches jfs_error(ip->i_sb, "stack overrun!\n");
287917e6afc7SDave Kleikamp XT_PUTPAGE(mp);
288017e6afc7SDave Kleikamp return -EIO;
288117e6afc7SDave Kleikamp }
28821da177e4SLinus Torvalds BT_PUSH(&btstack, bn, index);
28831da177e4SLinus Torvalds
28841da177e4SLinus Torvalds /* get child page */
28851da177e4SLinus Torvalds xad = &p->xad[index];
28861da177e4SLinus Torvalds bn = addressXAD(xad);
28871da177e4SLinus Torvalds
28881da177e4SLinus Torvalds /*
28891da177e4SLinus Torvalds * first access of each internal entry:
28901da177e4SLinus Torvalds */
28911da177e4SLinus Torvalds /* release parent page */
28921da177e4SLinus Torvalds XT_PUTPAGE(mp);
28931da177e4SLinus Torvalds
28941da177e4SLinus Torvalds /* process the child page */
28951da177e4SLinus Torvalds goto getPage;
28961da177e4SLinus Torvalds
28971da177e4SLinus Torvalds out:
28981da177e4SLinus Torvalds
28991da177e4SLinus Torvalds return 0;
29001da177e4SLinus Torvalds }
29011da177e4SLinus Torvalds
29021da177e4SLinus Torvalds #ifdef CONFIG_JFS_STATISTICS
jfs_xtstat_proc_show(struct seq_file * m,void * v)290307a3b8edSChristoph Hellwig int jfs_xtstat_proc_show(struct seq_file *m, void *v)
29041da177e4SLinus Torvalds {
2905b2e03ca7SAlexey Dobriyan seq_printf(m,
29061da177e4SLinus Torvalds "JFS Xtree statistics\n"
29071da177e4SLinus Torvalds "====================\n"
29081da177e4SLinus Torvalds "searches = %d\n"
29091da177e4SLinus Torvalds "fast searches = %d\n"
29101da177e4SLinus Torvalds "splits = %d\n",
29111da177e4SLinus Torvalds xtStat.search,
29121da177e4SLinus Torvalds xtStat.fastSearch,
29131da177e4SLinus Torvalds xtStat.split);
2914b2e03ca7SAlexey Dobriyan return 0;
29151da177e4SLinus Torvalds }
29161da177e4SLinus Torvalds #endif
2917