Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba1f9db9 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hch/hfsplus:
  hfsplus: ensure bio requests are not smaller than the hardware sectors
  hfsplus: Add additional range check to handle on-disk corruptions
  hfsplus: Add error propagation for hfsplus_ext_write_extent_locked
  hfsplus: add error checking for hfs_find_init()
  hfsplus: lift the 2TB size limit
  hfsplus: fix overflow in hfsplus_read_wrapper
  hfsplus: fix overflow in hfsplus_get_block
  hfsplus: assignments inside `if' condition clean-up
parents 49302baa 6596528e
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -43,6 +43,10 @@ u16 hfs_brec_keylen(struct hfs_bnode *node, u16 rec)
			node->tree->node_size - (rec + 1) * 2);
		if (!recoff)
			return 0;
		if (recoff > node->tree->node_size - 2) {
			printk(KERN_ERR "hfs: recoff %d too large\n", recoff);
			return 0;
		}

		retval = hfs_bnode_read_u16(node, recoff) + 2;
		if (retval > node->tree->max_key_len + 2) {
+10 −4
Original line number Diff line number Diff line
@@ -212,7 +212,9 @@ int hfsplus_create_cat(u32 cnid, struct inode *dir,

	dprint(DBG_CAT_MOD, "create_cat: %s,%u(%d)\n",
		str->name, cnid, inode->i_nlink);
	hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
	err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
	if (err)
		return err;

	hfsplus_cat_build_key(sb, fd.search_key, cnid, NULL);
	entry_size = hfsplus_fill_cat_thread(sb, &entry,
@@ -269,7 +271,9 @@ int hfsplus_delete_cat(u32 cnid, struct inode *dir, struct qstr *str)

	dprint(DBG_CAT_MOD, "delete_cat: %s,%u\n",
		str ? str->name : NULL, cnid);
	hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
	err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
	if (err)
		return err;

	if (!str) {
		int len;
@@ -347,12 +351,14 @@ int hfsplus_rename_cat(u32 cnid,
	struct hfs_find_data src_fd, dst_fd;
	hfsplus_cat_entry entry;
	int entry_size, type;
	int err = 0;
	int err;

	dprint(DBG_CAT_MOD, "rename_cat: %u - %lu,%s - %lu,%s\n",
		cnid, src_dir->i_ino, src_name->name,
		dst_dir->i_ino, dst_name->name);
	hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd);
	err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &src_fd);
	if (err)
		return err;
	dst_fd = src_fd;

	/* find the old dir entry and read the data */
+6 −2
Original line number Diff line number Diff line
@@ -38,7 +38,9 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
	sb = dir->i_sb;

	dentry->d_fsdata = NULL;
	hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
	err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
	if (err)
		return ERR_PTR(err);
	hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name);
again:
	err = hfs_brec_read(&fd, &entry, sizeof(entry));
@@ -132,7 +134,9 @@ static int hfsplus_readdir(struct file *filp, void *dirent, filldir_t filldir)
	if (filp->f_pos >= inode->i_size)
		return 0;

	hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
	err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
	if (err)
		return err;
	hfsplus_cat_build_key(sb, fd.search_key, inode->i_ino, NULL);
	err = hfs_brec_find(&fd);
	if (err)
+36 −14
Original line number Diff line number Diff line
@@ -119,22 +119,31 @@ static void __hfsplus_ext_write_extent(struct inode *inode,
	set_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags);
}

static void hfsplus_ext_write_extent_locked(struct inode *inode)
static int hfsplus_ext_write_extent_locked(struct inode *inode)
{
	int res;

	if (HFSPLUS_I(inode)->extent_state & HFSPLUS_EXT_DIRTY) {
		struct hfs_find_data fd;

		hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
		res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
		if (res)
			return res;
		__hfsplus_ext_write_extent(inode, &fd);
		hfs_find_exit(&fd);
	}
	return 0;
}

void hfsplus_ext_write_extent(struct inode *inode)
int hfsplus_ext_write_extent(struct inode *inode)
{
	int res;

	mutex_lock(&HFSPLUS_I(inode)->extents_lock);
	hfsplus_ext_write_extent_locked(inode);
	res = hfsplus_ext_write_extent_locked(inode);
	mutex_unlock(&HFSPLUS_I(inode)->extents_lock);

	return res;
}

static inline int __hfsplus_ext_read_extent(struct hfs_find_data *fd,
@@ -194,9 +203,11 @@ static int hfsplus_ext_read_extent(struct inode *inode, u32 block)
	    block < hip->cached_start + hip->cached_blocks)
		return 0;

	hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
	res = hfs_find_init(HFSPLUS_SB(inode->i_sb)->ext_tree, &fd);
	if (!res) {
		res = __hfsplus_ext_cache_extent(&fd, inode, block);
		hfs_find_exit(&fd);
	}
	return res;
}

@@ -209,6 +220,7 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
	struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
	int res = -EIO;
	u32 ablock, dblock, mask;
	sector_t sector;
	int was_dirty = 0;
	int shift;

@@ -255,10 +267,12 @@ int hfsplus_get_block(struct inode *inode, sector_t iblock,
done:
	dprint(DBG_EXTENT, "get_block(%lu): %llu - %u\n",
		inode->i_ino, (long long)iblock, dblock);

	mask = (1 << sbi->fs_shift) - 1;
	map_bh(bh_result, sb,
		(dblock << sbi->fs_shift) + sbi->blockoffset +
			(iblock & mask));
	sector = ((sector_t)dblock << sbi->fs_shift) +
		  sbi->blockoffset + (iblock & mask);
	map_bh(bh_result, sb, sector);

	if (create) {
		set_buffer_new(bh_result);
		hip->phys_size += sb->s_blocksize;
@@ -371,7 +385,9 @@ int hfsplus_free_fork(struct super_block *sb, u32 cnid,
	if (total_blocks == blocks)
		return 0;

	hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
	res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
	if (res)
		return res;
	do {
		res = __hfsplus_ext_read_extent(&fd, ext_entry, cnid,
						total_blocks, type);
@@ -469,7 +485,9 @@ out:

insert_extent:
	dprint(DBG_EXTENT, "insert new extent\n");
	hfsplus_ext_write_extent_locked(inode);
	res = hfsplus_ext_write_extent_locked(inode);
	if (res)
		goto out;

	memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
	hip->cached_extents[0].start_block = cpu_to_be32(start);
@@ -500,7 +518,6 @@ void hfsplus_file_truncate(struct inode *inode)
		struct page *page;
		void *fsdata;
		u32 size = inode->i_size;
		int res;

		res = pagecache_write_begin(NULL, mapping, size, 0,
						AOP_FLAG_UNINTERRUPTIBLE,
@@ -523,7 +540,12 @@ void hfsplus_file_truncate(struct inode *inode)
		goto out;

	mutex_lock(&hip->extents_lock);
	hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
	res = hfs_find_init(HFSPLUS_SB(sb)->ext_tree, &fd);
	if (res) {
		mutex_unlock(&hip->extents_lock);
		/* XXX: We lack error handling of hfsplus_file_truncate() */
		return;
	}
	while (1) {
		if (alloc_cnt == hip->first_blocks) {
			hfsplus_free_extents(sb, hip->first_extents,
+15 −3
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@
#include <linux/fs.h>
#include <linux/mutex.h>
#include <linux/buffer_head.h>
#include <linux/blkdev.h>
#include "hfsplus_raw.h"

#define DBG_BNODE_REFS	0x00000001
@@ -110,7 +111,9 @@ struct hfsplus_vh;
struct hfs_btree;

struct hfsplus_sb_info {
	void *s_vhdr_buf;
	struct hfsplus_vh *s_vhdr;
	void *s_backup_vhdr_buf;
	struct hfsplus_vh *s_backup_vhdr;
	struct hfs_btree *ext_tree;
	struct hfs_btree *cat_tree;
@@ -258,6 +261,15 @@ struct hfsplus_readdir_data {
	struct hfsplus_cat_key key;
};

/*
 * Find minimum acceptible I/O size for an hfsplus sb.
 */
static inline unsigned short hfsplus_min_io_size(struct super_block *sb)
{
	return max_t(unsigned short, bdev_logical_block_size(sb->s_bdev),
		     HFSPLUS_SECTOR_SIZE);
}

#define hfs_btree_open hfsplus_btree_open
#define hfs_btree_close hfsplus_btree_close
#define hfs_btree_write hfsplus_btree_write
@@ -374,7 +386,7 @@ extern const struct file_operations hfsplus_dir_operations;

/* extents.c */
int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *);
void hfsplus_ext_write_extent(struct inode *);
int hfsplus_ext_write_extent(struct inode *);
int hfsplus_get_block(struct inode *, sector_t, struct buffer_head *, int);
int hfsplus_free_fork(struct super_block *, u32,
		struct hfsplus_fork_raw *, int);
@@ -436,8 +448,8 @@ int hfsplus_compare_dentry(const struct dentry *parent,
/* wrapper.c */
int hfsplus_read_wrapper(struct super_block *);
int hfs_part_find(struct super_block *, sector_t *, sector_t *);
int hfsplus_submit_bio(struct block_device *bdev, sector_t sector,
		void *data, int rw);
int hfsplus_submit_bio(struct super_block *sb, sector_t sector,
		void *buf, void **data, int rw);

/* time macros */
#define __hfsp_mt2ut(t)		(be32_to_cpu(t) - 2082844800U)
Loading