* hfsplus updates
@ 2010-10-12 13:56 Christoph Hellwig
2010-10-12 13:56 ` hfsplus: fix oops on mount with corrupted btree extent records Christoph Hellwig
` (7 more replies)
0 siblings, 8 replies; 9+ messages in thread
From: Christoph Hellwig @ 2010-10-12 13:56 UTC (permalink / raw)
To: linux-fsdevel
Some more hfsplus updates before applying them to my for-next tree.
The biggest one is a fix for corrupting hard links under load,
in addition to that it's various corruption fixes ported from hfs and
a few cleanups.
^ permalink raw reply [flat|nested] 9+ messages in thread
* hfsplus: fix oops on mount with corrupted btree extent records
2010-10-12 13:56 hfsplus updates Christoph Hellwig
@ 2010-10-12 13:56 ` Christoph Hellwig
2010-10-12 13:57 ` hfs_bnode_find() can fail, resulting in hfs_bnode_split() breakage Christoph Hellwig
` (6 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Christoph Hellwig @ 2010-10-12 13:56 UTC (permalink / raw)
To: linux-fsdevel
From: Jeff Mahoney <jeffm@suse.com>
A particular fsfuzzer run caused an hfs file system to crash on mount. This
is due to a corrupted MDB extent record causing a miscalculation of
HFSPLUS_I(inode)->first_blocks for the extent tree. If the extent records
are zereod out, then it won't trigger the first_blocks special case and
instead falls through to the extent code, which we're in the middle
of initializing.
This patch catches the 0 size extent records, reports the corruption,
and fails the mount.
[hch: ported of commit 47f365eb575735c6b2edf5d08e0d16d26a9c23bd from hfs]
Reported-by: Ramon de Carvalho Valle <rcvalle@linux.vnet.ibm.com>
Signed-off-by: Jeff Mahoney <jeffm@suse.com>
Signed-off-by: Christoph Hellwig <hch@tuxera.com>
Index: linux-2.6/fs/hfsplus/btree.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/btree.c 2010-10-01 16:52:32.362010219 +0200
+++ linux-2.6/fs/hfsplus/btree.c 2010-10-01 16:53:49.328291422 +0200
@@ -39,10 +39,16 @@ struct hfs_btree *hfs_btree_open(struct
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));
@@ -89,8 +95,9 @@ struct hfs_btree *hfs_btree_open(struct
fail_page:
tree->inode->i_mapping->a_ops = &hfsplus_aops;
page_cache_release(page);
- free_tree:
+ free_inode:
iput(tree->inode);
+ free_tree:
kfree(tree);
return NULL;
}
^ permalink raw reply [flat|nested] 9+ messages in thread
* hfs_bnode_find() can fail, resulting in hfs_bnode_split() breakage
2010-10-12 13:56 hfsplus updates Christoph Hellwig
2010-10-12 13:56 ` hfsplus: fix oops on mount with corrupted btree extent records Christoph Hellwig
@ 2010-10-12 13:57 ` Christoph Hellwig
2010-10-12 13:57 ` hfsplus: handle more on-disk corruptions without oopsing Christoph Hellwig
` (5 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Christoph Hellwig @ 2010-10-12 13:57 UTC (permalink / raw)
To: linux-fsdevel
From: Al Viro <viro@ftp.linux.org.uk>
oops and fs corruption; the latter can happen even on valid fs in case of oom.
[hch: port of commit 3d10a15d6919488204bdb264050d156ced20d9aa from hfs]
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Christoph Hellwig <hch@tuxera.com>
Index: linux-2.6/fs/hfsplus/brec.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/brec.c 2010-10-06 09:34:17.753004170 +0200
+++ linux-2.6/fs/hfsplus/brec.c 2010-10-06 09:36:36.550004100 +0200
@@ -216,7 +216,7 @@ skip:
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;
@@ -235,6 +235,17 @@ static struct hfs_bnode *hfs_bnode_split
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;
@@ -248,6 +259,8 @@ static struct hfs_bnode *hfs_bnode_split
/* panic? */
hfs_bnode_put(node);
hfs_bnode_put(new_node);
+ if (next_node)
+ hfs_bnode_put(next_node);
return ERR_PTR(-ENOSPC);
}
@@ -302,8 +315,7 @@ static struct hfs_bnode *hfs_bnode_split
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);
^ permalink raw reply [flat|nested] 9+ messages in thread
* hfsplus: handle more on-disk corruptions without oopsing
2010-10-12 13:56 hfsplus updates Christoph Hellwig
2010-10-12 13:56 ` hfsplus: fix oops on mount with corrupted btree extent records Christoph Hellwig
2010-10-12 13:57 ` hfs_bnode_find() can fail, resulting in hfs_bnode_split() breakage Christoph Hellwig
@ 2010-10-12 13:57 ` Christoph Hellwig
2010-10-12 13:57 ` hfsplus: validate btree flags Christoph Hellwig
` (4 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Christoph Hellwig @ 2010-10-12 13:57 UTC (permalink / raw)
To: linux-fsdevel
From: Eric Sandeen <sandeen@redhat.com>
hfs seems prone to bad things when it encounters on disk corruption. Many
values are read from disk, and used as lengths to memcpy, as an example.
This patch fixes up several of these problematic cases.
o sanity check the on-disk maximum key lengths on mount
(these are set to a defined value at mkfs time and shouldn't differ)
o check on-disk node keylens against the maximum key length for each tree
o fix hfs_btree_open so that going out via free_tree: doesn't wind
up in hfs_releasepage, which wants to follow the very pointer
we were trying to set up:
HFS_SB(sb)->cat_tree = hfs_btree_open()
.
failure gets to hfs_releasepage and tries to follow HFS_SB(sb)->cat_tree
Tested with the fsfuzzer; it survives more than it used to.
[hch: ported of commit cf0594625083111ae522496dc1c256f7476939c2 from hfs]
[hch: added the fixes from 5581d018ed3493d226e7a4d645d9c8a5af6c36b]
Signed-off-by: Eric Sandeen <sandeen@redhat.com>
Signed-off-by: Christoph Hellwig <hch@tuxera.com>
Index: linux-2.6/fs/hfsplus/bfind.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/bfind.c 2010-10-06 10:35:04.264025891 +0200
+++ linux-2.6/fs/hfsplus/bfind.c 2010-10-06 10:35:32.714253856 +0200
@@ -52,6 +52,10 @@ int __hfs_brec_find(struct hfs_bnode *bn
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) {
@@ -67,6 +71,10 @@ int __hfs_brec_find(struct hfs_bnode *bn
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:
@@ -75,6 +83,7 @@ done:
fd->keylength = keylen;
fd->entryoffset = off + keylen;
fd->entrylength = len - keylen;
+fail:
return res;
}
@@ -198,6 +207,10 @@ int hfs_brec_goto(struct hfs_find_data *
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;
Index: linux-2.6/fs/hfsplus/brec.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/brec.c 2010-10-06 10:35:27.466040558 +0200
+++ linux-2.6/fs/hfsplus/brec.c 2010-10-06 10:35:32.715254345 +0200
@@ -42,10 +42,21 @@ u16 hfs_brec_keylen(struct hfs_bnode *no
recoff = hfs_bnode_read_u16(node, node->tree->node_size - (rec + 1) * 2);
if (!recoff)
return 0;
- if (node->tree->attributes & HFS_TREE_BIGKEYS)
+ if (node->tree->attributes & HFS_TREE_BIGKEYS) {
retval = hfs_bnode_read_u16(node, recoff) + 2;
- else
+ if (retval > node->tree->max_key_len + 2) {
+ printk(KERN_ERR "hfs: keylen %d too large\n",
+ retval);
+ retval = 0;
+ }
+ } else {
retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1;
+ if (retval > node->tree->max_key_len + 1) {
+ printk(KERN_ERR "hfs: keylen %d too large\n",
+ retval);
+ retval = 0;
+ }
+ }
}
return retval;
}
Index: linux-2.6/fs/hfsplus/btree.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/btree.c 2010-10-06 10:35:04.281004170 +0200
+++ linux-2.6/fs/hfsplus/btree.c 2010-10-06 10:36:04.657254064 +0200
@@ -63,10 +63,23 @@ struct hfs_btree *hfs_btree_open(struct
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;
+ }
tree->keycmp = hfsplus_ext_cmp_key;
- } else if (id == HFSPLUS_CAT_CNID) {
+ 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 (test_bit(HFSPLUS_SB_HFSX, &HFSPLUS_SB(sb)->flags) &&
(head->key_type == HFSPLUS_KEY_BINARY))
tree->keycmp = hfsplus_cat_bin_cmp_key;
@@ -74,7 +87,8 @@ struct hfs_btree *hfs_btree_open(struct
tree->keycmp = hfsplus_cat_case_cmp_key;
set_bit(HFSPLUS_SB_CASEFOLD, &HFSPLUS_SB(sb)->flags);
}
- } else {
+ break;
+ default:
printk(KERN_ERR "hfs: unknown B*Tree requested\n");
goto fail_page;
}
@@ -84,6 +98,7 @@ struct hfs_btree *hfs_btree_open(struct
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;
@@ -93,9 +108,9 @@ struct hfs_btree *hfs_btree_open(struct
return tree;
fail_page:
- tree->inode->i_mapping->a_ops = &hfsplus_aops;
page_cache_release(page);
free_inode:
+ tree->inode->i_mapping->a_ops = &hfsplus_aops;
iput(tree->inode);
free_tree:
kfree(tree);
Index: linux-2.6/fs/hfsplus/hfsplus_raw.h
===================================================================
--- linux-2.6.orig/fs/hfsplus/hfsplus_raw.h 2010-10-06 10:35:04.293005218 +0200
+++ linux-2.6/fs/hfsplus/hfsplus_raw.h 2010-10-06 10:35:33.270257069 +0200
@@ -200,6 +200,7 @@ struct hfsplus_cat_key {
struct hfsplus_unistr name;
} __packed;
+#define HFSPLUS_CAT_KEYLEN (sizeof(struct hfsplus_cat_key))
/* Structs from hfs.h */
struct hfsp_point {
@@ -323,7 +324,7 @@ struct hfsplus_ext_key {
__be32 start_block;
} __packed;
-#define HFSPLUS_EXT_KEYLEN 12
+#define HFSPLUS_EXT_KEYLEN sizeof(struct hfsplus_ext_key)
/* HFS+ generic BTree key */
typedef union {
^ permalink raw reply [flat|nested] 9+ messages in thread
* hfsplus: validate btree flags
2010-10-12 13:56 hfsplus updates Christoph Hellwig
` (2 preceding siblings ...)
2010-10-12 13:57 ` hfsplus: handle more on-disk corruptions without oopsing Christoph Hellwig
@ 2010-10-12 13:57 ` Christoph Hellwig
2010-10-12 13:58 ` hfsplus: fix link corruption Christoph Hellwig
` (3 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Christoph Hellwig @ 2010-10-12 13:57 UTC (permalink / raw)
To: linux-fsdevel
Signed-off-by: Christoph Hellwig <hch@tuxera.com>
Index: linux-2.6/fs/hfsplus/brec.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/brec.c 2010-10-06 10:35:32.715254345 +0200
+++ linux-2.6/fs/hfsplus/brec.c 2010-10-06 10:36:33.964279909 +0200
@@ -42,20 +42,12 @@ u16 hfs_brec_keylen(struct hfs_bnode *no
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;
- if (retval > node->tree->max_key_len + 2) {
- printk(KERN_ERR "hfs: keylen %d too large\n",
- retval);
- retval = 0;
- }
- } else {
- retval = (hfs_bnode_read_u8(node, recoff) | 1) + 1;
- if (retval > node->tree->max_key_len + 1) {
- printk(KERN_ERR "hfs: keylen %d too large\n",
- retval);
- retval = 0;
- }
+
+ 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;
Index: linux-2.6/fs/hfsplus/btree.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/btree.c 2010-10-06 10:36:04.657254064 +0200
+++ linux-2.6/fs/hfsplus/btree.c 2010-10-06 10:36:12.256253995 +0200
@@ -71,6 +71,11 @@ struct hfs_btree *hfs_btree_open(struct
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;
break;
case HFSPLUS_CAT_CNID:
@@ -79,6 +84,10 @@ struct hfs_btree *hfs_btree_open(struct
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))
@@ -93,6 +102,11 @@ struct hfs_btree *hfs_btree_open(struct
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;
^ permalink raw reply [flat|nested] 9+ messages in thread
* hfsplus: fix link corruption
2010-10-12 13:56 hfsplus updates Christoph Hellwig
` (3 preceding siblings ...)
2010-10-12 13:57 ` hfsplus: validate btree flags Christoph Hellwig
@ 2010-10-12 13:58 ` Christoph Hellwig
2010-10-12 13:58 ` hfsplus: remove superflous rootflags field in hfsplus_inode_info Christoph Hellwig
` (2 subsequent siblings)
7 siblings, 0 replies; 9+ messages in thread
From: Christoph Hellwig @ 2010-10-12 13:58 UTC (permalink / raw)
To: linux-fsdevel
HFS implements hardlink by using indirect catalog entries that refer to a hidden
directly. The link target is cached in the dev field in the HFS+ specific
inode, which is also used for the device number for device files, and inside
for passing the nlink value of the indirect node from hfsplus_cat_write_inode
to a helper function. Now if we happen to write out the indirect node while
hfsplus_link is creating the catalog entry we'll get a link pointing to the
linkid of the current nlink value. This can easily be reproduced by a large
enough loop of local git-clone operations.
Stop abusing the dev field in the HFS+ inode for short term storage by
refactoring the way the permission structure in the catalog entry is
set up, and rename the dev field to linkid to avoid any confusion.
While we're at it also prevent creating hard links to special files, as
the HFS+ dev and linkid share the same space in the on-disk structure.
Signed-off-by: Christoph Hellwig <hch@tuxera.com>
Index: linux-2.6/fs/hfsplus/dir.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/dir.c 2010-10-11 19:35:00.719004014 +0200
+++ linux-2.6/fs/hfsplus/dir.c 2010-10-11 20:01:06.023253839 +0200
@@ -102,7 +102,7 @@ again:
if (IS_ERR(inode))
return ERR_CAST(inode);
if (S_ISREG(inode->i_mode))
- HFSPLUS_I(inode)->dev = linkid;
+ HFSPLUS_I(inode)->linkid = linkid;
out:
d_add(dentry, inode);
return NULL;
@@ -252,6 +252,8 @@ static int hfsplus_link(struct dentry *s
if (HFSPLUS_IS_RSRC(inode))
return -EPERM;
+ if (!S_ISREG(inode->i_mode))
+ return -EPERM;
mutex_lock(&sbi->vh_mutex);
if (inode->i_ino == (u32)(unsigned long)src_dentry->d_fsdata) {
@@ -268,7 +270,7 @@ static int hfsplus_link(struct dentry *s
if (res != -EEXIST)
goto out;
}
- HFSPLUS_I(inode)->dev = id;
+ HFSPLUS_I(inode)->linkid = id;
cnid = sbi->next_cnid++;
src_dentry->d_fsdata = (void *)(unsigned long)cnid;
res = hfsplus_create_cat(cnid, src_dir, &src_dentry->d_name, inode);
Index: linux-2.6/fs/hfsplus/inode.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/inode.c 2010-10-11 19:35:00.725012325 +0200
+++ linux-2.6/fs/hfsplus/inode.c 2010-10-11 20:01:06.934260195 +0200
@@ -267,7 +267,13 @@ static void hfsplus_set_perms(struct ino
perms->mode = cpu_to_be16(inode->i_mode);
perms->owner = cpu_to_be32(inode->i_uid);
perms->group = cpu_to_be32(inode->i_gid);
- perms->dev = cpu_to_be32(HFSPLUS_I(inode)->dev);
+
+ if (S_ISREG(inode->i_mode))
+ perms->dev = cpu_to_be32(inode->i_nlink);
+ else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode))
+ perms->dev = cpu_to_be32(inode->i_rdev);
+ else
+ perms->dev = 0;
}
static int hfsplus_file_open(struct inode *inode, struct file *file)
@@ -491,7 +497,7 @@ int hfsplus_cat_read_inode(struct inode
type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset);
- HFSPLUS_I(inode)->dev = 0;
+ HFSPLUS_I(inode)->linkid = 0;
if (type == HFSPLUS_FOLDER) {
struct hfsplus_cat_folder *folder = &entry.folder;
@@ -595,10 +601,6 @@ int hfsplus_cat_write_inode(struct inode
hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
sizeof(struct hfsplus_cat_file));
hfsplus_inode_write_fork(inode, &file->data_fork);
- if (S_ISREG(inode->i_mode))
- HFSPLUS_I(inode)->dev = inode->i_nlink;
- if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
- HFSPLUS_I(inode)->dev = kdev_t_to_nr(inode->i_rdev);
hfsplus_set_perms(inode, &file->permissions);
if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE)
file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
Index: linux-2.6/fs/hfsplus/catalog.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/catalog.c 2010-10-11 19:35:00.741004643 +0200
+++ linux-2.6/fs/hfsplus/catalog.c 2010-10-11 20:01:06.916256284 +0200
@@ -134,7 +134,7 @@ static int hfsplus_cat_build_record(hfsp
file->user_info.fdCreator = cpu_to_be32(HFSP_HFSPLUS_CREATOR);
file->user_info.fdFlags = cpu_to_be16(0x100);
file->create_date = HFSPLUS_I(sbi->hidden_dir)->create_date;
- file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode)->dev);
+ file->permissions.dev = cpu_to_be32(HFSPLUS_I(inode)->linkid);
}
return sizeof(*file);
}
Index: linux-2.6/fs/hfsplus/hfsplus_fs.h
===================================================================
--- linux-2.6.orig/fs/hfsplus/hfsplus_fs.h 2010-10-11 19:35:00.753011697 +0200
+++ linux-2.6/fs/hfsplus/hfsplus_fs.h 2010-10-11 20:02:12.131299866 +0200
@@ -178,7 +178,11 @@ struct hfsplus_inode_info {
*/
struct inode *rsrc_inode;
__be32 create_date;
- u32 dev;
+
+ /*
+ * Protected by sbi->vh_mutex.
+ */
+ u32 linkid;
/*
* Protected by i_mutex.
@@ -427,6 +431,4 @@ static inline struct hfsplus_inode_info
#define hfsp_ut2mt(t) __hfsp_ut2mt((t).tv_sec)
#define hfsp_now2mt() __hfsp_ut2mt(get_seconds())
-#define kdev_t_to_nr(x) (x)
-
#endif
^ permalink raw reply [flat|nested] 9+ messages in thread
* hfsplus: remove superflous rootflags field in hfsplus_inode_info
2010-10-12 13:56 hfsplus updates Christoph Hellwig
` (4 preceding siblings ...)
2010-10-12 13:58 ` hfsplus: fix link corruption Christoph Hellwig
@ 2010-10-12 13:58 ` Christoph Hellwig
2010-10-12 13:58 ` hfsplus: create correct initial catalog entries for device files Christoph Hellwig
2010-10-12 13:58 ` hfsplus: remove the unused hfsplus_kmap/hfsplus_kunmap helpers Christoph Hellwig
7 siblings, 0 replies; 9+ messages in thread
From: Christoph Hellwig @ 2010-10-12 13:58 UTC (permalink / raw)
To: linux-fsdevel
The rootflags field in hfsplus_inode_info only caches the immutable and
append-only flags in the VFS inode, so we can easily get rid of it.
Signed-off-by: Christoph Hellwig <hch@tuxera.com>
Index: linux-2.6/fs/hfsplus/catalog.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/catalog.c 2010-10-11 19:53:11.478003833 +0200
+++ linux-2.6/fs/hfsplus/catalog.c 2010-10-11 19:53:25.153340347 +0200
@@ -77,7 +77,6 @@ static void hfsplus_set_perms(struct ino
perms->rootflags |= HFSPLUS_FLG_APPEND;
else
perms->rootflags &= ~HFSPLUS_FLG_APPEND;
- HFSPLUS_I(inode)->rootflags = perms->rootflags;
HFSPLUS_I(inode)->userflags = perms->userflags;
perms->mode = cpu_to_be16(inode->i_mode);
perms->owner = cpu_to_be32(inode->i_uid);
Index: linux-2.6/fs/hfsplus/hfsplus_fs.h
===================================================================
--- linux-2.6.orig/fs/hfsplus/hfsplus_fs.h 2010-10-11 19:53:45.780260404 +0200
+++ linux-2.6/fs/hfsplus/hfsplus_fs.h 2010-10-11 19:53:55.403280008 +0200
@@ -184,7 +184,7 @@ struct hfsplus_inode_info {
* Protected by i_mutex.
*/
sector_t fs_blocks;
- u8 rootflags, userflags; /* BSD system and user file flags */
+ u8 userflags; /* BSD user file flags */
struct list_head open_dir_list;
loff_t phys_size;
Index: linux-2.6/fs/hfsplus/inode.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/inode.c 2010-10-11 19:53:33.846004413 +0200
+++ linux-2.6/fs/hfsplus/inode.c 2010-10-11 19:53:36.680005829 +0200
@@ -241,7 +241,6 @@ static void hfsplus_get_perms(struct ino
mode = S_IFREG | ((S_IRUGO|S_IWUGO) & ~(sbi->umask));
inode->i_mode = mode;
- HFSPLUS_I(inode)->rootflags = perms->rootflags;
HFSPLUS_I(inode)->userflags = perms->userflags;
if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE)
inode->i_flags |= S_IMMUTABLE;
Index: linux-2.6/fs/hfsplus/ioctl.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/ioctl.c 2010-10-11 19:50:47.467253978 +0200
+++ linux-2.6/fs/hfsplus/ioctl.c 2010-10-11 19:53:03.041005900 +0200
@@ -26,9 +26,9 @@ static int hfsplus_ioctl_getflags(struct
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
unsigned int flags = 0;
- if (hip->rootflags & HFSPLUS_FLG_IMMUTABLE)
+ if (inode->i_flags & S_IMMUTABLE)
flags |= FS_IMMUTABLE_FL;
- if (hip->rootflags & HFSPLUS_FLG_APPEND)
+ if (inode->i_flags |= S_APPEND)
flags |= FS_APPEND_FL;
if (hip->userflags & HFSPLUS_FLG_NODUMP)
flags |= FS_NODUMP_FL;
@@ -59,8 +59,8 @@ static int hfsplus_ioctl_setflags(struct
mutex_lock(&inode->i_mutex);
- if (flags & (FS_IMMUTABLE_FL|FS_APPEND_FL) ||
- hip->rootflags & (HFSPLUS_FLG_IMMUTABLE|HFSPLUS_FLG_APPEND)) {
+ if ((flags & (FS_IMMUTABLE_FL|FS_APPEND_FL)) ||
+ inode->i_flags & (S_IMMUTABLE|S_APPEND)) {
if (!capable(CAP_LINUX_IMMUTABLE)) {
err = -EPERM;
goto out_unlock_inode;
@@ -72,20 +72,17 @@ static int hfsplus_ioctl_setflags(struct
err = -EOPNOTSUPP;
goto out_unlock_inode;
}
- if (flags & FS_IMMUTABLE_FL) {
+
+ if (flags & FS_IMMUTABLE_FL)
inode->i_flags |= S_IMMUTABLE;
- hip->rootflags |= HFSPLUS_FLG_IMMUTABLE;
- } else {
+ else
inode->i_flags &= ~S_IMMUTABLE;
- hip->rootflags &= ~HFSPLUS_FLG_IMMUTABLE;
- }
- if (flags & FS_APPEND_FL) {
+
+ if (flags & FS_APPEND_FL)
inode->i_flags |= S_APPEND;
- hip->rootflags |= HFSPLUS_FLG_APPEND;
- } else {
+ else
inode->i_flags &= ~S_APPEND;
- hip->rootflags &= ~HFSPLUS_FLG_APPEND;
- }
+
if (flags & FS_NODUMP_FL)
hip->userflags |= HFSPLUS_FLG_NODUMP;
else
^ permalink raw reply [flat|nested] 9+ messages in thread
* hfsplus: create correct initial catalog entries for device files
2010-10-12 13:56 hfsplus updates Christoph Hellwig
` (5 preceding siblings ...)
2010-10-12 13:58 ` hfsplus: remove superflous rootflags field in hfsplus_inode_info Christoph Hellwig
@ 2010-10-12 13:58 ` Christoph Hellwig
2010-10-12 13:58 ` hfsplus: remove the unused hfsplus_kmap/hfsplus_kunmap helpers Christoph Hellwig
7 siblings, 0 replies; 9+ messages in thread
From: Christoph Hellwig @ 2010-10-12 13:58 UTC (permalink / raw)
To: linux-fsdevel
Make sure the initial insertation of the catalog entry already contains
the device number by calling init_special_inode early and setting writing
out the dev field of the on-disk permission structure. The latter is
facilitated by sharing the almost identical hfsplus_set_perms helpers
between initial catalog entry creating and ->write_inode.
Unless we crashed just after mknod this bug was harmless as the inode
is marked dirty at the end of hfsplus_mknod, and hfsplus_write_inode
will update the catalog entry to contain the correct value.
Signed-off-by: Christoph Hellwig <hch@tuxera.com>
Index: linux-2.6/fs/hfsplus/catalog.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/catalog.c 2010-10-11 20:02:16.780274444 +0200
+++ linux-2.6/fs/hfsplus/catalog.c 2010-10-11 20:02:40.577253560 +0200
@@ -67,7 +67,7 @@ static void hfsplus_cat_build_key_uni(hf
key->key_len = cpu_to_be16(6 + ustrlen);
}
-static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms)
+void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms)
{
if (inode->i_flags & S_IMMUTABLE)
perms->rootflags |= HFSPLUS_FLG_IMMUTABLE;
@@ -77,10 +77,18 @@ static void hfsplus_set_perms(struct ino
perms->rootflags |= HFSPLUS_FLG_APPEND;
else
perms->rootflags &= ~HFSPLUS_FLG_APPEND;
- HFSPLUS_I(inode)->userflags = perms->userflags;
+
+ perms->userflags = HFSPLUS_I(inode)->userflags;
perms->mode = cpu_to_be16(inode->i_mode);
perms->owner = cpu_to_be32(inode->i_uid);
perms->group = cpu_to_be32(inode->i_gid);
+
+ if (S_ISREG(inode->i_mode))
+ perms->dev = cpu_to_be32(inode->i_nlink);
+ else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode))
+ perms->dev = cpu_to_be32(inode->i_rdev);
+ else
+ perms->dev = 0;
}
static int hfsplus_cat_build_record(hfsplus_cat_entry *entry, u32 cnid, struct inode *inode)
@@ -99,7 +107,7 @@ static int hfsplus_cat_build_record(hfsp
folder->content_mod_date =
folder->attribute_mod_date =
folder->access_date = hfsp_now2mt();
- hfsplus_set_perms(inode, &folder->permissions);
+ hfsplus_cat_set_perms(inode, &folder->permissions);
if (inode == sbi->hidden_dir)
/* invisible and namelocked */
folder->user_info.frFlags = cpu_to_be16(0x5000);
@@ -118,7 +126,7 @@ static int hfsplus_cat_build_record(hfsp
file->attribute_mod_date =
file->access_date = hfsp_now2mt();
if (cnid == inode->i_ino) {
- hfsplus_set_perms(inode, &file->permissions);
+ hfsplus_cat_set_perms(inode, &file->permissions);
if (S_ISLNK(inode->i_mode)) {
file->user_info.fdType = cpu_to_be32(HFSP_SYMLINK_TYPE);
file->user_info.fdCreator = cpu_to_be32(HFSP_SYMLINK_CREATOR);
Index: linux-2.6/fs/hfsplus/dir.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/dir.c 2010-10-11 20:01:06.023253839 +0200
+++ linux-2.6/fs/hfsplus/dir.c 2010-10-11 20:02:40.578254049 +0200
@@ -418,6 +418,9 @@ static int hfsplus_mknod(struct inode *d
if (!inode)
goto out;
+ if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode))
+ init_special_inode(inode, mode, rdev);
+
res = hfsplus_create_cat(inode->i_ino, dir, &dentry->d_name, inode);
if (res) {
inode->i_nlink = 0;
@@ -426,9 +429,6 @@ static int hfsplus_mknod(struct inode *d
goto out;
}
- if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode))
- init_special_inode(inode, mode, rdev);
-
hfsplus_instantiate(dentry, inode, inode->i_ino);
mark_inode_dirty(inode);
out:
Index: linux-2.6/fs/hfsplus/hfsplus_fs.h
===================================================================
--- linux-2.6.orig/fs/hfsplus/hfsplus_fs.h 2010-10-11 20:02:16.780274444 +0200
+++ linux-2.6/fs/hfsplus/hfsplus_fs.h 2010-10-11 20:02:40.584331783 +0200
@@ -326,6 +326,7 @@ int hfsplus_create_cat(u32, struct inode
int hfsplus_delete_cat(u32, struct inode *, struct qstr *);
int hfsplus_rename_cat(u32, struct inode *, struct qstr *,
struct inode *, struct qstr *);
+void hfsplus_cat_set_perms(struct inode *inode, struct hfsplus_perm *perms);
/* dir.c */
extern const struct inode_operations hfsplus_dir_inode_operations;
Index: linux-2.6/fs/hfsplus/inode.c
===================================================================
--- linux-2.6.orig/fs/hfsplus/inode.c 2010-10-11 20:02:16.786004155 +0200
+++ linux-2.6/fs/hfsplus/inode.c 2010-10-11 20:02:40.590255236 +0200
@@ -252,29 +252,6 @@ static void hfsplus_get_perms(struct ino
inode->i_flags &= ~S_APPEND;
}
-static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms)
-{
- if (inode->i_flags & S_IMMUTABLE)
- perms->rootflags |= HFSPLUS_FLG_IMMUTABLE;
- else
- perms->rootflags &= ~HFSPLUS_FLG_IMMUTABLE;
- if (inode->i_flags & S_APPEND)
- perms->rootflags |= HFSPLUS_FLG_APPEND;
- else
- perms->rootflags &= ~HFSPLUS_FLG_APPEND;
- perms->userflags = HFSPLUS_I(inode)->userflags;
- perms->mode = cpu_to_be16(inode->i_mode);
- perms->owner = cpu_to_be32(inode->i_uid);
- perms->group = cpu_to_be32(inode->i_gid);
-
- if (S_ISREG(inode->i_mode))
- perms->dev = cpu_to_be32(inode->i_nlink);
- else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode))
- perms->dev = cpu_to_be32(inode->i_rdev);
- else
- perms->dev = 0;
-}
-
static int hfsplus_file_open(struct inode *inode, struct file *file)
{
if (HFSPLUS_IS_RSRC(inode))
@@ -578,7 +555,7 @@ int hfsplus_cat_write_inode(struct inode
hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
sizeof(struct hfsplus_cat_folder));
/* simple node checks? */
- hfsplus_set_perms(inode, &folder->permissions);
+ hfsplus_cat_set_perms(inode, &folder->permissions);
folder->access_date = hfsp_ut2mt(inode->i_atime);
folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
@@ -600,7 +577,7 @@ int hfsplus_cat_write_inode(struct inode
hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
sizeof(struct hfsplus_cat_file));
hfsplus_inode_write_fork(inode, &file->data_fork);
- hfsplus_set_perms(inode, &file->permissions);
+ hfsplus_cat_set_perms(inode, &file->permissions);
if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE)
file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
else
^ permalink raw reply [flat|nested] 9+ messages in thread
* hfsplus: remove the unused hfsplus_kmap/hfsplus_kunmap helpers
2010-10-12 13:56 hfsplus updates Christoph Hellwig
` (6 preceding siblings ...)
2010-10-12 13:58 ` hfsplus: create correct initial catalog entries for device files Christoph Hellwig
@ 2010-10-12 13:58 ` Christoph Hellwig
7 siblings, 0 replies; 9+ messages in thread
From: Christoph Hellwig @ 2010-10-12 13:58 UTC (permalink / raw)
To: linux-fsdevel
Signed-off-by: Christoph Hellwig <hch@tuxera.com>
Index: linux-2.6/fs/hfsplus/hfsplus_fs.h
===================================================================
--- linux-2.6.orig/fs/hfsplus/hfsplus_fs.h 2010-10-11 20:02:40.584331783 +0200
+++ linux-2.6/fs/hfsplus/hfsplus_fs.h 2010-10-11 20:07:05.835253908 +0200
@@ -398,14 +398,6 @@ static inline struct hfsplus_inode_info
return list_entry(inode, struct hfsplus_inode_info, vfs_inode);
}
-#if 1
-#define hfsplus_kmap(p) ({ struct page *__p = (p); kmap(__p); })
-#define hfsplus_kunmap(p) ({ struct page *__p = (p); kunmap(__p); __p; })
-#else
-#define hfsplus_kmap(p) kmap(p)
-#define hfsplus_kunmap(p) kunmap(p)
-#endif
-
#define sb_bread512(sb, sec, data) ({ \
struct buffer_head *__bh; \
sector_t __block; \
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2010-10-12 13:58 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-10-12 13:56 hfsplus updates Christoph Hellwig
2010-10-12 13:56 ` hfsplus: fix oops on mount with corrupted btree extent records Christoph Hellwig
2010-10-12 13:57 ` hfs_bnode_find() can fail, resulting in hfs_bnode_split() breakage Christoph Hellwig
2010-10-12 13:57 ` hfsplus: handle more on-disk corruptions without oopsing Christoph Hellwig
2010-10-12 13:57 ` hfsplus: validate btree flags Christoph Hellwig
2010-10-12 13:58 ` hfsplus: fix link corruption Christoph Hellwig
2010-10-12 13:58 ` hfsplus: remove superflous rootflags field in hfsplus_inode_info Christoph Hellwig
2010-10-12 13:58 ` hfsplus: create correct initial catalog entries for device files Christoph Hellwig
2010-10-12 13:58 ` hfsplus: remove the unused hfsplus_kmap/hfsplus_kunmap helpers Christoph Hellwig
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).