1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/fs/hfsplus/bnode.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 2001
61da177e4SLinus Torvalds * Brad Boyer (flar@allandria.com)
71da177e4SLinus Torvalds * (C) 2003 Ardis Technologies <roman@ardistech.com>
81da177e4SLinus Torvalds *
91da177e4SLinus Torvalds * Handle basic btree node operations
101da177e4SLinus Torvalds */
111da177e4SLinus Torvalds
121da177e4SLinus Torvalds #include <linux/string.h>
131da177e4SLinus Torvalds #include <linux/slab.h>
141da177e4SLinus Torvalds #include <linux/pagemap.h>
151da177e4SLinus Torvalds #include <linux/fs.h>
161da177e4SLinus Torvalds #include <linux/swap.h>
171da177e4SLinus Torvalds
181da177e4SLinus Torvalds #include "hfsplus_fs.h"
191da177e4SLinus Torvalds #include "hfsplus_raw.h"
201da177e4SLinus Torvalds
211da177e4SLinus Torvalds /* Copy a specified range of bytes from the raw data of a node */
hfs_bnode_read(struct hfs_bnode * node,void * buf,int off,int len)221da177e4SLinus Torvalds void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
231da177e4SLinus Torvalds {
241da177e4SLinus Torvalds struct page **pagep;
251da177e4SLinus Torvalds int l;
261da177e4SLinus Torvalds
271da177e4SLinus Torvalds off += node->page_offset;
2809cbfeafSKirill A. Shutemov pagep = node->page + (off >> PAGE_SHIFT);
2909cbfeafSKirill A. Shutemov off &= ~PAGE_MASK;
301da177e4SLinus Torvalds
3109cbfeafSKirill A. Shutemov l = min_t(int, len, PAGE_SIZE - off);
32*6c3014a6SFabio M. De Francesco memcpy_from_page(buf, *pagep, off, l);
331da177e4SLinus Torvalds
341da177e4SLinus Torvalds while ((len -= l) != 0) {
351da177e4SLinus Torvalds buf += l;
3609cbfeafSKirill A. Shutemov l = min_t(int, len, PAGE_SIZE);
37*6c3014a6SFabio M. De Francesco memcpy_from_page(buf, *++pagep, 0, l);
381da177e4SLinus Torvalds }
391da177e4SLinus Torvalds }
401da177e4SLinus Torvalds
hfs_bnode_read_u16(struct hfs_bnode * node,int off)411da177e4SLinus Torvalds u16 hfs_bnode_read_u16(struct hfs_bnode *node, int off)
421da177e4SLinus Torvalds {
431da177e4SLinus Torvalds __be16 data;
4421f2296aSAnton Salikhmetov /* TODO: optimize later... */
451da177e4SLinus Torvalds hfs_bnode_read(node, &data, off, 2);
461da177e4SLinus Torvalds return be16_to_cpu(data);
471da177e4SLinus Torvalds }
481da177e4SLinus Torvalds
hfs_bnode_read_u8(struct hfs_bnode * node,int off)491da177e4SLinus Torvalds u8 hfs_bnode_read_u8(struct hfs_bnode *node, int off)
501da177e4SLinus Torvalds {
511da177e4SLinus Torvalds u8 data;
5221f2296aSAnton Salikhmetov /* TODO: optimize later... */
531da177e4SLinus Torvalds hfs_bnode_read(node, &data, off, 1);
541da177e4SLinus Torvalds return data;
551da177e4SLinus Torvalds }
561da177e4SLinus Torvalds
hfs_bnode_read_key(struct hfs_bnode * node,void * key,int off)571da177e4SLinus Torvalds void hfs_bnode_read_key(struct hfs_bnode *node, void *key, int off)
581da177e4SLinus Torvalds {
591da177e4SLinus Torvalds struct hfs_btree *tree;
601da177e4SLinus Torvalds int key_len;
611da177e4SLinus Torvalds
621da177e4SLinus Torvalds tree = node->tree;
631da177e4SLinus Torvalds if (node->type == HFS_NODE_LEAF ||
64324ef39aSVyacheslav Dubeyko tree->attributes & HFS_TREE_VARIDXKEYS ||
65324ef39aSVyacheslav Dubeyko node->tree->cnid == HFSPLUS_ATTR_CNID)
661da177e4SLinus Torvalds key_len = hfs_bnode_read_u16(node, off) + 2;
671da177e4SLinus Torvalds else
681da177e4SLinus Torvalds key_len = tree->max_key_len + 2;
691da177e4SLinus Torvalds
701da177e4SLinus Torvalds hfs_bnode_read(node, key, off, key_len);
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds
hfs_bnode_write(struct hfs_bnode * node,void * buf,int off,int len)731da177e4SLinus Torvalds void hfs_bnode_write(struct hfs_bnode *node, void *buf, int off, int len)
741da177e4SLinus Torvalds {
751da177e4SLinus Torvalds struct page **pagep;
761da177e4SLinus Torvalds int l;
771da177e4SLinus Torvalds
781da177e4SLinus Torvalds off += node->page_offset;
7909cbfeafSKirill A. Shutemov pagep = node->page + (off >> PAGE_SHIFT);
8009cbfeafSKirill A. Shutemov off &= ~PAGE_MASK;
811da177e4SLinus Torvalds
8209cbfeafSKirill A. Shutemov l = min_t(int, len, PAGE_SIZE - off);
83*6c3014a6SFabio M. De Francesco memcpy_to_page(*pagep, off, buf, l);
841da177e4SLinus Torvalds set_page_dirty(*pagep);
851da177e4SLinus Torvalds
861da177e4SLinus Torvalds while ((len -= l) != 0) {
871da177e4SLinus Torvalds buf += l;
8809cbfeafSKirill A. Shutemov l = min_t(int, len, PAGE_SIZE);
89*6c3014a6SFabio M. De Francesco memcpy_to_page(*++pagep, 0, buf, l);
901da177e4SLinus Torvalds set_page_dirty(*pagep);
911da177e4SLinus Torvalds }
921da177e4SLinus Torvalds }
931da177e4SLinus Torvalds
hfs_bnode_write_u16(struct hfs_bnode * node,int off,u16 data)941da177e4SLinus Torvalds void hfs_bnode_write_u16(struct hfs_bnode *node, int off, u16 data)
951da177e4SLinus Torvalds {
961da177e4SLinus Torvalds __be16 v = cpu_to_be16(data);
9721f2296aSAnton Salikhmetov /* TODO: optimize later... */
981da177e4SLinus Torvalds hfs_bnode_write(node, &v, off, 2);
991da177e4SLinus Torvalds }
1001da177e4SLinus Torvalds
hfs_bnode_clear(struct hfs_bnode * node,int off,int len)1011da177e4SLinus Torvalds void hfs_bnode_clear(struct hfs_bnode *node, int off, int len)
1021da177e4SLinus Torvalds {
1031da177e4SLinus Torvalds struct page **pagep;
1041da177e4SLinus Torvalds int l;
1051da177e4SLinus Torvalds
1061da177e4SLinus Torvalds off += node->page_offset;
10709cbfeafSKirill A. Shutemov pagep = node->page + (off >> PAGE_SHIFT);
10809cbfeafSKirill A. Shutemov off &= ~PAGE_MASK;
1091da177e4SLinus Torvalds
11009cbfeafSKirill A. Shutemov l = min_t(int, len, PAGE_SIZE - off);
111*6c3014a6SFabio M. De Francesco memzero_page(*pagep, off, l);
1121da177e4SLinus Torvalds set_page_dirty(*pagep);
1131da177e4SLinus Torvalds
1141da177e4SLinus Torvalds while ((len -= l) != 0) {
11509cbfeafSKirill A. Shutemov l = min_t(int, len, PAGE_SIZE);
116*6c3014a6SFabio M. De Francesco memzero_page(*++pagep, 0, l);
1171da177e4SLinus Torvalds set_page_dirty(*pagep);
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds }
1201da177e4SLinus Torvalds
hfs_bnode_copy(struct hfs_bnode * dst_node,int dst,struct hfs_bnode * src_node,int src,int len)1211da177e4SLinus Torvalds void hfs_bnode_copy(struct hfs_bnode *dst_node, int dst,
1221da177e4SLinus Torvalds struct hfs_bnode *src_node, int src, int len)
1231da177e4SLinus Torvalds {
1241da177e4SLinus Torvalds struct page **src_page, **dst_page;
1251da177e4SLinus Torvalds int l;
1261da177e4SLinus Torvalds
127c2b3e1f7SJoe Perches hfs_dbg(BNODE_MOD, "copybytes: %u,%u,%u\n", dst, src, len);
1281da177e4SLinus Torvalds if (!len)
1291da177e4SLinus Torvalds return;
1301da177e4SLinus Torvalds src += src_node->page_offset;
1311da177e4SLinus Torvalds dst += dst_node->page_offset;
13209cbfeafSKirill A. Shutemov src_page = src_node->page + (src >> PAGE_SHIFT);
13309cbfeafSKirill A. Shutemov src &= ~PAGE_MASK;
13409cbfeafSKirill A. Shutemov dst_page = dst_node->page + (dst >> PAGE_SHIFT);
13509cbfeafSKirill A. Shutemov dst &= ~PAGE_MASK;
1361da177e4SLinus Torvalds
1371da177e4SLinus Torvalds if (src == dst) {
13809cbfeafSKirill A. Shutemov l = min_t(int, len, PAGE_SIZE - src);
139*6c3014a6SFabio M. De Francesco memcpy_page(*dst_page, src, *src_page, src, l);
1401da177e4SLinus Torvalds set_page_dirty(*dst_page);
1411da177e4SLinus Torvalds
1421da177e4SLinus Torvalds while ((len -= l) != 0) {
14309cbfeafSKirill A. Shutemov l = min_t(int, len, PAGE_SIZE);
144*6c3014a6SFabio M. De Francesco memcpy_page(*++dst_page, 0, *++src_page, 0, l);
1451da177e4SLinus Torvalds set_page_dirty(*dst_page);
1461da177e4SLinus Torvalds }
1471da177e4SLinus Torvalds } else {
1481da177e4SLinus Torvalds void *src_ptr, *dst_ptr;
1491da177e4SLinus Torvalds
1501da177e4SLinus Torvalds do {
151*6c3014a6SFabio M. De Francesco dst_ptr = kmap_local_page(*dst_page) + dst;
152*6c3014a6SFabio M. De Francesco src_ptr = kmap_local_page(*src_page) + src;
15309cbfeafSKirill A. Shutemov if (PAGE_SIZE - src < PAGE_SIZE - dst) {
15409cbfeafSKirill A. Shutemov l = PAGE_SIZE - src;
1551da177e4SLinus Torvalds src = 0;
1561da177e4SLinus Torvalds dst += l;
1571da177e4SLinus Torvalds } else {
15809cbfeafSKirill A. Shutemov l = PAGE_SIZE - dst;
1591da177e4SLinus Torvalds src += l;
1601da177e4SLinus Torvalds dst = 0;
1611da177e4SLinus Torvalds }
1621da177e4SLinus Torvalds l = min(len, l);
1631da177e4SLinus Torvalds memcpy(dst_ptr, src_ptr, l);
164*6c3014a6SFabio M. De Francesco kunmap_local(src_ptr);
1651da177e4SLinus Torvalds set_page_dirty(*dst_page);
166*6c3014a6SFabio M. De Francesco kunmap_local(dst_ptr);
1671da177e4SLinus Torvalds if (!dst)
1681da177e4SLinus Torvalds dst_page++;
1691da177e4SLinus Torvalds else
1701da177e4SLinus Torvalds src_page++;
1711da177e4SLinus Torvalds } while ((len -= l));
1721da177e4SLinus Torvalds }
1731da177e4SLinus Torvalds }
1741da177e4SLinus Torvalds
hfs_bnode_move(struct hfs_bnode * node,int dst,int src,int len)1751da177e4SLinus Torvalds void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
1761da177e4SLinus Torvalds {
1771da177e4SLinus Torvalds struct page **src_page, **dst_page;
178*6c3014a6SFabio M. De Francesco void *src_ptr, *dst_ptr;
1791da177e4SLinus Torvalds int l;
1801da177e4SLinus Torvalds
181c2b3e1f7SJoe Perches hfs_dbg(BNODE_MOD, "movebytes: %u,%u,%u\n", dst, src, len);
1821da177e4SLinus Torvalds if (!len)
1831da177e4SLinus Torvalds return;
1841da177e4SLinus Torvalds src += node->page_offset;
1851da177e4SLinus Torvalds dst += node->page_offset;
1861da177e4SLinus Torvalds if (dst > src) {
1871da177e4SLinus Torvalds src += len - 1;
18809cbfeafSKirill A. Shutemov src_page = node->page + (src >> PAGE_SHIFT);
18909cbfeafSKirill A. Shutemov src = (src & ~PAGE_MASK) + 1;
1901da177e4SLinus Torvalds dst += len - 1;
19109cbfeafSKirill A. Shutemov dst_page = node->page + (dst >> PAGE_SHIFT);
19209cbfeafSKirill A. Shutemov dst = (dst & ~PAGE_MASK) + 1;
1931da177e4SLinus Torvalds
1941da177e4SLinus Torvalds if (src == dst) {
1951da177e4SLinus Torvalds while (src < len) {
196*6c3014a6SFabio M. De Francesco dst_ptr = kmap_local_page(*dst_page);
197*6c3014a6SFabio M. De Francesco src_ptr = kmap_local_page(*src_page);
198*6c3014a6SFabio M. De Francesco memmove(dst_ptr, src_ptr, src);
199*6c3014a6SFabio M. De Francesco kunmap_local(src_ptr);
2001da177e4SLinus Torvalds set_page_dirty(*dst_page);
201*6c3014a6SFabio M. De Francesco kunmap_local(dst_ptr);
2021da177e4SLinus Torvalds len -= src;
20309cbfeafSKirill A. Shutemov src = PAGE_SIZE;
2041da177e4SLinus Torvalds src_page--;
2051da177e4SLinus Torvalds dst_page--;
2061da177e4SLinus Torvalds }
2071da177e4SLinus Torvalds src -= len;
208*6c3014a6SFabio M. De Francesco dst_ptr = kmap_local_page(*dst_page);
209*6c3014a6SFabio M. De Francesco src_ptr = kmap_local_page(*src_page);
210*6c3014a6SFabio M. De Francesco memmove(dst_ptr + src, src_ptr + src, len);
211*6c3014a6SFabio M. De Francesco kunmap_local(src_ptr);
2121da177e4SLinus Torvalds set_page_dirty(*dst_page);
213*6c3014a6SFabio M. De Francesco kunmap_local(dst_ptr);
2141da177e4SLinus Torvalds } else {
2151da177e4SLinus Torvalds do {
216*6c3014a6SFabio M. De Francesco dst_ptr = kmap_local_page(*dst_page) + dst;
217*6c3014a6SFabio M. De Francesco src_ptr = kmap_local_page(*src_page) + src;
2181da177e4SLinus Torvalds if (src < dst) {
2191da177e4SLinus Torvalds l = src;
22009cbfeafSKirill A. Shutemov src = PAGE_SIZE;
2211da177e4SLinus Torvalds dst -= l;
2221da177e4SLinus Torvalds } else {
2231da177e4SLinus Torvalds l = dst;
2241da177e4SLinus Torvalds src -= l;
22509cbfeafSKirill A. Shutemov dst = PAGE_SIZE;
2261da177e4SLinus Torvalds }
2271da177e4SLinus Torvalds l = min(len, l);
2281da177e4SLinus Torvalds memmove(dst_ptr - l, src_ptr - l, l);
229*6c3014a6SFabio M. De Francesco kunmap_local(src_ptr);
2301da177e4SLinus Torvalds set_page_dirty(*dst_page);
231*6c3014a6SFabio M. De Francesco kunmap_local(dst_ptr);
23209cbfeafSKirill A. Shutemov if (dst == PAGE_SIZE)
2331da177e4SLinus Torvalds dst_page--;
2341da177e4SLinus Torvalds else
2351da177e4SLinus Torvalds src_page--;
2361da177e4SLinus Torvalds } while ((len -= l));
2371da177e4SLinus Torvalds }
2381da177e4SLinus Torvalds } else {
23909cbfeafSKirill A. Shutemov src_page = node->page + (src >> PAGE_SHIFT);
24009cbfeafSKirill A. Shutemov src &= ~PAGE_MASK;
24109cbfeafSKirill A. Shutemov dst_page = node->page + (dst >> PAGE_SHIFT);
24209cbfeafSKirill A. Shutemov dst &= ~PAGE_MASK;
2431da177e4SLinus Torvalds
2441da177e4SLinus Torvalds if (src == dst) {
24509cbfeafSKirill A. Shutemov l = min_t(int, len, PAGE_SIZE - src);
246*6c3014a6SFabio M. De Francesco
247*6c3014a6SFabio M. De Francesco dst_ptr = kmap_local_page(*dst_page) + src;
248*6c3014a6SFabio M. De Francesco src_ptr = kmap_local_page(*src_page) + src;
249*6c3014a6SFabio M. De Francesco memmove(dst_ptr, src_ptr, l);
250*6c3014a6SFabio M. De Francesco kunmap_local(src_ptr);
2511da177e4SLinus Torvalds set_page_dirty(*dst_page);
252*6c3014a6SFabio M. De Francesco kunmap_local(dst_ptr);
2531da177e4SLinus Torvalds
2541da177e4SLinus Torvalds while ((len -= l) != 0) {
25509cbfeafSKirill A. Shutemov l = min_t(int, len, PAGE_SIZE);
256*6c3014a6SFabio M. De Francesco dst_ptr = kmap_local_page(*++dst_page);
257*6c3014a6SFabio M. De Francesco src_ptr = kmap_local_page(*++src_page);
258*6c3014a6SFabio M. De Francesco memmove(dst_ptr, src_ptr, l);
259*6c3014a6SFabio M. De Francesco kunmap_local(src_ptr);
2601da177e4SLinus Torvalds set_page_dirty(*dst_page);
261*6c3014a6SFabio M. De Francesco kunmap_local(dst_ptr);
2621da177e4SLinus Torvalds }
2631da177e4SLinus Torvalds } else {
2641da177e4SLinus Torvalds do {
265*6c3014a6SFabio M. De Francesco dst_ptr = kmap_local_page(*dst_page) + dst;
266*6c3014a6SFabio M. De Francesco src_ptr = kmap_local_page(*src_page) + src;
26709cbfeafSKirill A. Shutemov if (PAGE_SIZE - src <
26809cbfeafSKirill A. Shutemov PAGE_SIZE - dst) {
26909cbfeafSKirill A. Shutemov l = PAGE_SIZE - src;
2701da177e4SLinus Torvalds src = 0;
2711da177e4SLinus Torvalds dst += l;
2721da177e4SLinus Torvalds } else {
27309cbfeafSKirill A. Shutemov l = PAGE_SIZE - dst;
2741da177e4SLinus Torvalds src += l;
2751da177e4SLinus Torvalds dst = 0;
2761da177e4SLinus Torvalds }
2771da177e4SLinus Torvalds l = min(len, l);
2781da177e4SLinus Torvalds memmove(dst_ptr, src_ptr, l);
279*6c3014a6SFabio M. De Francesco kunmap_local(src_ptr);
2801da177e4SLinus Torvalds set_page_dirty(*dst_page);
281*6c3014a6SFabio M. De Francesco kunmap_local(dst_ptr);
2821da177e4SLinus Torvalds if (!dst)
2831da177e4SLinus Torvalds dst_page++;
2841da177e4SLinus Torvalds else
2851da177e4SLinus Torvalds src_page++;
2861da177e4SLinus Torvalds } while ((len -= l));
2871da177e4SLinus Torvalds }
2881da177e4SLinus Torvalds }
2891da177e4SLinus Torvalds }
2901da177e4SLinus Torvalds
hfs_bnode_dump(struct hfs_bnode * node)2911da177e4SLinus Torvalds void hfs_bnode_dump(struct hfs_bnode *node)
2921da177e4SLinus Torvalds {
2931da177e4SLinus Torvalds struct hfs_bnode_desc desc;
2941da177e4SLinus Torvalds __be32 cnid;
2951da177e4SLinus Torvalds int i, off, key_off;
2961da177e4SLinus Torvalds
297c2b3e1f7SJoe Perches hfs_dbg(BNODE_MOD, "bnode: %d\n", node->this);
2981da177e4SLinus Torvalds hfs_bnode_read(node, &desc, 0, sizeof(desc));
299c2b3e1f7SJoe Perches hfs_dbg(BNODE_MOD, "%d, %d, %d, %d, %d\n",
3001da177e4SLinus Torvalds be32_to_cpu(desc.next), be32_to_cpu(desc.prev),
3011da177e4SLinus Torvalds desc.type, desc.height, be16_to_cpu(desc.num_recs));
3021da177e4SLinus Torvalds
3031da177e4SLinus Torvalds off = node->tree->node_size - 2;
3041da177e4SLinus Torvalds for (i = be16_to_cpu(desc.num_recs); i >= 0; off -= 2, i--) {
3051da177e4SLinus Torvalds key_off = hfs_bnode_read_u16(node, off);
306c2b3e1f7SJoe Perches hfs_dbg(BNODE_MOD, " %d", key_off);
3071da177e4SLinus Torvalds if (i && node->type == HFS_NODE_INDEX) {
3081da177e4SLinus Torvalds int tmp;
3091da177e4SLinus Torvalds
310324ef39aSVyacheslav Dubeyko if (node->tree->attributes & HFS_TREE_VARIDXKEYS ||
311324ef39aSVyacheslav Dubeyko node->tree->cnid == HFSPLUS_ATTR_CNID)
3121da177e4SLinus Torvalds tmp = hfs_bnode_read_u16(node, key_off) + 2;
3131da177e4SLinus Torvalds else
3141da177e4SLinus Torvalds tmp = node->tree->max_key_len + 2;
315c2b3e1f7SJoe Perches hfs_dbg_cont(BNODE_MOD, " (%d", tmp);
3161da177e4SLinus Torvalds hfs_bnode_read(node, &cnid, key_off + tmp, 4);
317c2b3e1f7SJoe Perches hfs_dbg_cont(BNODE_MOD, ",%d)", be32_to_cpu(cnid));
3181da177e4SLinus Torvalds } else if (i && node->type == HFS_NODE_LEAF) {
3191da177e4SLinus Torvalds int tmp;
3201da177e4SLinus Torvalds
3211da177e4SLinus Torvalds tmp = hfs_bnode_read_u16(node, key_off);
322c2b3e1f7SJoe Perches hfs_dbg_cont(BNODE_MOD, " (%d)", tmp);
3231da177e4SLinus Torvalds }
3241da177e4SLinus Torvalds }
325c2b3e1f7SJoe Perches hfs_dbg_cont(BNODE_MOD, "\n");
3261da177e4SLinus Torvalds }
3271da177e4SLinus Torvalds
hfs_bnode_unlink(struct hfs_bnode * node)3281da177e4SLinus Torvalds void hfs_bnode_unlink(struct hfs_bnode *node)
3291da177e4SLinus Torvalds {
3301da177e4SLinus Torvalds struct hfs_btree *tree;
3311da177e4SLinus Torvalds struct hfs_bnode *tmp;
3321da177e4SLinus Torvalds __be32 cnid;
3331da177e4SLinus Torvalds
3341da177e4SLinus Torvalds tree = node->tree;
3351da177e4SLinus Torvalds if (node->prev) {
3361da177e4SLinus Torvalds tmp = hfs_bnode_find(tree, node->prev);
3371da177e4SLinus Torvalds if (IS_ERR(tmp))
3381da177e4SLinus Torvalds return;
3391da177e4SLinus Torvalds tmp->next = node->next;
3401da177e4SLinus Torvalds cnid = cpu_to_be32(tmp->next);
3412753cc28SAnton Salikhmetov hfs_bnode_write(tmp, &cnid,
3422753cc28SAnton Salikhmetov offsetof(struct hfs_bnode_desc, next), 4);
3431da177e4SLinus Torvalds hfs_bnode_put(tmp);
3441da177e4SLinus Torvalds } else if (node->type == HFS_NODE_LEAF)
3451da177e4SLinus Torvalds tree->leaf_head = node->next;
3461da177e4SLinus Torvalds
3471da177e4SLinus Torvalds if (node->next) {
3481da177e4SLinus Torvalds tmp = hfs_bnode_find(tree, node->next);
3491da177e4SLinus Torvalds if (IS_ERR(tmp))
3501da177e4SLinus Torvalds return;
3511da177e4SLinus Torvalds tmp->prev = node->prev;
3521da177e4SLinus Torvalds cnid = cpu_to_be32(tmp->prev);
3532753cc28SAnton Salikhmetov hfs_bnode_write(tmp, &cnid,
3542753cc28SAnton Salikhmetov offsetof(struct hfs_bnode_desc, prev), 4);
3551da177e4SLinus Torvalds hfs_bnode_put(tmp);
3561da177e4SLinus Torvalds } else if (node->type == HFS_NODE_LEAF)
3571da177e4SLinus Torvalds tree->leaf_tail = node->prev;
3581da177e4SLinus Torvalds
35921f2296aSAnton Salikhmetov /* move down? */
360b2837fcfSAnton Salikhmetov if (!node->prev && !node->next)
361c2b3e1f7SJoe Perches hfs_dbg(BNODE_MOD, "hfs_btree_del_level\n");
3621da177e4SLinus Torvalds if (!node->parent) {
3631da177e4SLinus Torvalds tree->root = 0;
3641da177e4SLinus Torvalds tree->depth = 0;
3651da177e4SLinus Torvalds }
3661da177e4SLinus Torvalds set_bit(HFS_BNODE_DELETED, &node->flags);
3671da177e4SLinus Torvalds }
3681da177e4SLinus Torvalds
hfs_bnode_hash(u32 num)3691da177e4SLinus Torvalds static inline int hfs_bnode_hash(u32 num)
3701da177e4SLinus Torvalds {
3711da177e4SLinus Torvalds num = (num >> 16) + num;
3721da177e4SLinus Torvalds num += num >> 8;
3731da177e4SLinus Torvalds return num & (NODE_HASH_SIZE - 1);
3741da177e4SLinus Torvalds }
3751da177e4SLinus Torvalds
hfs_bnode_findhash(struct hfs_btree * tree,u32 cnid)3761da177e4SLinus Torvalds struct hfs_bnode *hfs_bnode_findhash(struct hfs_btree *tree, u32 cnid)
3771da177e4SLinus Torvalds {
3781da177e4SLinus Torvalds struct hfs_bnode *node;
3791da177e4SLinus Torvalds
3801da177e4SLinus Torvalds if (cnid >= tree->node_count) {
381e46707d1SFabian Frederick pr_err("request for non-existent node %d in B*Tree\n",
3822753cc28SAnton Salikhmetov cnid);
3831da177e4SLinus Torvalds return NULL;
3841da177e4SLinus Torvalds }
3851da177e4SLinus Torvalds
3861da177e4SLinus Torvalds for (node = tree->node_hash[hfs_bnode_hash(cnid)];
387b2837fcfSAnton Salikhmetov node; node = node->next_hash)
388b2837fcfSAnton Salikhmetov if (node->this == cnid)
3891da177e4SLinus Torvalds return node;
3901da177e4SLinus Torvalds return NULL;
3911da177e4SLinus Torvalds }
3921da177e4SLinus Torvalds
__hfs_bnode_create(struct hfs_btree * tree,u32 cnid)3931da177e4SLinus Torvalds static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
3941da177e4SLinus Torvalds {
3951da177e4SLinus Torvalds struct hfs_bnode *node, *node2;
3961da177e4SLinus Torvalds struct address_space *mapping;
3971da177e4SLinus Torvalds struct page *page;
3981da177e4SLinus Torvalds int size, block, i, hash;
3991da177e4SLinus Torvalds loff_t off;
4001da177e4SLinus Torvalds
4011da177e4SLinus Torvalds if (cnid >= tree->node_count) {
402e46707d1SFabian Frederick pr_err("request for non-existent node %d in B*Tree\n",
4032753cc28SAnton Salikhmetov cnid);
4041da177e4SLinus Torvalds return NULL;
4051da177e4SLinus Torvalds }
4061da177e4SLinus Torvalds
4071da177e4SLinus Torvalds size = sizeof(struct hfs_bnode) + tree->pages_per_bnode *
4081da177e4SLinus Torvalds sizeof(struct page *);
409f8314dc6SPanagiotis Issaris node = kzalloc(size, GFP_KERNEL);
4101da177e4SLinus Torvalds if (!node)
4111da177e4SLinus Torvalds return NULL;
4121da177e4SLinus Torvalds node->tree = tree;
4131da177e4SLinus Torvalds node->this = cnid;
4141da177e4SLinus Torvalds set_bit(HFS_BNODE_NEW, &node->flags);
4151da177e4SLinus Torvalds atomic_set(&node->refcnt, 1);
416c2b3e1f7SJoe Perches hfs_dbg(BNODE_REFS, "new_node(%d:%d): 1\n",
4171da177e4SLinus Torvalds node->tree->cnid, node->this);
4181da177e4SLinus Torvalds init_waitqueue_head(&node->lock_wq);
4191da177e4SLinus Torvalds spin_lock(&tree->hash_lock);
4201da177e4SLinus Torvalds node2 = hfs_bnode_findhash(tree, cnid);
4211da177e4SLinus Torvalds if (!node2) {
4221da177e4SLinus Torvalds hash = hfs_bnode_hash(cnid);
4231da177e4SLinus Torvalds node->next_hash = tree->node_hash[hash];
4241da177e4SLinus Torvalds tree->node_hash[hash] = node;
4251da177e4SLinus Torvalds tree->node_hash_cnt++;
4261da177e4SLinus Torvalds } else {
4271da177e4SLinus Torvalds spin_unlock(&tree->hash_lock);
4281da177e4SLinus Torvalds kfree(node);
4292753cc28SAnton Salikhmetov wait_event(node2->lock_wq,
4302753cc28SAnton Salikhmetov !test_bit(HFS_BNODE_NEW, &node2->flags));
4311da177e4SLinus Torvalds return node2;
4321da177e4SLinus Torvalds }
4331da177e4SLinus Torvalds spin_unlock(&tree->hash_lock);
4341da177e4SLinus Torvalds
4351da177e4SLinus Torvalds mapping = tree->inode->i_mapping;
4361da177e4SLinus Torvalds off = (loff_t)cnid << tree->node_size_shift;
43709cbfeafSKirill A. Shutemov block = off >> PAGE_SHIFT;
43809cbfeafSKirill A. Shutemov node->page_offset = off & ~PAGE_MASK;
4391da177e4SLinus Torvalds for (i = 0; i < tree->pages_per_bnode; block++, i++) {
440090d2b18SPekka Enberg page = read_mapping_page(mapping, block, NULL);
4411da177e4SLinus Torvalds if (IS_ERR(page))
4421da177e4SLinus Torvalds goto fail;
4431da177e4SLinus Torvalds node->page[i] = page;
4441da177e4SLinus Torvalds }
4451da177e4SLinus Torvalds
4461da177e4SLinus Torvalds return node;
4471da177e4SLinus Torvalds fail:
4481da177e4SLinus Torvalds set_bit(HFS_BNODE_ERROR, &node->flags);
4491da177e4SLinus Torvalds return node;
4501da177e4SLinus Torvalds }
4511da177e4SLinus Torvalds
hfs_bnode_unhash(struct hfs_bnode * node)4521da177e4SLinus Torvalds void hfs_bnode_unhash(struct hfs_bnode *node)
4531da177e4SLinus Torvalds {
4541da177e4SLinus Torvalds struct hfs_bnode **p;
4551da177e4SLinus Torvalds
456c2b3e1f7SJoe Perches hfs_dbg(BNODE_REFS, "remove_node(%d:%d): %d\n",
4571da177e4SLinus Torvalds node->tree->cnid, node->this, atomic_read(&node->refcnt));
4581da177e4SLinus Torvalds for (p = &node->tree->node_hash[hfs_bnode_hash(node->this)];
4591da177e4SLinus Torvalds *p && *p != node; p = &(*p)->next_hash)
4601da177e4SLinus Torvalds ;
4610bf3ba53SEric Sesterhenn BUG_ON(!*p);
4621da177e4SLinus Torvalds *p = node->next_hash;
4631da177e4SLinus Torvalds node->tree->node_hash_cnt--;
4641da177e4SLinus Torvalds }
4651da177e4SLinus Torvalds
4661da177e4SLinus Torvalds /* Load a particular node out of a tree */
hfs_bnode_find(struct hfs_btree * tree,u32 num)4671da177e4SLinus Torvalds struct hfs_bnode *hfs_bnode_find(struct hfs_btree *tree, u32 num)
4681da177e4SLinus Torvalds {
4691da177e4SLinus Torvalds struct hfs_bnode *node;
4701da177e4SLinus Torvalds struct hfs_bnode_desc *desc;
4711da177e4SLinus Torvalds int i, rec_off, off, next_off;
4721da177e4SLinus Torvalds int entry_size, key_size;
4731da177e4SLinus Torvalds
4741da177e4SLinus Torvalds spin_lock(&tree->hash_lock);
4751da177e4SLinus Torvalds node = hfs_bnode_findhash(tree, num);
4761da177e4SLinus Torvalds if (node) {
4771da177e4SLinus Torvalds hfs_bnode_get(node);
4781da177e4SLinus Torvalds spin_unlock(&tree->hash_lock);
4792753cc28SAnton Salikhmetov wait_event(node->lock_wq,
4802753cc28SAnton Salikhmetov !test_bit(HFS_BNODE_NEW, &node->flags));
4811da177e4SLinus Torvalds if (test_bit(HFS_BNODE_ERROR, &node->flags))
4821da177e4SLinus Torvalds goto node_error;
4831da177e4SLinus Torvalds return node;
4841da177e4SLinus Torvalds }
4851da177e4SLinus Torvalds spin_unlock(&tree->hash_lock);
4861da177e4SLinus Torvalds node = __hfs_bnode_create(tree, num);
4871da177e4SLinus Torvalds if (!node)
4881da177e4SLinus Torvalds return ERR_PTR(-ENOMEM);
4891da177e4SLinus Torvalds if (test_bit(HFS_BNODE_ERROR, &node->flags))
4901da177e4SLinus Torvalds goto node_error;
4911da177e4SLinus Torvalds if (!test_bit(HFS_BNODE_NEW, &node->flags))
4921da177e4SLinus Torvalds return node;
4931da177e4SLinus Torvalds
494*6c3014a6SFabio M. De Francesco desc = (struct hfs_bnode_desc *)(kmap_local_page(node->page[0]) +
4952753cc28SAnton Salikhmetov node->page_offset);
4961da177e4SLinus Torvalds node->prev = be32_to_cpu(desc->prev);
4971da177e4SLinus Torvalds node->next = be32_to_cpu(desc->next);
4981da177e4SLinus Torvalds node->num_recs = be16_to_cpu(desc->num_recs);
4991da177e4SLinus Torvalds node->type = desc->type;
5001da177e4SLinus Torvalds node->height = desc->height;
501*6c3014a6SFabio M. De Francesco kunmap_local(desc);
5021da177e4SLinus Torvalds
5031da177e4SLinus Torvalds switch (node->type) {
5041da177e4SLinus Torvalds case HFS_NODE_HEADER:
5051da177e4SLinus Torvalds case HFS_NODE_MAP:
5061da177e4SLinus Torvalds if (node->height != 0)
5071da177e4SLinus Torvalds goto node_error;
5081da177e4SLinus Torvalds break;
5091da177e4SLinus Torvalds case HFS_NODE_LEAF:
5101da177e4SLinus Torvalds if (node->height != 1)
5111da177e4SLinus Torvalds goto node_error;
5121da177e4SLinus Torvalds break;
5131da177e4SLinus Torvalds case HFS_NODE_INDEX:
5141da177e4SLinus Torvalds if (node->height <= 1 || node->height > tree->depth)
5151da177e4SLinus Torvalds goto node_error;
5161da177e4SLinus Torvalds break;
5171da177e4SLinus Torvalds default:
5181da177e4SLinus Torvalds goto node_error;
5191da177e4SLinus Torvalds }
5201da177e4SLinus Torvalds
5211da177e4SLinus Torvalds rec_off = tree->node_size - 2;
5221da177e4SLinus Torvalds off = hfs_bnode_read_u16(node, rec_off);
5231da177e4SLinus Torvalds if (off != sizeof(struct hfs_bnode_desc))
5241da177e4SLinus Torvalds goto node_error;
5251da177e4SLinus Torvalds for (i = 1; i <= node->num_recs; off = next_off, i++) {
5261da177e4SLinus Torvalds rec_off -= 2;
5271da177e4SLinus Torvalds next_off = hfs_bnode_read_u16(node, rec_off);
5281da177e4SLinus Torvalds if (next_off <= off ||
5291da177e4SLinus Torvalds next_off > tree->node_size ||
5301da177e4SLinus Torvalds next_off & 1)
5311da177e4SLinus Torvalds goto node_error;
5321da177e4SLinus Torvalds entry_size = next_off - off;
5331da177e4SLinus Torvalds if (node->type != HFS_NODE_INDEX &&
5341da177e4SLinus Torvalds node->type != HFS_NODE_LEAF)
5351da177e4SLinus Torvalds continue;
5361da177e4SLinus Torvalds key_size = hfs_bnode_read_u16(node, off) + 2;
5371da177e4SLinus Torvalds if (key_size >= entry_size || key_size & 1)
5381da177e4SLinus Torvalds goto node_error;
5391da177e4SLinus Torvalds }
5401da177e4SLinus Torvalds clear_bit(HFS_BNODE_NEW, &node->flags);
5411da177e4SLinus Torvalds wake_up(&node->lock_wq);
5421da177e4SLinus Torvalds return node;
5431da177e4SLinus Torvalds
5441da177e4SLinus Torvalds node_error:
5451da177e4SLinus Torvalds set_bit(HFS_BNODE_ERROR, &node->flags);
5461da177e4SLinus Torvalds clear_bit(HFS_BNODE_NEW, &node->flags);
5471da177e4SLinus Torvalds wake_up(&node->lock_wq);
5481da177e4SLinus Torvalds hfs_bnode_put(node);
5491da177e4SLinus Torvalds return ERR_PTR(-EIO);
5501da177e4SLinus Torvalds }
5511da177e4SLinus Torvalds
hfs_bnode_free(struct hfs_bnode * node)5521da177e4SLinus Torvalds void hfs_bnode_free(struct hfs_bnode *node)
5531da177e4SLinus Torvalds {
55421f2296aSAnton Salikhmetov int i;
5551da177e4SLinus Torvalds
55621f2296aSAnton Salikhmetov for (i = 0; i < node->tree->pages_per_bnode; i++)
55721f2296aSAnton Salikhmetov if (node->page[i])
55809cbfeafSKirill A. Shutemov put_page(node->page[i]);
5591da177e4SLinus Torvalds kfree(node);
5601da177e4SLinus Torvalds }
5611da177e4SLinus Torvalds
hfs_bnode_create(struct hfs_btree * tree,u32 num)5621da177e4SLinus Torvalds struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num)
5631da177e4SLinus Torvalds {
5641da177e4SLinus Torvalds struct hfs_bnode *node;
5651da177e4SLinus Torvalds struct page **pagep;
5661da177e4SLinus Torvalds int i;
5671da177e4SLinus Torvalds
5681da177e4SLinus Torvalds spin_lock(&tree->hash_lock);
5691da177e4SLinus Torvalds node = hfs_bnode_findhash(tree, num);
5701da177e4SLinus Torvalds spin_unlock(&tree->hash_lock);
5711da177e4SLinus Torvalds if (node) {
572d6142673SJoe Perches pr_crit("new node %u already hashed?\n", num);
573634725a9SRoman Zippel WARN_ON(1);
574634725a9SRoman Zippel return node;
5751da177e4SLinus Torvalds }
5761da177e4SLinus Torvalds node = __hfs_bnode_create(tree, num);
5771da177e4SLinus Torvalds if (!node)
5781da177e4SLinus Torvalds return ERR_PTR(-ENOMEM);
5791da177e4SLinus Torvalds if (test_bit(HFS_BNODE_ERROR, &node->flags)) {
5801da177e4SLinus Torvalds hfs_bnode_put(node);
5811da177e4SLinus Torvalds return ERR_PTR(-EIO);
5821da177e4SLinus Torvalds }
5831da177e4SLinus Torvalds
5841da177e4SLinus Torvalds pagep = node->page;
585*6c3014a6SFabio M. De Francesco memzero_page(*pagep, node->page_offset,
58609cbfeafSKirill A. Shutemov min_t(int, PAGE_SIZE, tree->node_size));
5871da177e4SLinus Torvalds set_page_dirty(*pagep);
5881da177e4SLinus Torvalds for (i = 1; i < tree->pages_per_bnode; i++) {
589*6c3014a6SFabio M. De Francesco memzero_page(*++pagep, 0, PAGE_SIZE);
5901da177e4SLinus Torvalds set_page_dirty(*pagep);
5911da177e4SLinus Torvalds }
5921da177e4SLinus Torvalds clear_bit(HFS_BNODE_NEW, &node->flags);
5931da177e4SLinus Torvalds wake_up(&node->lock_wq);
5941da177e4SLinus Torvalds
5951da177e4SLinus Torvalds return node;
5961da177e4SLinus Torvalds }
5971da177e4SLinus Torvalds
hfs_bnode_get(struct hfs_bnode * node)5981da177e4SLinus Torvalds void hfs_bnode_get(struct hfs_bnode *node)
5991da177e4SLinus Torvalds {
6001da177e4SLinus Torvalds if (node) {
6011da177e4SLinus Torvalds atomic_inc(&node->refcnt);
602c2b3e1f7SJoe Perches hfs_dbg(BNODE_REFS, "get_node(%d:%d): %d\n",
6032753cc28SAnton Salikhmetov node->tree->cnid, node->this,
6042753cc28SAnton Salikhmetov atomic_read(&node->refcnt));
6051da177e4SLinus Torvalds }
6061da177e4SLinus Torvalds }
6071da177e4SLinus Torvalds
6081da177e4SLinus Torvalds /* Dispose of resources used by a node */
hfs_bnode_put(struct hfs_bnode * node)6091da177e4SLinus Torvalds void hfs_bnode_put(struct hfs_bnode *node)
6101da177e4SLinus Torvalds {
6111da177e4SLinus Torvalds if (node) {
6121da177e4SLinus Torvalds struct hfs_btree *tree = node->tree;
6131da177e4SLinus Torvalds int i;
6141da177e4SLinus Torvalds
615c2b3e1f7SJoe Perches hfs_dbg(BNODE_REFS, "put_node(%d:%d): %d\n",
6162753cc28SAnton Salikhmetov node->tree->cnid, node->this,
6172753cc28SAnton Salikhmetov atomic_read(&node->refcnt));
6180bf3ba53SEric Sesterhenn BUG_ON(!atomic_read(&node->refcnt));
619a5e3985fSRoman Zippel if (!atomic_dec_and_lock(&node->refcnt, &tree->hash_lock))
6201da177e4SLinus Torvalds return;
6211da177e4SLinus Torvalds for (i = 0; i < tree->pages_per_bnode; i++) {
62274f9c9c2SRoman Zippel if (!node->page[i])
62374f9c9c2SRoman Zippel continue;
6241da177e4SLinus Torvalds mark_page_accessed(node->page[i]);
6251da177e4SLinus Torvalds }
6261da177e4SLinus Torvalds
6271da177e4SLinus Torvalds if (test_bit(HFS_BNODE_DELETED, &node->flags)) {
6281da177e4SLinus Torvalds hfs_bnode_unhash(node);
6291da177e4SLinus Torvalds spin_unlock(&tree->hash_lock);
6302cd282a1SSergei Antonov if (hfs_bnode_need_zeroout(tree))
6312cd282a1SSergei Antonov hfs_bnode_clear(node, 0, tree->node_size);
6321da177e4SLinus Torvalds hfs_bmap_free(node);
6331da177e4SLinus Torvalds hfs_bnode_free(node);
6341da177e4SLinus Torvalds return;
6351da177e4SLinus Torvalds }
6361da177e4SLinus Torvalds spin_unlock(&tree->hash_lock);
6371da177e4SLinus Torvalds }
6381da177e4SLinus Torvalds }
6391da177e4SLinus Torvalds
6402cd282a1SSergei Antonov /*
6412cd282a1SSergei Antonov * Unused nodes have to be zeroed if this is the catalog tree and
6422cd282a1SSergei Antonov * a corresponding flag in the volume header is set.
6432cd282a1SSergei Antonov */
hfs_bnode_need_zeroout(struct hfs_btree * tree)6442cd282a1SSergei Antonov bool hfs_bnode_need_zeroout(struct hfs_btree *tree)
6452cd282a1SSergei Antonov {
6462cd282a1SSergei Antonov struct super_block *sb = tree->inode->i_sb;
6472cd282a1SSergei Antonov struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
6482cd282a1SSergei Antonov const u32 volume_attr = be32_to_cpu(sbi->s_vhdr->attributes);
6492cd282a1SSergei Antonov
6502cd282a1SSergei Antonov return tree->cnid == HFSPLUS_CAT_CNID &&
6512cd282a1SSergei Antonov volume_attr & HFSPLUS_VOL_UNUSED_NODE_FIX;
6522cd282a1SSergei Antonov }
653