Skip to content

Commit

Permalink
Merge branch 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…git/hch/hfsplus

* 'for-next' of git://git.kernel.org/pub/scm/linux/kernel/git/hch/hfsplus: (29 commits)
  hfsplus: fix getxattr return value
  hfsplus: remove the unused hfsplus_kmap/hfsplus_kunmap helpers
  hfsplus: create correct initial catalog entries for device files
  hfsplus: remove superflous rootflags field in hfsplus_inode_info
  hfsplus: fix link corruption
  hfsplus: validate btree flags
  hfsplus: handle more on-disk corruptions without oopsing
  hfsplus: hfs_bnode_find() can fail, resulting in hfs_bnode_split() breakage
  hfsplus: fix oops on mount with corrupted btree extent records
  hfsplus: fix rename over directories
  hfsplus: convert tree_lock to mutex
  hfsplus: add missing extent locking in hfsplus_write_inode
  hfsplus: protect readdir against removals from open_dir_list
  hfsplus: use atomic bitops for the superblock flags
  hfsplus: add per-superblock lock for volume header updates
  hfsplus: remove the rsrc_inodes list
  hfsplus: do not cache and write next_alloc
  hfsplus: fix error handling in hfsplus_symlink
  hfsplus: merge mknod/mkdir/creat
  hfsplus: clean up hfsplus_write_inode
  ...
  • Loading branch information
Linus Torvalds committed Oct 21, 2010
2 parents f6f94e2 + 46bf36e commit 9f1ad09
Show file tree
Hide file tree
Showing 16 changed files with 765 additions and 649 deletions.
17 changes: 15 additions & 2 deletions fs/hfsplus/bfind.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ int hfs_find_init(struct hfs_btree *tree, struct hfs_find_data *fd)
fd->search_key = ptr;
fd->key = ptr + tree->max_key_len + 2;
dprint(DBG_BNODE_REFS, "find_init: %d (%p)\n", tree->cnid, __builtin_return_address(0));
down(&tree->tree_lock);
mutex_lock(&tree->tree_lock);
return 0;
}

Expand All @@ -32,7 +32,7 @@ void hfs_find_exit(struct hfs_find_data *fd)
hfs_bnode_put(fd->bnode);
kfree(fd->search_key);
dprint(DBG_BNODE_REFS, "find_exit: %d (%p)\n", fd->tree->cnid, __builtin_return_address(0));
up(&fd->tree->tree_lock);
mutex_unlock(&fd->tree->tree_lock);
fd->tree = NULL;
}

Expand All @@ -52,6 +52,10 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
rec = (e + b) / 2;
len = hfs_brec_lenoff(bnode, rec, &off);
keylen = hfs_brec_keylen(bnode, rec);
if (keylen == 0) {
res = -EINVAL;
goto fail;
}
hfs_bnode_read(bnode, fd->key, off, keylen);
cmpval = bnode->tree->keycmp(fd->key, fd->search_key);
if (!cmpval) {
Expand All @@ -67,6 +71,10 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
if (rec != e && e >= 0) {
len = hfs_brec_lenoff(bnode, e, &off);
keylen = hfs_brec_keylen(bnode, e);
if (keylen == 0) {
res = -EINVAL;
goto fail;
}
hfs_bnode_read(bnode, fd->key, off, keylen);
}
done:
Expand All @@ -75,6 +83,7 @@ int __hfs_brec_find(struct hfs_bnode *bnode, struct hfs_find_data *fd)
fd->keylength = keylen;
fd->entryoffset = off + keylen;
fd->entrylength = len - keylen;
fail:
return res;
}

Expand Down Expand Up @@ -198,6 +207,10 @@ int hfs_brec_goto(struct hfs_find_data *fd, int cnt)

len = hfs_brec_lenoff(bnode, fd->record, &off);
keylen = hfs_brec_keylen(bnode, fd->record);
if (keylen == 0) {
res = -EINVAL;
goto out;
}
fd->keyoffset = off;
fd->keylength = keylen;
fd->entryoffset = off + keylen;
Expand Down
20 changes: 11 additions & 9 deletions fs/hfsplus/bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *max)
{
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
struct page *page;
struct address_space *mapping;
__be32 *pptr, *curr, *end;
Expand All @@ -29,8 +30,8 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *ma
return size;

dprint(DBG_BITMAP, "block_allocate: %u,%u,%u\n", size, offset, len);
mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex);
mapping = HFSPLUS_SB(sb).alloc_file->i_mapping;
mutex_lock(&sbi->alloc_mutex);
mapping = sbi->alloc_file->i_mapping;
page = read_mapping_page(mapping, offset / PAGE_CACHE_BITS, NULL);
if (IS_ERR(page)) {
start = size;
Expand Down Expand Up @@ -150,16 +151,17 @@ int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset, u32 *ma
set_page_dirty(page);
kunmap(page);
*max = offset + (curr - pptr) * 32 + i - start;
HFSPLUS_SB(sb).free_blocks -= *max;
sbi->free_blocks -= *max;
sb->s_dirt = 1;
dprint(DBG_BITMAP, "-> %u,%u\n", start, *max);
out:
mutex_unlock(&HFSPLUS_SB(sb).alloc_file->i_mutex);
mutex_unlock(&sbi->alloc_mutex);
return start;
}

