mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 12:21:22 -05:00
Merge tag 'hfs-v6.18-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs
Pull hfs updates from Viacheslav Dubeyko:
"This contains several fixes of syzbot reported issues, HFS/HFS+ fixes
of xfstests failures, and rework of HFS/HFS+ debug output subsystem.
- Kang Chen fixed a slab-out-of-bounds issue in hfsplus_uni2asc()
when hfsplus_uni2asc() is called from hfsplus_listxattr().
- Yang Chenzhi fixed a crash in hfsplus_bmap_alloc() if record offset
or length is larger than node_size.
- Yangtao Li corrected the error code from hfsplus_fill_super() if
Catalog File contains corrupted record for the case of hidden
directory's type.
- KMSAN uninit-value fixes: hfs_find_set_zero_bits() and
__hfsplus_ext_cache_extent() use kzalloc() instead of kmalloc(),
and in hfsplus_delete_cat() by proper initialization of struct
hfsplus_inode_info in the hfsplus_iget() logic.
- A slab-out-of-bounds issue could happen in hfsplus_strcasecmp() if
the length field of struct hfsplus_unistr is bigger than
HFSPLUS_MAX_STRLEN. Fixed by checking the length of comparing
strings, and if the strings' length is bigger than
HFSPLUS_MAX_STRLEN, then the length is corrected to this value.
- The generic/736 xfstest failed for HFS because the HFS volume
becomes corrupted after the test run.
The main reason was the absence of logic that corrects
mdb->drNxtCNID/HFS_SB(sb)->next_id (next unused CNID) after
deleting a record in Catalog File. That was fixed by implementing
the necessary logic in hfs_correct_next_unused_CNID()"
* tag 'hfs-v6.18-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs:
hfs/hfsplus: rework debug output subsystem
hfsplus: fix slab-out-of-bounds read in hfsplus_strcasecmp()
hfsplus: fix slab-out-of-bounds read in hfsplus_uni2asc()
hfs: clear offset and space out of valid records in b-tree node
hfs: add logic of correcting a next unused CNID
hfsplus: fix KMSAN uninit-value issue in hfsplus_delete_cat()
hfs: fix KMSAN uninit-value issue in hfs_find_set_zero_bits()
hfs: make proper initalization of struct hfs_find_data
hfsplus: fix KMSAN uninit-value issue in __hfsplus_ext_cache_extent()
hfs: validate record offset in hfsplus_bmap_alloc
hfsplus: return EIO when type of hidden directory mismatch in hfsplus_fill_super()
MAINTAINERS: update location of hfs&hfsplus trees
This commit is contained in:
@@ -10806,8 +10806,10 @@ M: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
|
||||
M: Yangtao Li <frank.li@vivo.com>
|
||||
L: linux-fsdevel@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs.git
|
||||
F: Documentation/filesystems/hfs.rst
|
||||
F: fs/hfs/
|
||||
F: include/linux/hfs_common.h
|
||||
|
||||
HFSPLUS FILESYSTEM
|
||||
M: Viacheslav Dubeyko <slava@dubeyko.com>
|
||||
@@ -10815,8 +10817,10 @@ M: John Paul Adrian Glaubitz <glaubitz@physik.fu-berlin.de>
|
||||
M: Yangtao Li <frank.li@vivo.com>
|
||||
L: linux-fsdevel@vger.kernel.org
|
||||
S: Maintained
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs.git
|
||||
F: Documentation/filesystems/hfsplus.rst
|
||||
F: fs/hfsplus/
|
||||
F: include/linux/hfs_common.h
|
||||
|
||||
HGA FRAMEBUFFER DRIVER
|
||||
M: Ferenc Bakonyi <fero@drama.obuda.kando.hu>
|
||||
|
||||
@@ -21,12 +21,12 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
|
||||
|
||||
fd->tree = tree;
|
||||
fd->bnode = NULL;
|
||||
ptr = kmalloc(tree->max_key_len * 2 + 4, GFP_KERNEL);
|
||||
ptr = kzalloc(tree->max_key_len * 2 + 4, GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
fd->search_key = ptr;
|
||||
fd->key = ptr + tree->max_key_len + 2;
|
||||
hfs_dbg(BNODE_REFS, "find_init: %d (%p)\n",
|
||||
hfs_dbg("cnid %d, caller %ps\n",
|
||||
tree->cnid, __builtin_return_address(0));
|
||||
switch (tree->cnid) {
|
||||
case HFS_CAT_CNID:
|
||||
@@ -48,7 +48,7 @@ void hfs_find_exit(struct hfs_find_data *fd)
|
||||
{
|
||||
hfs_bnode_put(fd->bnode);
|
||||
kfree(fd->search_key);
|
||||
hfs_dbg(BNODE_REFS, "find_exit: %d (%p)\n",
|
||||
hfs_dbg("cnid %d, caller %ps\n",
|
||||
fd->tree->cnid, __builtin_return_address(0));
|
||||
mutex_unlock(&fd->tree->tree_lock);
|
||||
fd->tree = NULL;
|
||||
@@ -115,6 +115,12 @@ int hfs_brec_find(struct hfs_find_data *fd)
|
||||
__be32 data;
|
||||
int height, res;
|
||||
|
||||
fd->record = -1;
|
||||
fd->keyoffset = -1;
|
||||
fd->keylength = -1;
|
||||
fd->entryoffset = -1;
|
||||
fd->entrylength = -1;
|
||||
|
||||
tree = fd->tree;
|
||||
if (fd->bnode)
|
||||
hfs_bnode_put(fd->bnode);
|
||||
|
||||
@@ -158,7 +158,7 @@ u32 hfs_vbm_search_free(struct super_block *sb, u32 goal, u32 *num_bits)
|
||||
}
|
||||
}
|
||||
|
||||
hfs_dbg(BITMAP, "alloc_bits: %u,%u\n", pos, *num_bits);
|
||||
hfs_dbg("pos %u, num_bits %u\n", pos, *num_bits);
|
||||
HFS_SB(sb)->free_ablocks -= *num_bits;
|
||||
hfs_bitmap_dirty(sb);
|
||||
out:
|
||||
@@ -200,7 +200,7 @@ int hfs_clear_vbm_bits(struct super_block *sb, u16 start, u16 count)
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
hfs_dbg(BITMAP, "clear_bits: %u,%u\n", start, count);
|
||||
hfs_dbg("start %u, count %u\n", start, count);
|
||||
/* are all of the bits in range? */
|
||||
if ((start + count) > HFS_SB(sb)->fs_ablocks)
|
||||
return -2;
|
||||
|
||||
@@ -200,7 +200,7 @@ void hfs_bnode_copy(struct hfs_bnode *dst_node, int dst,
|
||||
{
|
||||
struct page *src_page, *dst_page;
|
||||
|
||||
hfs_dbg(BNODE_MOD, "copybytes: %u,%u,%u\n", dst, src, len);
|
||||
hfs_dbg("dst %u, src %u, len %u\n", dst, src, len);
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
@@ -221,7 +221,7 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
|
||||
struct page *page;
|
||||
void *ptr;
|
||||
|
||||
hfs_dbg(BNODE_MOD, "movebytes: %u,%u,%u\n", dst, src, len);
|
||||
hfs_dbg("dst %u, src %u, len %u\n", dst, src, len);
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
@@ -243,16 +243,16 @@ void hfs_bnode_dump(struct hfs_bnode *node)
|
||||
__be32 cnid;
|
||||
int i, off, key_off;
|
||||
|
||||
hfs_dbg(BNODE_MOD, "bnode: %d\n", node->this);
|
||||
hfs_dbg("node %d\n", node->this);
|
||||
hfs_bnode_read(node, &desc, 0, sizeof(desc));
|
||||
hfs_dbg(BNODE_MOD, "%d, %d, %d, %d, %d\n",
|
||||
hfs_dbg("next %d, prev %d, type %d, height %d, num_recs %d\n",
|
||||
be32_to_cpu(desc.next), be32_to_cpu(desc.prev),
|
||||
desc.type, desc.height, be16_to_cpu(desc.num_recs));
|
||||
|
||||
off = node->tree->node_size - 2;
|
||||
for (i = be16_to_cpu(desc.num_recs); i >= 0; off -= 2, i--) {
|
||||
key_off = hfs_bnode_read_u16(node, off);
|
||||
hfs_dbg_cont(BNODE_MOD, " %d", key_off);
|
||||
hfs_dbg(" key_off %d", key_off);
|
||||
if (i && node->type == HFS_NODE_INDEX) {
|
||||
int tmp;
|
||||
|
||||
@@ -260,18 +260,18 @@ void hfs_bnode_dump(struct hfs_bnode *node)
|
||||
tmp = (hfs_bnode_read_u8(node, key_off) | 1) + 1;
|
||||
else
|
||||
tmp = node->tree->max_key_len + 1;
|
||||
hfs_dbg_cont(BNODE_MOD, " (%d,%d",
|
||||
tmp, hfs_bnode_read_u8(node, key_off));
|
||||
hfs_dbg(" (%d,%d",
|
||||
tmp, hfs_bnode_read_u8(node, key_off));
|
||||
hfs_bnode_read(node, &cnid, key_off + tmp, 4);
|
||||
hfs_dbg_cont(BNODE_MOD, ",%d)", be32_to_cpu(cnid));
|
||||
hfs_dbg(", cnid %d)", be32_to_cpu(cnid));
|
||||
} else if (i && node->type == HFS_NODE_LEAF) {
|
||||
int tmp;
|
||||
|
||||
tmp = hfs_bnode_read_u8(node, key_off);
|
||||
hfs_dbg_cont(BNODE_MOD, " (%d)", tmp);
|
||||
hfs_dbg(" (%d)", tmp);
|
||||
}
|
||||
}
|
||||
hfs_dbg_cont(BNODE_MOD, "\n");
|
||||
hfs_dbg("\n");
|
||||
}
|
||||
|
||||
void hfs_bnode_unlink(struct hfs_bnode *node)
|
||||
@@ -361,7 +361,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
|
||||
node->this = cnid;
|
||||
set_bit(HFS_BNODE_NEW, &node->flags);
|
||||
atomic_set(&node->refcnt, 1);
|
||||
hfs_dbg(BNODE_REFS, "new_node(%d:%d): 1\n",
|
||||
hfs_dbg("cnid %d, node %d, refcnt 1\n",
|
||||
node->tree->cnid, node->this);
|
||||
init_waitqueue_head(&node->lock_wq);
|
||||
spin_lock(&tree->hash_lock);
|
||||
@@ -401,7 +401,7 @@ void hfs_bnode_unhash(struct hfs_bnode *node)
|
||||
{
|
||||
struct hfs_bnode **p;
|
||||
|
||||
hfs_dbg(BNODE_REFS, "remove_node(%d:%d): %d\n",
|
||||
hfs_dbg("cnid %d, node %d, refcnt %d\n",
|
||||
node->tree->cnid, node->this, atomic_read(&node->refcnt));
|
||||
for (p = &node->tree->node_hash[hfs_bnode_hash(node->this)];
|
||||
*p && *p != node; p = &(*p)->next_hash)
|
||||
@@ -546,7 +546,7 @@ void hfs_bnode_get(struct hfs_bnode *node)
|
||||
{
|
||||
if (node) {
|
||||
atomic_inc(&node->refcnt);
|
||||
hfs_dbg(BNODE_REFS, "get_node(%d:%d): %d\n",
|
||||
hfs_dbg("cnid %d, node %d, refcnt %d\n",
|
||||
node->tree->cnid, node->this,
|
||||
atomic_read(&node->refcnt));
|
||||
}
|
||||
@@ -559,7 +559,7 @@ void hfs_bnode_put(struct hfs_bnode *node)
|
||||
struct hfs_btree *tree = node->tree;
|
||||
int i;
|
||||
|
||||
hfs_dbg(BNODE_REFS, "put_node(%d:%d): %d\n",
|
||||
hfs_dbg("cnid %d, node %d, refcnt %d\n",
|
||||
node->tree->cnid, node->this,
|
||||
atomic_read(&node->refcnt));
|
||||
BUG_ON(!atomic_read(&node->refcnt));
|
||||
|
||||
@@ -94,7 +94,7 @@ int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
|
||||
end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
|
||||
end_off = hfs_bnode_read_u16(node, end_rec_off);
|
||||
end_rec_off -= 2;
|
||||
hfs_dbg(BNODE_MOD, "insert_rec: %d, %d, %d, %d\n",
|
||||
hfs_dbg("rec %d, size %d, end_off %d, end_rec_off %d\n",
|
||||
rec, size, end_off, end_rec_off);
|
||||
if (size > end_rec_off - end_off) {
|
||||
if (new_node)
|
||||
@@ -179,6 +179,7 @@ int hfs_brec_remove(struct hfs_find_data *fd)
|
||||
struct hfs_btree *tree;
|
||||
struct hfs_bnode *node, *parent;
|
||||
int end_off, rec_off, data_off, size;
|
||||
int src, dst, len;
|
||||
|
||||
tree = fd->tree;
|
||||
node = fd->bnode;
|
||||
@@ -191,7 +192,7 @@ int hfs_brec_remove(struct hfs_find_data *fd)
|
||||
mark_inode_dirty(tree->inode);
|
||||
}
|
||||
hfs_bnode_dump(node);
|
||||
hfs_dbg(BNODE_MOD, "remove_rec: %d, %d\n",
|
||||
hfs_dbg("rec %d, len %d\n",
|
||||
fd->record, fd->keylength + fd->entrylength);
|
||||
if (!--node->num_recs) {
|
||||
hfs_bnode_unlink(node);
|
||||
@@ -208,10 +209,14 @@ int hfs_brec_remove(struct hfs_find_data *fd)
|
||||
}
|
||||
hfs_bnode_write_u16(node, offsetof(struct hfs_bnode_desc, num_recs), node->num_recs);
|
||||
|
||||
if (rec_off == end_off)
|
||||
goto skip;
|
||||
size = fd->keylength + fd->entrylength;
|
||||
|
||||
if (rec_off == end_off) {
|
||||
src = fd->keyoffset;
|
||||
hfs_bnode_clear(node, src, size);
|
||||
goto skip;
|
||||
}
|
||||
|
||||
do {
|
||||
data_off = hfs_bnode_read_u16(node, rec_off);
|
||||
hfs_bnode_write_u16(node, rec_off + 2, data_off - size);
|
||||
@@ -219,9 +224,23 @@ int hfs_brec_remove(struct hfs_find_data *fd)
|
||||
} while (rec_off >= end_off);
|
||||
|
||||
/* fill hole */
|
||||
hfs_bnode_move(node, fd->keyoffset, fd->keyoffset + size,
|
||||
data_off - fd->keyoffset - size);
|
||||
dst = fd->keyoffset;
|
||||
src = fd->keyoffset + size;
|
||||
len = data_off - src;
|
||||
|
||||
hfs_bnode_move(node, dst, src, len);
|
||||
|
||||
src = dst + len;
|
||||
len = data_off - src;
|
||||
|
||||
hfs_bnode_clear(node, src, len);
|
||||
|
||||
skip:
|
||||
/*
|
||||
* Remove the obsolete offset to free space.
|
||||
*/
|
||||
hfs_bnode_write_u16(node, end_off, 0);
|
||||
|
||||
hfs_bnode_dump(node);
|
||||
if (!fd->record)
|
||||
hfs_brec_update_parent(fd);
|
||||
@@ -242,7 +261,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
|
||||
if (IS_ERR(new_node))
|
||||
return new_node;
|
||||
hfs_bnode_get(node);
|
||||
hfs_dbg(BNODE_MOD, "split_nodes: %d - %d - %d\n",
|
||||
hfs_dbg("this %d, new %d, next %d\n",
|
||||
node->this, new_node->this, node->next);
|
||||
new_node->next = node->next;
|
||||
new_node->prev = node->this;
|
||||
@@ -378,7 +397,7 @@ static int hfs_brec_update_parent(struct hfs_find_data *fd)
|
||||
newkeylen = (hfs_bnode_read_u8(node, 14) | 1) + 1;
|
||||
else
|
||||
fd->keylength = newkeylen = tree->max_key_len + 1;
|
||||
hfs_dbg(BNODE_MOD, "update_rec: %d, %d, %d\n",
|
||||
hfs_dbg("rec %d, keylength %d, newkeylen %d\n",
|
||||
rec, fd->keylength, newkeylen);
|
||||
|
||||
rec_off = tree->node_size - (rec + 2) * 2;
|
||||
|
||||
@@ -364,7 +364,7 @@ void hfs_bmap_free(struct hfs_bnode *node)
|
||||
u32 nidx;
|
||||
u8 *data, byte, m;
|
||||
|
||||
hfs_dbg(BNODE_MOD, "btree_free_node: %u\n", node->this);
|
||||
hfs_dbg("node %u\n", node->this);
|
||||
tree = node->tree;
|
||||
nidx = node->this;
|
||||
node = hfs_bnode_find(tree, 0);
|
||||
|
||||
129
fs/hfs/catalog.c
129
fs/hfs/catalog.c
@@ -87,7 +87,7 @@ int hfs_cat_create(u32 cnid, struct inode *dir, const struct qstr *str, struct i
|
||||
int entry_size;
|
||||
int err;
|
||||
|
||||
hfs_dbg(CAT_MOD, "create_cat: %s,%u(%d)\n",
|
||||
hfs_dbg("name %s, cnid %u, i_nlink %d\n",
|
||||
str->name, cnid, inode->i_nlink);
|
||||
if (dir->i_size >= HFS_MAX_VALENCE)
|
||||
return -ENOSPC;
|
||||
@@ -211,6 +211,124 @@ int hfs_cat_find_brec(struct super_block *sb, u32 cnid,
|
||||
return hfs_brec_find(fd);
|
||||
}
|
||||
|
||||
static inline
|
||||
void hfs_set_next_unused_CNID(struct super_block *sb,
|
||||
u32 deleted_cnid, u32 found_cnid)
|
||||
{
|
||||
if (found_cnid < HFS_FIRSTUSER_CNID) {
|
||||
atomic64_cmpxchg(&HFS_SB(sb)->next_id,
|
||||
deleted_cnid + 1, HFS_FIRSTUSER_CNID);
|
||||
} else {
|
||||
atomic64_cmpxchg(&HFS_SB(sb)->next_id,
|
||||
deleted_cnid + 1, found_cnid + 1);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* hfs_correct_next_unused_CNID()
|
||||
*
|
||||
* Correct the next unused CNID of Catalog Tree.
|
||||
*/
|
||||
static
|
||||
int hfs_correct_next_unused_CNID(struct super_block *sb, u32 cnid)
|
||||
{
|
||||
struct hfs_btree *cat_tree;
|
||||
struct hfs_bnode *node;
|
||||
s64 leaf_head;
|
||||
s64 leaf_tail;
|
||||
s64 node_id;
|
||||
|
||||
hfs_dbg("cnid %u, next_id %lld\n",
|
||||
cnid, atomic64_read(&HFS_SB(sb)->next_id));
|
||||
|
||||
if ((cnid + 1) < atomic64_read(&HFS_SB(sb)->next_id)) {
|
||||
/* next ID should be unchanged */
|
||||
return 0;
|
||||
}
|
||||
|
||||
cat_tree = HFS_SB(sb)->cat_tree;
|
||||
leaf_head = cat_tree->leaf_head;
|
||||
leaf_tail = cat_tree->leaf_tail;
|
||||
|
||||
if (leaf_head > leaf_tail) {
|
||||
pr_err("node is corrupted: leaf_head %lld, leaf_tail %lld\n",
|
||||
leaf_head, leaf_tail);
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
node = hfs_bnode_find(cat_tree, leaf_tail);
|
||||
if (IS_ERR(node)) {
|
||||
pr_err("fail to find leaf node: node ID %lld\n",
|
||||
leaf_tail);
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
node_id = leaf_tail;
|
||||
|
||||
do {
|
||||
int i;
|
||||
|
||||
if (node_id != leaf_tail) {
|
||||
node = hfs_bnode_find(cat_tree, node_id);
|
||||
if (IS_ERR(node))
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
hfs_dbg("node %lld, leaf_tail %lld, leaf_head %lld\n",
|
||||
node_id, leaf_tail, leaf_head);
|
||||
|
||||
hfs_bnode_dump(node);
|
||||
|
||||
for (i = node->num_recs - 1; i >= 0; i--) {
|
||||
hfs_cat_rec rec;
|
||||
u16 off, len, keylen;
|
||||
int entryoffset;
|
||||
int entrylength;
|
||||
u32 found_cnid;
|
||||
|
||||
len = hfs_brec_lenoff(node, i, &off);
|
||||
keylen = hfs_brec_keylen(node, i);
|
||||
if (keylen == 0) {
|
||||
pr_err("fail to get the keylen: "
|
||||
"node_id %lld, record index %d\n",
|
||||
node_id, i);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
entryoffset = off + keylen;
|
||||
entrylength = len - keylen;
|
||||
|
||||
if (entrylength > sizeof(rec)) {
|
||||
pr_err("unexpected record length: "
|
||||
"entrylength %d\n",
|
||||
entrylength);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
hfs_bnode_read(node, &rec, entryoffset, entrylength);
|
||||
|
||||
if (rec.type == HFS_CDR_DIR) {
|
||||
found_cnid = be32_to_cpu(rec.dir.DirID);
|
||||
hfs_dbg("found_cnid %u\n", found_cnid);
|
||||
hfs_set_next_unused_CNID(sb, cnid, found_cnid);
|
||||
hfs_bnode_put(node);
|
||||
return 0;
|
||||
} else if (rec.type == HFS_CDR_FIL) {
|
||||
found_cnid = be32_to_cpu(rec.file.FlNum);
|
||||
hfs_dbg("found_cnid %u\n", found_cnid);
|
||||
hfs_set_next_unused_CNID(sb, cnid, found_cnid);
|
||||
hfs_bnode_put(node);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
hfs_bnode_put(node);
|
||||
|
||||
node_id = node->prev;
|
||||
} while (node_id >= leaf_head);
|
||||
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
/*
|
||||
* hfs_cat_delete()
|
||||
@@ -225,7 +343,7 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, const struct qstr *str)
|
||||
struct hfs_readdir_data *rd;
|
||||
int res, type;
|
||||
|
||||
hfs_dbg(CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid);
|
||||
hfs_dbg("name %s, cnid %u\n", str ? str->name : NULL, cnid);
|
||||
sb = dir->i_sb;
|
||||
res = hfs_find_init(HFS_SB(sb)->cat_tree, &fd);
|
||||
if (res)
|
||||
@@ -271,6 +389,11 @@ int hfs_cat_delete(u32 cnid, struct inode *dir, const struct qstr *str)
|
||||
dir->i_size--;
|
||||
inode_set_mtime_to_ts(dir, inode_set_ctime_current(dir));
|
||||
mark_inode_dirty(dir);
|
||||
|
||||
res = hfs_correct_next_unused_CNID(sb, cnid);
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
res = 0;
|
||||
out:
|
||||
hfs_find_exit(&fd);
|
||||
@@ -294,7 +417,7 @@ int hfs_cat_move(u32 cnid, struct inode *src_dir, const struct qstr *src_name,
|
||||
int entry_size, type;
|
||||
int err;
|
||||
|
||||
hfs_dbg(CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n",
|
||||
hfs_dbg("cnid %u - (ino %lu, name %s) - (ino %lu, name %s)\n",
|
||||
cnid, src_dir->i_ino, src_name->name,
|
||||
dst_dir->i_ino, dst_name->name);
|
||||
sb = src_dir->i_sb;
|
||||
|
||||
@@ -209,12 +209,12 @@ static void hfs_dump_extent(struct hfs_extent *extent)
|
||||
{
|
||||
int i;
|
||||
|
||||
hfs_dbg(EXTENT, " ");
|
||||
hfs_dbg("extent: ");
|
||||
for (i = 0; i < 3; i++)
|
||||
hfs_dbg_cont(EXTENT, " %u:%u",
|
||||
be16_to_cpu(extent[i].block),
|
||||
be16_to_cpu(extent[i].count));
|
||||
hfs_dbg_cont(EXTENT, "\n");
|
||||
hfs_dbg(" block %u, count %u",
|
||||
be16_to_cpu(extent[i].block),
|
||||
be16_to_cpu(extent[i].count));
|
||||
hfs_dbg("\n");
|
||||
}
|
||||
|
||||
static int hfs_add_extent(struct hfs_extent *extent, u16 offset,
|
||||
@@ -411,10 +411,11 @@ int hfs_extend_file(struct inode *inode)
|
||||
goto out;
|
||||
}
|
||||
|
||||
hfs_dbg(EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len);
|
||||
hfs_dbg("ino %lu, start %u, len %u\n", inode->i_ino, start, len);
|
||||
if (HFS_I(inode)->alloc_blocks == HFS_I(inode)->first_blocks) {
|
||||
if (!HFS_I(inode)->first_blocks) {
|
||||
hfs_dbg(EXTENT, "first extents\n");
|
||||
hfs_dbg("first_extent: start %u, len %u\n",
|
||||
start, len);
|
||||
/* no extents yet */
|
||||
HFS_I(inode)->first_extents[0].block = cpu_to_be16(start);
|
||||
HFS_I(inode)->first_extents[0].count = cpu_to_be16(len);
|
||||
@@ -456,7 +457,7 @@ int hfs_extend_file(struct inode *inode)
|
||||
return res;
|
||||
|
||||
insert_extent:
|
||||
hfs_dbg(EXTENT, "insert new extent\n");
|
||||
hfs_dbg("insert new extent\n");
|
||||
res = hfs_ext_write_extent(inode);
|
||||
if (res)
|
||||
goto out;
|
||||
@@ -481,7 +482,7 @@ void hfs_file_truncate(struct inode *inode)
|
||||
u32 size;
|
||||
int res;
|
||||
|
||||
hfs_dbg(INODE, "truncate: %lu, %Lu -> %Lu\n",
|
||||
hfs_dbg("ino %lu, phys_size %llu -> i_size %llu\n",
|
||||
inode->i_ino, (long long)HFS_I(inode)->phys_size,
|
||||
inode->i_size);
|
||||
if (inode->i_size > HFS_I(inode)->phys_size) {
|
||||
|
||||
@@ -9,12 +9,6 @@
|
||||
#ifndef _LINUX_HFS_FS_H
|
||||
#define _LINUX_HFS_FS_H
|
||||
|
||||
#ifdef pr_fmt
|
||||
#undef pr_fmt
|
||||
#endif
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/mutex.h>
|
||||
@@ -24,35 +18,10 @@
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/hfs_common.h>
|
||||
|
||||
#include "hfs.h"
|
||||
|
||||
#define DBG_BNODE_REFS 0x00000001
|
||||
#define DBG_BNODE_MOD 0x00000002
|
||||
#define DBG_CAT_MOD 0x00000004
|
||||
#define DBG_INODE 0x00000008
|
||||
#define DBG_SUPER 0x00000010
|
||||
#define DBG_EXTENT 0x00000020
|
||||
#define DBG_BITMAP 0x00000040
|
||||
|
||||
//#define DBG_MASK (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD|DBG_CAT_MOD|DBG_BITMAP)
|
||||
//#define DBG_MASK (DBG_BNODE_MOD|DBG_CAT_MOD|DBG_INODE)
|
||||
//#define DBG_MASK (DBG_CAT_MOD|DBG_BNODE_REFS|DBG_INODE|DBG_EXTENT)
|
||||
#define DBG_MASK (0)
|
||||
|
||||
#define hfs_dbg(flg, fmt, ...) \
|
||||
do { \
|
||||
if (DBG_##flg & DBG_MASK) \
|
||||
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define hfs_dbg_cont(flg, fmt, ...) \
|
||||
do { \
|
||||
if (DBG_##flg & DBG_MASK) \
|
||||
pr_cont(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
|
||||
/*
|
||||
* struct hfs_inode_info
|
||||
*
|
||||
@@ -112,13 +81,13 @@ struct hfs_sb_info {
|
||||
the extents b-tree */
|
||||
struct hfs_btree *cat_tree; /* Information about
|
||||
the catalog b-tree */
|
||||
u32 file_count; /* The number of
|
||||
atomic64_t file_count; /* The number of
|
||||
regular files in
|
||||
the filesystem */
|
||||
u32 folder_count; /* The number of
|
||||
atomic64_t folder_count; /* The number of
|
||||
directories in the
|
||||
filesystem */
|
||||
u32 next_id; /* The next available
|
||||
atomic64_t next_id; /* The next available
|
||||
file id number */
|
||||
u32 clumpablks; /* The number of allocation
|
||||
blocks to try to add when
|
||||
|
||||
@@ -183,6 +183,10 @@ struct inode *hfs_new_inode(struct inode *dir, const struct qstr *name, umode_t
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct inode *inode = new_inode(sb);
|
||||
s64 next_id;
|
||||
s64 file_count;
|
||||
s64 folder_count;
|
||||
|
||||
if (!inode)
|
||||
return NULL;
|
||||
|
||||
@@ -190,7 +194,9 @@ struct inode *hfs_new_inode(struct inode *dir, const struct qstr *name, umode_t
|
||||
INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list);
|
||||
spin_lock_init(&HFS_I(inode)->open_dir_lock);
|
||||
hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name);
|
||||
inode->i_ino = HFS_SB(sb)->next_id++;
|
||||
next_id = atomic64_inc_return(&HFS_SB(sb)->next_id);
|
||||
BUG_ON(next_id > U32_MAX);
|
||||
inode->i_ino = (u32)next_id;
|
||||
inode->i_mode = mode;
|
||||
inode->i_uid = current_fsuid();
|
||||
inode->i_gid = current_fsgid();
|
||||
@@ -202,7 +208,8 @@ struct inode *hfs_new_inode(struct inode *dir, const struct qstr *name, umode_t
|
||||
HFS_I(inode)->tz_secondswest = sys_tz.tz_minuteswest * 60;
|
||||
if (S_ISDIR(mode)) {
|
||||
inode->i_size = 2;
|
||||
HFS_SB(sb)->folder_count++;
|
||||
folder_count = atomic64_inc_return(&HFS_SB(sb)->folder_count);
|
||||
BUG_ON(folder_count > U32_MAX);
|
||||
if (dir->i_ino == HFS_ROOT_CNID)
|
||||
HFS_SB(sb)->root_dirs++;
|
||||
inode->i_op = &hfs_dir_inode_operations;
|
||||
@@ -211,7 +218,8 @@ struct inode *hfs_new_inode(struct inode *dir, const struct qstr *name, umode_t
|
||||
inode->i_mode &= ~HFS_SB(inode->i_sb)->s_dir_umask;
|
||||
} else if (S_ISREG(mode)) {
|
||||
HFS_I(inode)->clump_blocks = HFS_SB(sb)->clumpablks;
|
||||
HFS_SB(sb)->file_count++;
|
||||
file_count = atomic64_inc_return(&HFS_SB(sb)->file_count);
|
||||
BUG_ON(file_count > U32_MAX);
|
||||
if (dir->i_ino == HFS_ROOT_CNID)
|
||||
HFS_SB(sb)->root_files++;
|
||||
inode->i_op = &hfs_file_inode_operations;
|
||||
@@ -241,16 +249,19 @@ void hfs_delete_inode(struct inode *inode)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
|
||||
hfs_dbg(INODE, "delete_inode: %lu\n", inode->i_ino);
|
||||
hfs_dbg("ino %lu\n", inode->i_ino);
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
HFS_SB(sb)->folder_count--;
|
||||
BUG_ON(atomic64_read(&HFS_SB(sb)->folder_count) > U32_MAX);
|
||||
atomic64_dec(&HFS_SB(sb)->folder_count);
|
||||
if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID))
|
||||
HFS_SB(sb)->root_dirs--;
|
||||
set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
|
||||
hfs_mark_mdb_dirty(sb);
|
||||
return;
|
||||
}
|
||||
HFS_SB(sb)->file_count--;
|
||||
|
||||
BUG_ON(atomic64_read(&HFS_SB(sb)->file_count) > U32_MAX);
|
||||
atomic64_dec(&HFS_SB(sb)->file_count);
|
||||
if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID))
|
||||
HFS_SB(sb)->root_files--;
|
||||
if (S_ISREG(inode->i_mode)) {
|
||||
@@ -425,7 +436,7 @@ int hfs_write_inode(struct inode *inode, struct writeback_control *wbc)
|
||||
hfs_cat_rec rec;
|
||||
int res;
|
||||
|
||||
hfs_dbg(INODE, "hfs_write_inode: %lu\n", inode->i_ino);
|
||||
hfs_dbg("ino %lu\n", inode->i_ino);
|
||||
res = hfs_ext_write_extent(inode);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
20
fs/hfs/mdb.c
20
fs/hfs/mdb.c
@@ -150,11 +150,11 @@ int hfs_mdb_get(struct super_block *sb)
|
||||
|
||||
/* These parameters are read from and written to the MDB */
|
||||
HFS_SB(sb)->free_ablocks = be16_to_cpu(mdb->drFreeBks);
|
||||
HFS_SB(sb)->next_id = be32_to_cpu(mdb->drNxtCNID);
|
||||
atomic64_set(&HFS_SB(sb)->next_id, be32_to_cpu(mdb->drNxtCNID));
|
||||
HFS_SB(sb)->root_files = be16_to_cpu(mdb->drNmFls);
|
||||
HFS_SB(sb)->root_dirs = be16_to_cpu(mdb->drNmRtDirs);
|
||||
HFS_SB(sb)->file_count = be32_to_cpu(mdb->drFilCnt);
|
||||
HFS_SB(sb)->folder_count = be32_to_cpu(mdb->drDirCnt);
|
||||
atomic64_set(&HFS_SB(sb)->file_count, be32_to_cpu(mdb->drFilCnt));
|
||||
atomic64_set(&HFS_SB(sb)->folder_count, be32_to_cpu(mdb->drDirCnt));
|
||||
|
||||
/* TRY to get the alternate (backup) MDB. */
|
||||
sect = part_start + part_size - 2;
|
||||
@@ -172,7 +172,7 @@ int hfs_mdb_get(struct super_block *sb)
|
||||
pr_warn("continuing without an alternate MDB\n");
|
||||
}
|
||||
|
||||
HFS_SB(sb)->bitmap = kmalloc(8192, GFP_KERNEL);
|
||||
HFS_SB(sb)->bitmap = kzalloc(8192, GFP_KERNEL);
|
||||
if (!HFS_SB(sb)->bitmap)
|
||||
goto out;
|
||||
|
||||
@@ -273,11 +273,17 @@ void hfs_mdb_commit(struct super_block *sb)
|
||||
/* These parameters may have been modified, so write them back */
|
||||
mdb->drLsMod = hfs_mtime();
|
||||
mdb->drFreeBks = cpu_to_be16(HFS_SB(sb)->free_ablocks);
|
||||
mdb->drNxtCNID = cpu_to_be32(HFS_SB(sb)->next_id);
|
||||
BUG_ON(atomic64_read(&HFS_SB(sb)->next_id) > U32_MAX);
|
||||
mdb->drNxtCNID =
|
||||
cpu_to_be32((u32)atomic64_read(&HFS_SB(sb)->next_id));
|
||||
mdb->drNmFls = cpu_to_be16(HFS_SB(sb)->root_files);
|
||||
mdb->drNmRtDirs = cpu_to_be16(HFS_SB(sb)->root_dirs);
|
||||
mdb->drFilCnt = cpu_to_be32(HFS_SB(sb)->file_count);
|
||||
mdb->drDirCnt = cpu_to_be32(HFS_SB(sb)->folder_count);
|
||||
BUG_ON(atomic64_read(&HFS_SB(sb)->file_count) > U32_MAX);
|
||||
mdb->drFilCnt =
|
||||
cpu_to_be32((u32)atomic64_read(&HFS_SB(sb)->file_count));
|
||||
BUG_ON(atomic64_read(&HFS_SB(sb)->folder_count) > U32_MAX);
|
||||
mdb->drDirCnt =
|
||||
cpu_to_be32((u32)atomic64_read(&HFS_SB(sb)->folder_count));
|
||||
|
||||
/* write MDB to disk */
|
||||
mark_buffer_dirty(HFS_SB(sb)->mdb_bh);
|
||||
|
||||
@@ -319,6 +319,10 @@ static int hfs_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
int silent = fc->sb_flags & SB_SILENT;
|
||||
int res;
|
||||
|
||||
atomic64_set(&sbi->file_count, 0);
|
||||
atomic64_set(&sbi->folder_count, 0);
|
||||
atomic64_set(&sbi->next_id, 0);
|
||||
|
||||
/* load_nls_default does not fail */
|
||||
if (sbi->nls_disk && !sbi->nls_io)
|
||||
sbi->nls_io = load_nls_default();
|
||||
|
||||
@@ -139,7 +139,7 @@ int hfsplus_find_attr(struct super_block *sb, u32 cnid,
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
hfs_dbg(ATTR_MOD, "find_attr: %s,%d\n", name ? name : NULL, cnid);
|
||||
hfs_dbg("name %s, cnid %d\n", name ? name : NULL, cnid);
|
||||
|
||||
if (!HFSPLUS_SB(sb)->attr_tree) {
|
||||
pr_err("attributes file doesn't exist\n");
|
||||
@@ -201,7 +201,7 @@ int hfsplus_create_attr(struct inode *inode,
|
||||
int entry_size;
|
||||
int err;
|
||||
|
||||
hfs_dbg(ATTR_MOD, "create_attr: %s,%ld\n",
|
||||
hfs_dbg("name %s, ino %ld\n",
|
||||
name ? name : NULL, inode->i_ino);
|
||||
|
||||
if (!HFSPLUS_SB(sb)->attr_tree) {
|
||||
@@ -310,7 +310,7 @@ int hfsplus_delete_attr(struct inode *inode, const char *name)
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct hfs_find_data fd;
|
||||
|
||||
hfs_dbg(ATTR_MOD, "delete_attr: %s,%ld\n",
|
||||
hfs_dbg("name %s, ino %ld\n",
|
||||
name ? name : NULL, inode->i_ino);
|
||||
|
||||
if (!HFSPLUS_SB(sb)->attr_tree) {
|
||||
@@ -356,7 +356,7 @@ int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid)
|
||||
int err = 0;
|
||||
struct hfs_find_data fd;
|
||||
|
||||
hfs_dbg(ATTR_MOD, "delete_all_attrs: %d\n", cnid);
|
||||
hfs_dbg("cnid %d\n", cnid);
|
||||
|
||||
if (!HFSPLUS_SB(dir->i_sb)->attr_tree) {
|
||||
pr_err("attributes file doesn't exist\n");
|
||||
|
||||
@@ -18,12 +18,12 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
|
||||
|
||||
fd->tree = tree;
|
||||
fd->bnode = NULL;
|
||||
ptr = kmalloc(tree->max_key_len * 2 + 4, GFP_KERNEL);
|
||||
ptr = kzalloc(tree->max_key_len * 2 + 4, GFP_KERNEL);
|
||||
if (!ptr)
|
||||
return -ENOMEM;
|
||||
fd->search_key = ptr;
|
||||
fd->key = ptr + tree->max_key_len + 2;
|
||||
hfs_dbg(BNODE_REFS, "find_init: %d (%p)\n",
|
||||
hfs_dbg("cnid %d, caller %ps\n",
|
||||
tree->cnid, __builtin_return_address(0));
|
||||
mutex_lock_nested(&tree->tree_lock,
|
||||
hfsplus_btree_lock_class(tree));
|
||||
@@ -34,7 +34,7 @@ void hfs_find_exit(struct hfs_find_data *fd)
|
||||
{
|
||||
hfs_bnode_put(fd->bnode);
|
||||
kfree(fd->search_key);
|
||||
hfs_dbg(BNODE_REFS, "find_exit: %d (%p)\n",
|
||||
hfs_dbg("cnid %d, caller %ps\n",
|
||||
fd->tree->cnid, __builtin_return_address(0));
|
||||
mutex_unlock(&fd->tree->tree_lock);
|
||||
fd->tree = NULL;
|
||||
@@ -158,6 +158,12 @@ int hfs_brec_find(struct hfs_find_data *fd, search_strategy_t do_key_compare)
|
||||
__be32 data;
|
||||
int height, res;
|
||||
|
||||
fd->record = -1;
|
||||
fd->keyoffset = -1;
|
||||
fd->keylength = -1;
|
||||
fd->entryoffset = -1;
|
||||
fd->entrylength = -1;
|
||||
|
||||
tree = fd->tree;
|
||||
if (fd->bnode)
|
||||
hfs_bnode_put(fd->bnode);
|
||||
|
||||
@@ -31,7 +31,7 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size,
|
||||
if (!len)
|
||||
return size;
|
||||
|
||||
hfs_dbg(BITMAP, "block_allocate: %u,%u,%u\n", size, offset, len);
|
||||
hfs_dbg("size %u, offset %u, len %u\n", size, offset, len);
|
||||
mutex_lock(&sbi->alloc_mutex);
|
||||
mapping = sbi->alloc_file->i_mapping;
|
||||
page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL);
|
||||
@@ -90,14 +90,14 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size,
|
||||
else
|
||||
end = pptr + ((size + 31) & (PAGE_CACHE_BITS - 1)) / 32;
|
||||
}
|
||||
hfs_dbg(BITMAP, "bitmap full\n");
|
||||
hfs_dbg("bitmap full\n");
|
||||
start = size;
|
||||
goto out;
|
||||
|
||||
found:
|
||||
start = offset + (curr - pptr) * 32 + i;
|
||||
if (start >= size) {
|
||||
hfs_dbg(BITMAP, "bitmap full\n");
|
||||
hfs_dbg("bitmap full\n");
|
||||
goto out;
|
||||
}
|
||||
/* do any partial u32 at the start */
|
||||
@@ -155,7 +155,7 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size,
|
||||
*max = offset + (curr - pptr) * 32 + i - start;
|
||||
sbi->free_blocks -= *max;
|
||||
hfsplus_mark_mdb_dirty(sb);
|
||||
hfs_dbg(BITMAP, "-> %u,%u\n", start, *max);
|
||||
hfs_dbg("start %u, max %u\n", start, *max);
|
||||
out:
|
||||
mutex_unlock(&sbi->alloc_mutex);
|
||||
return start;
|
||||
@@ -174,7 +174,7 @@ int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count)
|
||||
if (!count)
|
||||
return 0;
|
||||
|
||||
hfs_dbg(BITMAP, "block_free: %u,%u\n", offset, count);
|
||||
hfs_dbg("offset %u, count %u\n", offset, count);
|
||||
/* are all of the bits in range? */
|
||||
if ((offset + count) > sbi->total_blocks)
|
||||
return -ENOENT;
|
||||
|
||||
@@ -18,47 +18,6 @@
|
||||
#include "hfsplus_fs.h"
|
||||
#include "hfsplus_raw.h"
|
||||
|
||||
static inline
|
||||
bool is_bnode_offset_valid(struct hfs_bnode *node, int off)
|
||||
{
|
||||
bool is_valid = off < node->tree->node_size;
|
||||
|
||||
if (!is_valid) {
|
||||
pr_err("requested invalid offset: "
|
||||
"NODE: id %u, type %#x, height %u, "
|
||||
"node_size %u, offset %d\n",
|
||||
node->this, node->type, node->height,
|
||||
node->tree->node_size, off);
|
||||
}
|
||||
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
static inline
|
||||
int check_and_correct_requested_length(struct hfs_bnode *node, int off, int len)
|
||||
{
|
||||
unsigned int node_size;
|
||||
|
||||
if (!is_bnode_offset_valid(node, off))
|
||||
return 0;
|
||||
|
||||
node_size = node->tree->node_size;
|
||||
|
||||
if ((off + len) > node_size) {
|
||||
int new_len = (int)node_size - off;
|
||||
|
||||
pr_err("requested length has been corrected: "
|
||||
"NODE: id %u, type %#x, height %u, "
|
||||
"node_size %u, offset %d, "
|
||||
"requested_len %d, corrected_len %d\n",
|
||||
node->this, node->type, node->height,
|
||||
node->tree->node_size, off, len, new_len);
|
||||
|
||||
return new_len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* Copy a specified range of bytes from the raw data of a node */
|
||||
void hfs_bnode_read(struct hfs_bnode *node, void *buf, int off, int len)
|
||||
@@ -214,7 +173,7 @@ void hfs_bnode_copy(struct hfs_bnode *dst_node, int dst,
|
||||
struct page **src_page, **dst_page;
|
||||
int l;
|
||||
|
||||
hfs_dbg(BNODE_MOD, "copybytes: %u,%u,%u\n", dst, src, len);
|
||||
hfs_dbg("dst %u, src %u, len %u\n", dst, src, len);
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
@@ -272,7 +231,7 @@ void hfs_bnode_move(struct hfs_bnode *node, int dst, int src, int len)
|
||||
void *src_ptr, *dst_ptr;
|
||||
int l;
|
||||
|
||||
hfs_dbg(BNODE_MOD, "movebytes: %u,%u,%u\n", dst, src, len);
|
||||
hfs_dbg("dst %u, src %u, len %u\n", dst, src, len);
|
||||
if (!len)
|
||||
return;
|
||||
|
||||
@@ -392,16 +351,16 @@ void hfs_bnode_dump(struct hfs_bnode *node)
|
||||
__be32 cnid;
|
||||
int i, off, key_off;
|
||||
|
||||
hfs_dbg(BNODE_MOD, "bnode: %d\n", node->this);
|
||||
hfs_dbg("node %d\n", node->this);
|
||||
hfs_bnode_read(node, &desc, 0, sizeof(desc));
|
||||
hfs_dbg(BNODE_MOD, "%d, %d, %d, %d, %d\n",
|
||||
hfs_dbg("next %d, prev %d, type %d, height %d, num_recs %d\n",
|
||||
be32_to_cpu(desc.next), be32_to_cpu(desc.prev),
|
||||
desc.type, desc.height, be16_to_cpu(desc.num_recs));
|
||||
|
||||
off = node->tree->node_size - 2;
|
||||
for (i = be16_to_cpu(desc.num_recs); i >= 0; off -= 2, i--) {
|
||||
key_off = hfs_bnode_read_u16(node, off);
|
||||
hfs_dbg(BNODE_MOD, " %d", key_off);
|
||||
hfs_dbg(" key_off %d", key_off);
|
||||
if (i && node->type == HFS_NODE_INDEX) {
|
||||
int tmp;
|
||||
|
||||
@@ -410,17 +369,17 @@ void hfs_bnode_dump(struct hfs_bnode *node)
|
||||
tmp = hfs_bnode_read_u16(node, key_off) + 2;
|
||||
else
|
||||
tmp = node->tree->max_key_len + 2;
|
||||
hfs_dbg_cont(BNODE_MOD, " (%d", tmp);
|
||||
hfs_dbg(" (%d", tmp);
|
||||
hfs_bnode_read(node, &cnid, key_off + tmp, 4);
|
||||
hfs_dbg_cont(BNODE_MOD, ",%d)", be32_to_cpu(cnid));
|
||||
hfs_dbg(", cnid %d)", be32_to_cpu(cnid));
|
||||
} else if (i && node->type == HFS_NODE_LEAF) {
|
||||
int tmp;
|
||||
|
||||
tmp = hfs_bnode_read_u16(node, key_off);
|
||||
hfs_dbg_cont(BNODE_MOD, " (%d)", tmp);
|
||||
hfs_dbg(" (%d)", tmp);
|
||||
}
|
||||
}
|
||||
hfs_dbg_cont(BNODE_MOD, "\n");
|
||||
hfs_dbg("\n");
|
||||
}
|
||||
|
||||
void hfs_bnode_unlink(struct hfs_bnode *node)
|
||||
@@ -456,7 +415,7 @@ void hfs_bnode_unlink(struct hfs_bnode *node)
|
||||
|
||||
/* move down? */
|
||||
if (!node->prev && !node->next)
|
||||
hfs_dbg(BNODE_MOD, "hfs_btree_del_level\n");
|
||||
hfs_dbg("btree delete level\n");
|
||||
if (!node->parent) {
|
||||
tree->root = 0;
|
||||
tree->depth = 0;
|
||||
@@ -511,7 +470,7 @@ static struct hfs_bnode *__hfs_bnode_create(struct hfs_btree *tree, u32 cnid)
|
||||
node->this = cnid;
|
||||
set_bit(HFS_BNODE_NEW, &node->flags);
|
||||
atomic_set(&node->refcnt, 1);
|
||||
hfs_dbg(BNODE_REFS, "new_node(%d:%d): 1\n",
|
||||
hfs_dbg("cnid %d, node %d, refcnt 1\n",
|
||||
node->tree->cnid, node->this);
|
||||
init_waitqueue_head(&node->lock_wq);
|
||||
spin_lock(&tree->hash_lock);
|
||||
@@ -551,7 +510,7 @@ void hfs_bnode_unhash(struct hfs_bnode *node)
|
||||
{
|
||||
struct hfs_bnode **p;
|
||||
|
||||
hfs_dbg(BNODE_REFS, "remove_node(%d:%d): %d\n",
|
||||
hfs_dbg("cnid %d, node %d, refcnt %d\n",
|
||||
node->tree->cnid, node->this, atomic_read(&node->refcnt));
|
||||
for (p = &node->tree->node_hash[hfs_bnode_hash(node->this)];
|
||||
*p && *p != node; p = &(*p)->next_hash)
|
||||
@@ -697,7 +656,7 @@ void hfs_bnode_get(struct hfs_bnode *node)
|
||||
{
|
||||
if (node) {
|
||||
atomic_inc(&node->refcnt);
|
||||
hfs_dbg(BNODE_REFS, "get_node(%d:%d): %d\n",
|
||||
hfs_dbg("cnid %d, node %d, refcnt %d\n",
|
||||
node->tree->cnid, node->this,
|
||||
atomic_read(&node->refcnt));
|
||||
}
|
||||
@@ -710,7 +669,7 @@ void hfs_bnode_put(struct hfs_bnode *node)
|
||||
struct hfs_btree *tree = node->tree;
|
||||
int i;
|
||||
|
||||
hfs_dbg(BNODE_REFS, "put_node(%d:%d): %d\n",
|
||||
hfs_dbg("cnid %d, node %d, refcnt %d\n",
|
||||
node->tree->cnid, node->this,
|
||||
atomic_read(&node->refcnt));
|
||||
BUG_ON(!atomic_read(&node->refcnt));
|
||||
|
||||
@@ -92,7 +92,7 @@ int hfs_brec_insert(struct hfs_find_data *fd, void *entry, int entry_len)
|
||||
end_rec_off = tree->node_size - (node->num_recs + 1) * 2;
|
||||
end_off = hfs_bnode_read_u16(node, end_rec_off);
|
||||
end_rec_off -= 2;
|
||||
hfs_dbg(BNODE_MOD, "insert_rec: %d, %d, %d, %d\n",
|
||||
hfs_dbg("rec %d, size %d, end_off %d, end_rec_off %d\n",
|
||||
rec, size, end_off, end_rec_off);
|
||||
if (size > end_rec_off - end_off) {
|
||||
if (new_node)
|
||||
@@ -193,7 +193,7 @@ int hfs_brec_remove(struct hfs_find_data *fd)
|
||||
mark_inode_dirty(tree->inode);
|
||||
}
|
||||
hfs_bnode_dump(node);
|
||||
hfs_dbg(BNODE_MOD, "remove_rec: %d, %d\n",
|
||||
hfs_dbg("rec %d, len %d\n",
|
||||
fd->record, fd->keylength + fd->entrylength);
|
||||
if (!--node->num_recs) {
|
||||
hfs_bnode_unlink(node);
|
||||
@@ -246,7 +246,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
|
||||
if (IS_ERR(new_node))
|
||||
return new_node;
|
||||
hfs_bnode_get(node);
|
||||
hfs_dbg(BNODE_MOD, "split_nodes: %d - %d - %d\n",
|
||||
hfs_dbg("this %d - new %d - next %d\n",
|
||||
node->this, new_node->this, node->next);
|
||||
new_node->next = node->next;
|
||||
new_node->prev = node->this;
|
||||
@@ -383,7 +383,7 @@ static int hfs_brec_update_parent(struct hfs_find_data *fd)
|
||||
newkeylen = hfs_bnode_read_u16(node, 14) + 2;
|
||||
else
|
||||
fd->keylength = newkeylen = tree->max_key_len + 2;
|
||||
hfs_dbg(BNODE_MOD, "update_rec: %d, %d, %d\n",
|
||||
hfs_dbg("rec %d, keylength %d, newkeylen %d\n",
|
||||
rec, fd->keylength, newkeylen);
|
||||
|
||||
rec_off = tree->node_size - (rec + 2) * 2;
|
||||
@@ -395,7 +395,7 @@ static int hfs_brec_update_parent(struct hfs_find_data *fd)
|
||||
end_off = hfs_bnode_read_u16(parent, end_rec_off);
|
||||
if (end_rec_off - end_off < diff) {
|
||||
|
||||
hfs_dbg(BNODE_MOD, "splitting index node\n");
|
||||
hfs_dbg("splitting index node\n");
|
||||
fd->bnode = parent;
|
||||
new_node = hfs_bnode_split(fd);
|
||||
if (IS_ERR(new_node))
|
||||
|
||||
@@ -393,6 +393,12 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
|
||||
len = hfs_brec_lenoff(node, 2, &off16);
|
||||
off = off16;
|
||||
|
||||
if (!is_bnode_offset_valid(node, off)) {
|
||||
hfs_bnode_put(node);
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
len = check_and_correct_requested_length(node, off, len);
|
||||
|
||||
off += node->page_offset;
|
||||
pagep = node->page + (off >> PAGE_SHIFT);
|
||||
data = kmap_local_page(*pagep);
|
||||
@@ -428,7 +434,7 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)
|
||||
kunmap_local(data);
|
||||
nidx = node->next;
|
||||
if (!nidx) {
|
||||
hfs_dbg(BNODE_MOD, "create new bmap node\n");
|
||||
hfs_dbg("create new bmap node\n");
|
||||
next_node = hfs_bmap_new_bmap(node, idx);
|
||||
} else
|
||||
next_node = hfs_bnode_find(tree, nidx);
|
||||
@@ -454,7 +460,7 @@ void hfs_bmap_free(struct hfs_bnode *node)
|
||||
u32 nidx;
|
||||
u8 *data, byte, m;
|
||||
|
||||
hfs_dbg(BNODE_MOD, "btree_free_node: %u\n", node->this);
|
||||
hfs_dbg("node %u\n", node->this);
|
||||
BUG_ON(!node->this);
|
||||
tree = node->tree;
|
||||
nidx = node->this;
|
||||
|
||||
@@ -259,7 +259,7 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir,
|
||||
int entry_size;
|
||||
int err;
|
||||
|
||||
hfs_dbg(CAT_MOD, "create_cat: %s,%u(%d)\n",
|
||||
hfs_dbg("name %s, cnid %u, i_nlink %d\n",
|
||||
str->name, cnid, inode->i_nlink);
|
||||
err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
|
||||
if (err)
|
||||
@@ -336,7 +336,7 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, const struct qstr *str)
|
||||
int err, off;
|
||||
u16 type;
|
||||
|
||||
hfs_dbg(CAT_MOD, "delete_cat: %s,%u\n", str ? str->name : NULL, cnid);
|
||||
hfs_dbg("name %s, cnid %u\n", str ? str->name : NULL, cnid);
|
||||
err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
|
||||
if (err)
|
||||
return err;
|
||||
@@ -441,7 +441,7 @@ int hfsplus_rename_cat(u32 cnid,
|
||||
int entry_size, type;
|
||||
int err;
|
||||
|
||||
hfs_dbg(CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n",
|
||||
hfs_dbg("cnid %u - ino %lu, name %s - ino %lu, name %s\n",
|
||||
cnid, src_dir->i_ino, src_name->name,
|
||||
dst_dir->i_ino, dst_name->name);
|
||||
err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd);
|
||||
|
||||
@@ -204,7 +204,7 @@ static int hfsplus_readdir(struct file *file, struct dir_context *ctx)
|
||||
fd.entrylength);
|
||||
type = be16_to_cpu(entry.type);
|
||||
len = NLS_MAX_CHARSET_SIZE * HFSPLUS_MAX_STRLEN;
|
||||
err = hfsplus_uni2asc(sb, &fd.key->cat.name, strbuf, &len);
|
||||
err = hfsplus_uni2asc_str(sb, &fd.key->cat.name, strbuf, &len);
|
||||
if (err)
|
||||
goto out;
|
||||
if (type == HFSPLUS_FOLDER) {
|
||||
|
||||
@@ -275,7 +275,7 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
|
||||
mutex_unlock(&hip->extents_lock);
|
||||
|
||||
done:
|
||||
hfs_dbg(EXTENT, "get_block(%lu): %llu - %u\n",
|
||||
hfs_dbg("ino %lu, iblock %llu - dblock %u\n",
|
||||
inode->i_ino, (long long)iblock, dblock);
|
||||
|
||||
mask = (1 << sbi->fs_shift) - 1;
|
||||
@@ -298,12 +298,12 @@ static void hfsplus_dump_extent(struct hfsplus_extent *extent)
|
||||
{
|
||||
int i;
|
||||
|
||||
hfs_dbg(EXTENT, " ");
|
||||
hfs_dbg("extent ");
|
||||
for (i = 0; i < 8; i++)
|
||||
hfs_dbg_cont(EXTENT, " %u:%u",
|
||||
be32_to_cpu(extent[i].start_block),
|
||||
be32_to_cpu(extent[i].block_count));
|
||||
hfs_dbg_cont(EXTENT, "\n");
|
||||
hfs_dbg(" start_block %u, block_count %u",
|
||||
be32_to_cpu(extent[i].start_block),
|
||||
be32_to_cpu(extent[i].block_count));
|
||||
hfs_dbg("\n");
|
||||
}
|
||||
|
||||
static int hfsplus_add_extent(struct hfsplus_extent *extent, u32 offset,
|
||||
@@ -359,8 +359,7 @@ static int hfsplus_free_extents(struct super_block *sb,
|
||||
if (count <= block_nr) {
|
||||
err = hfsplus_block_free(sb, start, count);
|
||||
if (err) {
|
||||
pr_err("can't free extent\n");
|
||||
hfs_dbg(EXTENT, " start: %u count: %u\n",
|
||||
pr_err("can't free extent: start %u, count %u\n",
|
||||
start, count);
|
||||
}
|
||||
extent->block_count = 0;
|
||||
@@ -370,8 +369,7 @@ static int hfsplus_free_extents(struct super_block *sb,
|
||||
count -= block_nr;
|
||||
err = hfsplus_block_free(sb, start + count, block_nr);
|
||||
if (err) {
|
||||
pr_err("can't free extent\n");
|
||||
hfs_dbg(EXTENT, " start: %u count: %u\n",
|
||||
pr_err("can't free extent: start %u, count %u\n",
|
||||
start, count);
|
||||
}
|
||||
extent->block_count = cpu_to_be32(count);
|
||||
@@ -478,11 +476,12 @@ int hfsplus_file_extend(struct inode *inode, bool zeroout)
|
||||
goto out;
|
||||
}
|
||||
|
||||
hfs_dbg(EXTENT, "extend %lu: %u,%u\n", inode->i_ino, start, len);
|
||||
hfs_dbg("ino %lu, start %u, len %u\n", inode->i_ino, start, len);
|
||||
|
||||
if (hip->alloc_blocks <= hip->first_blocks) {
|
||||
if (!hip->first_blocks) {
|
||||
hfs_dbg(EXTENT, "first extents\n");
|
||||
hfs_dbg("first_extent: start %u, len %u\n",
|
||||
start, len);
|
||||
/* no extents yet */
|
||||
hip->first_extents[0].start_block = cpu_to_be32(start);
|
||||
hip->first_extents[0].block_count = cpu_to_be32(len);
|
||||
@@ -521,7 +520,7 @@ int hfsplus_file_extend(struct inode *inode, bool zeroout)
|
||||
return res;
|
||||
|
||||
insert_extent:
|
||||
hfs_dbg(EXTENT, "insert new extent\n");
|
||||
hfs_dbg("insert new extent\n");
|
||||
res = hfsplus_ext_write_extent_locked(inode);
|
||||
if (res)
|
||||
goto out;
|
||||
@@ -546,7 +545,7 @@ void hfsplus_file_truncate(struct inode *inode)
|
||||
u32 alloc_cnt, blk_cnt, start;
|
||||
int res;
|
||||
|
||||
hfs_dbg(INODE, "truncate: %lu, %llu -> %llu\n",
|
||||
hfs_dbg("ino %lu, phys_size %llu -> i_size %llu\n",
|
||||
inode->i_ino, (long long)hip->phys_size, inode->i_size);
|
||||
|
||||
if (inode->i_size > hip->phys_size) {
|
||||
|
||||
@@ -11,47 +11,14 @@
|
||||
#ifndef _LINUX_HFSPLUS_FS_H
|
||||
#define _LINUX_HFSPLUS_FS_H
|
||||
|
||||
#ifdef pr_fmt
|
||||
#undef pr_fmt
|
||||
#endif
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/fs_context.h>
|
||||
#include <linux/hfs_common.h>
|
||||
#include "hfsplus_raw.h"
|
||||
|
||||
#define DBG_BNODE_REFS 0x00000001
|
||||
#define DBG_BNODE_MOD 0x00000002
|
||||
#define DBG_CAT_MOD 0x00000004
|
||||
#define DBG_INODE 0x00000008
|
||||
#define DBG_SUPER 0x00000010
|
||||
#define DBG_EXTENT 0x00000020
|
||||
#define DBG_BITMAP 0x00000040
|
||||
#define DBG_ATTR_MOD 0x00000080
|
||||
|
||||
#if 0
|
||||
#define DBG_MASK (DBG_EXTENT|DBG_INODE|DBG_BNODE_MOD)
|
||||
#define DBG_MASK (DBG_BNODE_MOD|DBG_CAT_MOD|DBG_INODE)
|
||||
#define DBG_MASK (DBG_CAT_MOD|DBG_BNODE_REFS|DBG_INODE|DBG_EXTENT)
|
||||
#endif
|
||||
#define DBG_MASK (0)
|
||||
|
||||
#define hfs_dbg(flg, fmt, ...) \
|
||||
do { \
|
||||
if (DBG_##flg & DBG_MASK) \
|
||||
printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define hfs_dbg_cont(flg, fmt, ...) \
|
||||
do { \
|
||||
if (DBG_##flg & DBG_MASK) \
|
||||
pr_cont(fmt, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
/* Runtime config options */
|
||||
#define HFSPLUS_DEF_CR_TYPE 0x3F3F3F3F /* '????' */
|
||||
|
||||
@@ -521,8 +488,12 @@ int hfsplus_strcasecmp(const struct hfsplus_unistr *s1,
|
||||
const struct hfsplus_unistr *s2);
|
||||
int hfsplus_strcmp(const struct hfsplus_unistr *s1,
|
||||
const struct hfsplus_unistr *s2);
|
||||
int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr,
|
||||
char *astr, int *len_p);
|
||||
int hfsplus_uni2asc_str(struct super_block *sb,
|
||||
const struct hfsplus_unistr *ustr, char *astr,
|
||||
int *len_p);
|
||||
int hfsplus_uni2asc_xattr_str(struct super_block *sb,
|
||||
const struct hfsplus_attr_unistr *ustr,
|
||||
char *astr, int *len_p);
|
||||
int hfsplus_asc2uni(struct super_block *sb, struct hfsplus_unistr *ustr,
|
||||
int max_unistr_len, const char *astr, int len);
|
||||
int hfsplus_hash_dentry(const struct dentry *dentry, struct qstr *str);
|
||||
@@ -577,6 +548,48 @@ hfsplus_btree_lock_class(struct hfs_btree *tree)
|
||||
return class;
|
||||
}
|
||||
|
||||
static inline
|
||||
bool is_bnode_offset_valid(struct hfs_bnode *node, int off)
|
||||
{
|
||||
bool is_valid = off < node->tree->node_size;
|
||||
|
||||
if (!is_valid) {
|
||||
pr_err("requested invalid offset: "
|
||||
"NODE: id %u, type %#x, height %u, "
|
||||
"node_size %u, offset %d\n",
|
||||
node->this, node->type, node->height,
|
||||
node->tree->node_size, off);
|
||||
}
|
||||
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
static inline
|
||||
int check_and_correct_requested_length(struct hfs_bnode *node, int off, int len)
|
||||
{
|
||||
unsigned int node_size;
|
||||
|
||||
if (!is_bnode_offset_valid(node, off))
|
||||
return 0;
|
||||
|
||||
node_size = node->tree->node_size;
|
||||
|
||||
if ((off + len) > node_size) {
|
||||
int new_len = (int)node_size - off;
|
||||
|
||||
pr_err("requested length has been corrected: "
|
||||
"NODE: id %u, type %#x, height %u, "
|
||||
"node_size %u, offset %d, "
|
||||
"requested_len %d, corrected_len %d\n",
|
||||
node->this, node->type, node->height,
|
||||
node->tree->node_size, off, len, new_len);
|
||||
|
||||
return new_len;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/* compatibility */
|
||||
#define hfsp_mt2ut(t) (struct timespec64){ .tv_sec = __hfsp_mt2ut(t) }
|
||||
#define hfsp_ut2mt(t) __hfsp_ut2mt((t).tv_sec)
|
||||
|
||||
@@ -68,13 +68,26 @@ struct inode *hfsplus_iget(struct super_block *sb, unsigned long ino)
|
||||
if (!(inode->i_state & I_NEW))
|
||||
return inode;
|
||||
|
||||
atomic_set(&HFSPLUS_I(inode)->opencnt, 0);
|
||||
HFSPLUS_I(inode)->first_blocks = 0;
|
||||
HFSPLUS_I(inode)->clump_blocks = 0;
|
||||
HFSPLUS_I(inode)->alloc_blocks = 0;
|
||||
HFSPLUS_I(inode)->cached_start = U32_MAX;
|
||||
HFSPLUS_I(inode)->cached_blocks = 0;
|
||||
memset(HFSPLUS_I(inode)->first_extents, 0, sizeof(hfsplus_extent_rec));
|
||||
memset(HFSPLUS_I(inode)->cached_extents, 0, sizeof(hfsplus_extent_rec));
|
||||
HFSPLUS_I(inode)->extent_state = 0;
|
||||
mutex_init(&HFSPLUS_I(inode)->extents_lock);
|
||||
HFSPLUS_I(inode)->rsrc_inode = NULL;
|
||||
HFSPLUS_I(inode)->create_date = 0;
|
||||
HFSPLUS_I(inode)->linkid = 0;
|
||||
HFSPLUS_I(inode)->flags = 0;
|
||||
HFSPLUS_I(inode)->fs_blocks = 0;
|
||||
HFSPLUS_I(inode)->userflags = 0;
|
||||
HFSPLUS_I(inode)->subfolders = 0;
|
||||
INIT_LIST_HEAD(&HFSPLUS_I(inode)->open_dir_list);
|
||||
spin_lock_init(&HFSPLUS_I(inode)->open_dir_lock);
|
||||
mutex_init(&HFSPLUS_I(inode)->extents_lock);
|
||||
HFSPLUS_I(inode)->flags = 0;
|
||||
HFSPLUS_I(inode)->extent_state = 0;
|
||||
HFSPLUS_I(inode)->rsrc_inode = NULL;
|
||||
atomic_set(&HFSPLUS_I(inode)->opencnt, 0);
|
||||
HFSPLUS_I(inode)->phys_size = 0;
|
||||
|
||||
if (inode->i_ino >= HFSPLUS_FIRSTUSER_CNID ||
|
||||
inode->i_ino == HFSPLUS_ROOT_CNID) {
|
||||
@@ -150,7 +163,7 @@ static int hfsplus_write_inode(struct inode *inode,
|
||||
{
|
||||
int err;
|
||||
|
||||
hfs_dbg(INODE, "hfsplus_write_inode: %lu\n", inode->i_ino);
|
||||
hfs_dbg("ino %lu\n", inode->i_ino);
|
||||
|
||||
err = hfsplus_ext_write_extent(inode);
|
||||
if (err)
|
||||
@@ -165,7 +178,7 @@ static int hfsplus_write_inode(struct inode *inode,
|
||||
|
||||
static void hfsplus_evict_inode(struct inode *inode)
|
||||
{
|
||||
hfs_dbg(INODE, "hfsplus_evict_inode: %lu\n", inode->i_ino);
|
||||
hfs_dbg("ino %lu\n", inode->i_ino);
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
clear_inode(inode);
|
||||
if (HFSPLUS_IS_RSRC(inode)) {
|
||||
@@ -184,7 +197,7 @@ static int hfsplus_sync_fs(struct super_block *sb, int wait)
|
||||
if (!wait)
|
||||
return 0;
|
||||
|
||||
hfs_dbg(SUPER, "hfsplus_sync_fs\n");
|
||||
hfs_dbg("starting...\n");
|
||||
|
||||
/*
|
||||
* Explicitly write out the special metadata inodes.
|
||||
@@ -215,6 +228,10 @@ static int hfsplus_sync_fs(struct super_block *sb, int wait)
|
||||
vhdr->folder_count = cpu_to_be32(sbi->folder_count);
|
||||
vhdr->file_count = cpu_to_be32(sbi->file_count);
|
||||
|
||||
hfs_dbg("free_blocks %u, next_cnid %u, folder_count %u, file_count %u\n",
|
||||
sbi->free_blocks, sbi->next_cnid,
|
||||
sbi->folder_count, sbi->file_count);
|
||||
|
||||
if (test_and_clear_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags)) {
|
||||
memcpy(sbi->s_backup_vhdr, sbi->s_vhdr, sizeof(*sbi->s_vhdr));
|
||||
write_backup = 1;
|
||||
@@ -240,6 +257,8 @@ static int hfsplus_sync_fs(struct super_block *sb, int wait)
|
||||
if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
|
||||
blkdev_issue_flush(sb->s_bdev);
|
||||
|
||||
hfs_dbg("finished: err %d\n", error);
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -288,7 +307,7 @@ static void hfsplus_put_super(struct super_block *sb)
|
||||
{
|
||||
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
|
||||
|
||||
hfs_dbg(SUPER, "hfsplus_put_super\n");
|
||||
hfs_dbg("starting...\n");
|
||||
|
||||
cancel_delayed_work_sync(&sbi->sync_work);
|
||||
|
||||
@@ -310,6 +329,8 @@ static void hfsplus_put_super(struct super_block *sb)
|
||||
kfree(sbi->s_vhdr_buf);
|
||||
kfree(sbi->s_backup_vhdr_buf);
|
||||
call_rcu(&sbi->rcu, delayed_free);
|
||||
|
||||
hfs_dbg("finished\n");
|
||||
}
|
||||
|
||||
static int hfsplus_statfs(struct dentry *dentry, struct kstatfs *buf)
|
||||
@@ -524,7 +545,7 @@ static int hfsplus_fill_super(struct super_block *sb, struct fs_context *fc)
|
||||
if (!hfs_brec_read(&fd, &entry, sizeof(entry))) {
|
||||
hfs_find_exit(&fd);
|
||||
if (entry.type != cpu_to_be16(HFSPLUS_FOLDER)) {
|
||||
err = -EINVAL;
|
||||
err = -EIO;
|
||||
goto out_put_root;
|
||||
}
|
||||
inode = hfsplus_iget(sb, be32_to_cpu(entry.folder.id));
|
||||
|
||||
@@ -40,6 +40,18 @@ int hfsplus_strcasecmp(const struct hfsplus_unistr *s1,
|
||||
p1 = s1->unicode;
|
||||
p2 = s2->unicode;
|
||||
|
||||
if (len1 > HFSPLUS_MAX_STRLEN) {
|
||||
len1 = HFSPLUS_MAX_STRLEN;
|
||||
pr_err("invalid length %u has been corrected to %d\n",
|
||||
be16_to_cpu(s1->length), len1);
|
||||
}
|
||||
|
||||
if (len2 > HFSPLUS_MAX_STRLEN) {
|
||||
len2 = HFSPLUS_MAX_STRLEN;
|
||||
pr_err("invalid length %u has been corrected to %d\n",
|
||||
be16_to_cpu(s2->length), len2);
|
||||
}
|
||||
|
||||
while (1) {
|
||||
c1 = c2 = 0;
|
||||
|
||||
@@ -74,6 +86,18 @@ int hfsplus_strcmp(const struct hfsplus_unistr *s1,
|
||||
p1 = s1->unicode;
|
||||
p2 = s2->unicode;
|
||||
|
||||
if (len1 > HFSPLUS_MAX_STRLEN) {
|
||||
len1 = HFSPLUS_MAX_STRLEN;
|
||||
pr_err("invalid length %u has been corrected to %d\n",
|
||||
be16_to_cpu(s1->length), len1);
|
||||
}
|
||||
|
||||
if (len2 > HFSPLUS_MAX_STRLEN) {
|
||||
len2 = HFSPLUS_MAX_STRLEN;
|
||||
pr_err("invalid length %u has been corrected to %d\n",
|
||||
be16_to_cpu(s2->length), len2);
|
||||
}
|
||||
|
||||
for (len = min(len1, len2); len > 0; len--) {
|
||||
c1 = be16_to_cpu(*p1);
|
||||
c2 = be16_to_cpu(*p2);
|
||||
@@ -119,9 +143,8 @@ static u16 *hfsplus_compose_lookup(u16 *p, u16 cc)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int hfsplus_uni2asc(struct super_block *sb,
|
||||
const struct hfsplus_unistr *ustr,
|
||||
char *astr, int *len_p)
|
||||
static int hfsplus_uni2asc(struct super_block *sb, const struct hfsplus_unistr *ustr,
|
||||
int max_len, char *astr, int *len_p)
|
||||
{
|
||||
const hfsplus_unichr *ip;
|
||||
struct nls_table *nls = HFSPLUS_SB(sb)->nls;
|
||||
@@ -134,8 +157,8 @@ int hfsplus_uni2asc(struct super_block *sb,
|
||||
ip = ustr->unicode;
|
||||
|
||||
ustrlen = be16_to_cpu(ustr->length);
|
||||
if (ustrlen > HFSPLUS_MAX_STRLEN) {
|
||||
ustrlen = HFSPLUS_MAX_STRLEN;
|
||||
if (ustrlen > max_len) {
|
||||
ustrlen = max_len;
|
||||
pr_err("invalid length %u has been corrected to %d\n",
|
||||
be16_to_cpu(ustr->length), ustrlen);
|
||||
}
|
||||
@@ -256,6 +279,21 @@ int hfsplus_uni2asc(struct super_block *sb,
|
||||
return res;
|
||||
}
|
||||
|
||||
inline int hfsplus_uni2asc_str(struct super_block *sb,
|
||||
const struct hfsplus_unistr *ustr, char *astr,
|
||||
int *len_p)
|
||||
{
|
||||
return hfsplus_uni2asc(sb, ustr, HFSPLUS_MAX_STRLEN, astr, len_p);
|
||||
}
|
||||
|
||||
inline int hfsplus_uni2asc_xattr_str(struct super_block *sb,
|
||||
const struct hfsplus_attr_unistr *ustr,
|
||||
char *astr, int *len_p)
|
||||
{
|
||||
return hfsplus_uni2asc(sb, (const struct hfsplus_unistr *)ustr,
|
||||
HFSPLUS_ATTR_MAX_STRLEN, astr, len_p);
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert one or more ASCII characters into a single unicode character.
|
||||
* Returns the number of ASCII characters corresponding to the unicode char.
|
||||
|
||||
@@ -64,7 +64,7 @@ static void hfsplus_init_header_node(struct inode *attr_file,
|
||||
u32 used_bmp_bytes;
|
||||
u64 tmp;
|
||||
|
||||
hfs_dbg(ATTR_MOD, "init_hdr_attr_file: clump %u, node_size %u\n",
|
||||
hfs_dbg("clump %u, node_size %u\n",
|
||||
clump_size, node_size);
|
||||
|
||||
/* The end of the node contains list of record offsets */
|
||||
@@ -132,7 +132,7 @@ static int hfsplus_create_attributes_file(struct super_block *sb)
|
||||
struct page *page;
|
||||
int old_state = HFSPLUS_EMPTY_ATTR_TREE;
|
||||
|
||||
hfs_dbg(ATTR_MOD, "create_attr_file: ino %d\n", HFSPLUS_ATTR_CNID);
|
||||
hfs_dbg("ino %d\n", HFSPLUS_ATTR_CNID);
|
||||
|
||||
check_attr_tree_state_again:
|
||||
switch (atomic_read(&sbi->attr_tree_state)) {
|
||||
@@ -735,9 +735,9 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||
goto end_listxattr;
|
||||
|
||||
xattr_name_len = NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN;
|
||||
if (hfsplus_uni2asc(inode->i_sb,
|
||||
(const struct hfsplus_unistr *)&fd.key->attr.key_name,
|
||||
strbuf, &xattr_name_len)) {
|
||||
if (hfsplus_uni2asc_xattr_str(inode->i_sb,
|
||||
&fd.key->attr.key_name, strbuf,
|
||||
&xattr_name_len)) {
|
||||
pr_err("unicode conversion failed\n");
|
||||
res = -EIO;
|
||||
goto end_listxattr;
|
||||
|
||||
20
include/linux/hfs_common.h
Normal file
20
include/linux/hfs_common.h
Normal file
@@ -0,0 +1,20 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* HFS/HFS+ common definitions, inline functions,
|
||||
* and shared functionality.
|
||||
*/
|
||||
|
||||
#ifndef _HFS_COMMON_H_
|
||||
#define _HFS_COMMON_H_
|
||||
|
||||
#ifdef pr_fmt
|
||||
#undef pr_fmt
|
||||
#endif
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#define hfs_dbg(fmt, ...) \
|
||||
pr_debug("pid %d:%s:%d %s(): " fmt, \
|
||||
current->pid, __FILE__, __LINE__, __func__, ##__VA_ARGS__) \
|
||||
|
||||
#endif /* _HFS_COMMON_H_ */
|
||||
Reference in New Issue
Block a user