cramfs: fix named-pipe handling
After commit a97c9bf33f
(fix cramfs
making duplicate entries in inode cache) in kernel 2.6.14, named-pipe
on cramfs does not work properly.
It seems the commit make all named-pipe on cramfs share their inode
(and named-pipe buffer).
Make ..._test() refuse to merge inodes with ->i_ino == 1, take inode setup
back to get_cramfs_inode() and make ->drop_inode() evict ones with ->i_ino
== 1 immediately.
Reported-by: Atsushi Nemoto <anemo@mba.ocn.ne.jp>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: <stable@kernel.org> [2.6.14 and later]
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
This commit is contained in:
@@ -43,58 +43,13 @@ static DEFINE_MUTEX(read_mutex);
|
|||||||
static int cramfs_iget5_test(struct inode *inode, void *opaque)
|
static int cramfs_iget5_test(struct inode *inode, void *opaque)
|
||||||
{
|
{
|
||||||
struct cramfs_inode *cramfs_inode = opaque;
|
struct cramfs_inode *cramfs_inode = opaque;
|
||||||
|
return inode->i_ino == CRAMINO(cramfs_inode) && inode->i_ino != 1;
|
||||||
if (inode->i_ino != CRAMINO(cramfs_inode))
|
|
||||||
return 0; /* does not match */
|
|
||||||
|
|
||||||
if (inode->i_ino != 1)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
/* all empty directories, char, block, pipe, and sock, share inode #1 */
|
|
||||||
|
|
||||||
if ((inode->i_mode != cramfs_inode->mode) ||
|
|
||||||
(inode->i_gid != cramfs_inode->gid) ||
|
|
||||||
(inode->i_uid != cramfs_inode->uid))
|
|
||||||
return 0; /* does not match */
|
|
||||||
|
|
||||||
if ((S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) &&
|
|
||||||
(inode->i_rdev != old_decode_dev(cramfs_inode->size)))
|
|
||||||
return 0; /* does not match */
|
|
||||||
|
|
||||||
return 1; /* matches */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int cramfs_iget5_set(struct inode *inode, void *opaque)
|
static int cramfs_iget5_set(struct inode *inode, void *opaque)
|
||||||
{
|
{
|
||||||
static struct timespec zerotime;
|
|
||||||
struct cramfs_inode *cramfs_inode = opaque;
|
struct cramfs_inode *cramfs_inode = opaque;
|
||||||
inode->i_mode = cramfs_inode->mode;
|
|
||||||
inode->i_uid = cramfs_inode->uid;
|
|
||||||
inode->i_size = cramfs_inode->size;
|
|
||||||
inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
|
|
||||||
inode->i_gid = cramfs_inode->gid;
|
|
||||||
/* Struct copy intentional */
|
|
||||||
inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
|
|
||||||
inode->i_ino = CRAMINO(cramfs_inode);
|
inode->i_ino = CRAMINO(cramfs_inode);
|
||||||
/* inode->i_nlink is left 1 - arguably wrong for directories,
|
|
||||||
but it's the best we can do without reading the directory
|
|
||||||
contents. 1 yields the right result in GNU find, even
|
|
||||||
without -noleaf option. */
|
|
||||||
if (S_ISREG(inode->i_mode)) {
|
|
||||||
inode->i_fop = &generic_ro_fops;
|
|
||||||
inode->i_data.a_ops = &cramfs_aops;
|
|
||||||
} else if (S_ISDIR(inode->i_mode)) {
|
|
||||||
inode->i_op = &cramfs_dir_inode_operations;
|
|
||||||
inode->i_fop = &cramfs_directory_operations;
|
|
||||||
} else if (S_ISLNK(inode->i_mode)) {
|
|
||||||
inode->i_op = &page_symlink_inode_operations;
|
|
||||||
inode->i_data.a_ops = &cramfs_aops;
|
|
||||||
} else {
|
|
||||||
inode->i_size = 0;
|
|
||||||
inode->i_blocks = 0;
|
|
||||||
init_special_inode(inode, inode->i_mode,
|
|
||||||
old_decode_dev(cramfs_inode->size));
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,12 +59,48 @@ static struct inode *get_cramfs_inode(struct super_block *sb,
|
|||||||
struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode),
|
struct inode *inode = iget5_locked(sb, CRAMINO(cramfs_inode),
|
||||||
cramfs_iget5_test, cramfs_iget5_set,
|
cramfs_iget5_test, cramfs_iget5_set,
|
||||||
cramfs_inode);
|
cramfs_inode);
|
||||||
|
static struct timespec zerotime;
|
||||||
|
|
||||||
if (inode && (inode->i_state & I_NEW)) {
|
if (inode && (inode->i_state & I_NEW)) {
|
||||||
|
inode->i_mode = cramfs_inode->mode;
|
||||||
|
inode->i_uid = cramfs_inode->uid;
|
||||||
|
inode->i_size = cramfs_inode->size;
|
||||||
|
inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1;
|
||||||
|
inode->i_gid = cramfs_inode->gid;
|
||||||
|
/* Struct copy intentional */
|
||||||
|
inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime;
|
||||||
|
/* inode->i_nlink is left 1 - arguably wrong for directories,
|
||||||
|
but it's the best we can do without reading the directory
|
||||||
|
contents. 1 yields the right result in GNU find, even
|
||||||
|
without -noleaf option. */
|
||||||
|
if (S_ISREG(inode->i_mode)) {
|
||||||
|
inode->i_fop = &generic_ro_fops;
|
||||||
|
inode->i_data.a_ops = &cramfs_aops;
|
||||||
|
} else if (S_ISDIR(inode->i_mode)) {
|
||||||
|
inode->i_op = &cramfs_dir_inode_operations;
|
||||||
|
inode->i_fop = &cramfs_directory_operations;
|
||||||
|
} else if (S_ISLNK(inode->i_mode)) {
|
||||||
|
inode->i_op = &page_symlink_inode_operations;
|
||||||
|
inode->i_data.a_ops = &cramfs_aops;
|
||||||
|
} else {
|
||||||
|
inode->i_size = 0;
|
||||||
|
inode->i_blocks = 0;
|
||||||
|
init_special_inode(inode, inode->i_mode,
|
||||||
|
old_decode_dev(cramfs_inode->size));
|
||||||
|
}
|
||||||
unlock_new_inode(inode);
|
unlock_new_inode(inode);
|
||||||
}
|
}
|
||||||
return inode;
|
return inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void cramfs_drop_inode(struct inode *inode)
|
||||||
|
{
|
||||||
|
if (inode->i_ino == 1)
|
||||||
|
generic_delete_inode(inode);
|
||||||
|
else
|
||||||
|
generic_drop_inode(inode);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have our own block cache: don't fill up the buffer cache
|
* We have our own block cache: don't fill up the buffer cache
|
||||||
* with the rom-image, because the way the filesystem is set
|
* with the rom-image, because the way the filesystem is set
|
||||||
@@ -534,6 +525,7 @@ static const struct super_operations cramfs_ops = {
|
|||||||
.put_super = cramfs_put_super,
|
.put_super = cramfs_put_super,
|
||||||
.remount_fs = cramfs_remount,
|
.remount_fs = cramfs_remount,
|
||||||
.statfs = cramfs_statfs,
|
.statfs = cramfs_statfs,
|
||||||
|
.drop_inode = cramfs_drop_inode,
|
||||||
};
|
};
|
||||||
|
|
||||||
static int cramfs_get_sb(struct file_system_type *fs_type,
|
static int cramfs_get_sb(struct file_system_type *fs_type,
|
||||||
|
Reference in New Issue
Block a user