int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count)
{
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
struct page *page;
struct address_space *mapping;
__be32 *pptr, *curr, *end;
Expand All @@ -172,11 +174,11 @@ int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count)

dprint(DBG_BITMAP, "block_free: %u,%u\n", offset, count);
/* are all of the bits in range? */
if ((offset + count) > HFSPLUS_SB(sb).total_blocks)
if ((offset + count) > sbi->total_blocks)
return -2;

mutex_lock(&HFSPLUS_SB(sb).alloc_file->i_mutex);
mapping = HFSPLUS_SB(sb).alloc_file->i_mapping;
mutex_lock(&sbi->alloc_mutex);
mapping = sbi->alloc_file->i_mapping;
pnr = offset / PAGE_CACHE_BITS;
page = read_mapping_page(mapping, pnr, NULL);
pptr = kmap(page);
Expand Down Expand Up @@ -224,9 +226,9 @@ int hfsplus_block_free(struct super_block *sb, u32 offset, u32 count)
out:
set_page_dirty(page);
kunmap(page);
HFSPLUS_SB(sb).free_blocks += len;
sbi->free_blocks += len;
sb->s_dirt = 1;
mutex_unlock(&HFSPLUS_SB(sb).alloc_file->i_mutex);
mutex_unlock(&sbi->alloc_mutex);

return 0;
}
29 changes: 22 additions & 7 deletions fs/hfsplus/brec.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,13 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
recoff = hfs_bnode_read_u16(node, node->tree->node_size - (rec + 1) * 2);
if (!recoff)
return 0;
if (node->tree->attributes & HFS_TREE_BIGKEYS)
retval = hfs_bnode_read_u16(node, recoff) + 2;
else
retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1;

retval = hfs_bnode_read_u16(node, recoff) + 2;
if (retval > node->tree->max_key_len + 2) {
printk(KERN_ERR "hfs: keylen %d too large\n",
retval);
retval = 0;
}
}
return retval;
}
Expand Down Expand Up @@ -216,7 +219,7 @@ int hfs_brec_remove(struct hfs_find_data *fd)
static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
{
struct hfs_btree *tree;
struct hfs_bnode *node, *new_node;
struct hfs_bnode *node, *new_node, *next_node;
struct hfs_bnode_desc node_desc;
int num_recs, new_rec_off, new_off, old_rec_off;
int data_start, data_end, size;
Expand All @@ -235,6 +238,17 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
new_node->type = node->type;
new_node->height = node->height;

if (node->next)
next_node = hfs_bnode_find(tree, node->next);
else
next_node = NULL;

if (IS_ERR(next_node)) {
hfs_bnode_put(node);
hfs_bnode_put(new_node);
return next_node;
}

size = tree->node_size / 2 - node->num_recs * 2 - 14;
old_rec_off = tree->node_size - 4;
num_recs = 1;
Expand All @@ -248,6 +262,8 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
/* panic? */
hfs_bnode_put(node);
hfs_bnode_put(new_node);
if (next_node)
hfs_bnode_put(next_node);
return ERR_PTR(-ENOSPC);
}

Expand Down Expand Up @@ -302,8 +318,7 @@ static struct hfs_bnode *hfs_bnode_split(struct hfs_find_data *fd)
hfs_bnode_write(node, &node_desc, 0, sizeof(node_desc));

/* update next bnode header */
if (new_node->next) {
struct hfs_bnode *next_node = hfs_bnode_find(tree, new_node->next);
if (next_node) {
next_node->prev = new_node->this;
hfs_bnode_read(next_node, &node_desc, 0, sizeof(node_desc));
node_desc.prev = cpu_to_be32(next_node->prev);
Expand Down
67 changes: 52 additions & 15 deletions fs/hfsplus/btree.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
if (!tree)
return NULL;

init_MUTEX(&tree->tree_lock);
mutex_init(&tree->tree_lock);
spin_lock_init(&tree->hash_lock);
tree->sb = sb;
tree->cnid = id;
Expand All @@ -39,10 +39,16 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
goto free_tree;
tree->inode = inode;

if (!HFSPLUS_I(tree->inode)->first_blocks) {
printk(KERN_ERR
"hfs: invalid btree extent records (0 size).\n");
goto free_inode;
}

mapping = tree->inode->i_mapping;
page = read_mapping_page(mapping, 0, NULL);
if (IS_ERR(page))
goto free_tree;
goto free_inode;

/* Load the header */
head = (struct hfs_btree_header_rec *)(kmap(page) + sizeof(struct hfs_bnode_desc));
Expand All @@ -57,27 +63,56 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
tree->max_key_len = be16_to_cpu(head->max_key_len);
tree->depth = be16_to_cpu(head->depth);

/* Set the correct compare function */
if (id == HFSPLUS_EXT_CNID) {
/* Verify the tree and set the correct compare function */
switch (id) {
case HFSPLUS_EXT_CNID:
if (tree->max_key_len != HFSPLUS_EXT_KEYLEN - sizeof(u16)) {
printk(KERN_ERR "hfs: invalid extent max_key_len %d\n",
tree->max_key_len);
goto fail_page;
}
if (tree->attributes & HFS_TREE_VARIDXKEYS) {
printk(KERN_ERR "hfs: invalid extent btree flag\n");
goto fail_page;
}

tree->keycmp = hfsplus_ext_cmp_key;
} else if (id == HFSPLUS_CAT_CNID) {
if ((HFSPLUS_SB(sb).flags & HFSPLUS_SB_HFSX) &&
break;
case HFSPLUS_CAT_CNID:
if (tree->max_key_len != HFSPLUS_CAT_KEYLEN - sizeof(u16)) {
printk(KERN_ERR "hfs: invalid catalog max_key_len %d\n",
tree->max_key_len);
goto fail_page;
}
if (!(tree->attributes & HFS_TREE_VARIDXKEYS)) {
printk(KERN_ERR "hfs: invalid catalog btree flag\n");
goto fail_page;
}

if (test_bit(HFSPLUS_SB_HFSX, &HFSPLUS_SB(sb)->flags) &&
(head->key_type == HFSPLUS_KEY_BINARY))
tree->keycmp = hfsplus_cat_bin_cmp_key;
else {
tree->keycmp = hfsplus_cat_case_cmp_key;
HFSPLUS_SB(sb).flags |= HFSPLUS_SB_CASEFOLD;
set_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
}
} else {
break;
default:
printk(KERN_ERR "hfs: unknown B*Tree requested\n");
goto fail_page;
}

if (!(tree->attributes & HFS_TREE_BIGKEYS)) {
printk(KERN_ERR "hfs: invalid btree flag\n");
goto fail_page;
}

size = tree->node_size;
if (!is_power_of_2(size))
goto fail_page;
if (!tree->node_count)
goto fail_page;

tree->node_size_shift = ffs(size) - 1;

tree->pages_per_bnode = (tree->node_size + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
Expand All @@ -87,10 +122,11 @@ struct hfs_btree *hfs_btree_open(struct super_block *sb, u32 id)
return tree;

fail_page:
tree->inode->i_mapping->a_ops = &hfsplus_aops;
page_cache_release(page);
free_tree:
free_inode:
tree->inode->i_mapping->a_ops = &hfsplus_aops;
iput(tree->inode);
free_tree:
kfree(tree);
return NULL;
}
Expand Down Expand Up @@ -192,17 +228,18 @@ struct hfs_bnode *hfs_bmap_alloc(struct hfs_btree *tree)

while (!tree->free_nodes) {
struct inode *inode = tree->inode;
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
u32 count;
int res;

res = hfsplus_file_extend(inode);
if (res)
return ERR_PTR(res);
HFSPLUS_I(inode).phys_size = inode->i_size =
(loff_t)HFSPLUS_I(inode).alloc_blocks <<
HFSPLUS_SB(tree->sb).alloc_blksz_shift;
HFSPLUS_I(inode).fs_blocks = HFSPLUS_I(inode).alloc_blocks <<
HFSPLUS_SB(tree->sb).fs_shift;
hip->phys_size = inode->i_size =
(loff_t)hip->alloc_blocks <<
HFSPLUS_SB(tree->sb)->alloc_blksz_shift;
hip->fs_blocks =
hip->alloc_blocks << HFSPLUS_SB(tree->sb)->fs_shift;
inode_set_bytes(inode, inode->i_size);
count = inode->i_size >> tree->node_size_shift;
tree->free_nodes = count - tree->node_count;
Expand Down
Loading

0 comments on commit 9f1ad09

Please sign in to comment.