From c8aebb0c9f8c7471643d5f8ba68328de8013005f Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Dec 2010 10:22:30 -0500 Subject: [PATCH 01/41] per-superblock default ->d_op Signed-off-by: Al Viro --- fs/dcache.c | 4 ++++ include/linux/fs.h | 1 + 2 files changed, 5 insertions(+) diff --git a/fs/dcache.c b/fs/dcache.c index 5699d4c027cbe..5ec58267b5bb1 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1320,6 +1320,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name) __dget_dlock(parent); dentry->d_parent = parent; dentry->d_sb = parent->d_sb; + d_set_d_op(dentry, dentry->d_sb->s_d_op); list_add(&dentry->d_u.d_child, &parent->d_subdirs); spin_unlock(&parent->d_lock); } @@ -1335,6 +1336,7 @@ struct dentry *d_alloc_pseudo(struct super_block *sb, const struct qstr *name) struct dentry *dentry = d_alloc(NULL, name); if (dentry) { dentry->d_sb = sb; + d_set_d_op(dentry, dentry->d_sb->s_d_op); dentry->d_parent = dentry; dentry->d_flags |= DCACHE_DISCONNECTED; } @@ -1507,6 +1509,7 @@ struct dentry * d_alloc_root(struct inode * root_inode) res = d_alloc(NULL, &name); if (res) { res->d_sb = root_inode->i_sb; + d_set_d_op(res, res->d_sb->s_d_op); res->d_parent = res; d_instantiate(res, root_inode); } @@ -1567,6 +1570,7 @@ struct dentry *d_obtain_alias(struct inode *inode) /* attach a disconnected dentry */ spin_lock(&tmp->d_lock); tmp->d_sb = inode->i_sb; + d_set_d_op(tmp, tmp->d_sb->s_d_op); tmp->d_inode = inode; tmp->d_flags |= DCACHE_DISCONNECTED; list_add(&tmp->d_alias, &inode->i_dentry); diff --git a/include/linux/fs.h b/include/linux/fs.h index f84d9928bdb16..3e4c27486e744 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1423,6 +1423,7 @@ struct super_block { * generic_show_options() */ char __rcu *s_options; + const struct dentry_operations *s_d_op; /* default d_op for dentries */ }; extern struct timespec current_fs_time(struct super_block *sb); From 6cc9c1d2c1414ef67f465462aa96a5d1fed12f5d Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Dec 2010 10:29:26 -0500 Subject: [PATCH 02/41] fix isofs d_op handling switch to ->s_d_op; d_obtain_alias() will DTRT now Signed-off-by: Al Viro --- fs/isofs/inode.c | 13 +++++++------ fs/isofs/namei.c | 2 -- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 844a7903c72f7..a0f3833c0dbf5 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -939,17 +939,18 @@ static int isofs_fill_super(struct super_block *s, void *data, int silent) goto out_iput; } - /* get the root dentry */ - s->s_root = d_alloc_root(inode); - if (!(s->s_root)) - goto out_no_root; - table = 0; if (joliet_level) table += 2; if (opt.check == 'r') table++; - d_set_d_op(s->s_root, &isofs_dentry_ops[table]); + + s->s_d_op = &isofs_dentry_ops[table]; + + /* get the root dentry */ + s->s_root = d_alloc_root(inode); + if (!(s->s_root)) + goto out_no_root; kfree(opt.iocharset); diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c index 679a849c3b27e..4fb3e8074fd46 100644 --- a/fs/isofs/namei.c +++ b/fs/isofs/namei.c @@ -172,8 +172,6 @@ struct dentry *isofs_lookup(struct inode *dir, struct dentry *dentry, struct nam struct inode *inode; struct page *page; - d_set_d_op(dentry, dir->i_sb->s_root->d_op); - page = alloc_page(GFP_USER); if (!page) return ERR_PTR(-ENOMEM); From 3d23985d6cfa7908e46fd0c62a2ee84faffe4d8b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Dec 2010 10:44:00 -0500 Subject: [PATCH 03/41] switch fat to ->s_d_op, close exportfs races there don't bother with lock_super() in fat_fill_super() callers, while we are at it - there won't be any concurrency anyway. Signed-off-by: Al Viro --- fs/fat/fat.h | 3 ++- fs/fat/inode.c | 13 +++++-------- fs/fat/namei_msdos.c | 27 +++++++++------------------ fs/fat/namei_vfat.c | 27 +++++++++------------------ 4 files changed, 25 insertions(+), 45 deletions(-) diff --git a/fs/fat/fat.h b/fs/fat/fat.h index d75a77f85c281..f50408901f7ea 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h @@ -319,7 +319,8 @@ extern struct inode *fat_build_inode(struct super_block *sb, struct msdos_dir_entry *de, loff_t i_pos); extern int fat_sync_inode(struct inode *inode); extern int fat_fill_super(struct super_block *sb, void *data, int silent, - const struct inode_operations *fs_dir_inode_ops, int isvfat); + const struct inode_operations *fs_dir_inode_ops, + int isvfat, void (*setup)(struct super_block *)); extern int fat_flush_inodes(struct super_block *sb, struct inode *i1, struct inode *i2); diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 206351af7c58a..86753fe10bd1d 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -703,7 +703,6 @@ static struct dentry *fat_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) { struct inode *inode = NULL; - struct dentry *result; u32 *fh = fid->raw; if (fh_len < 5 || fh_type != 3) @@ -748,10 +747,7 @@ static struct dentry *fat_fh_to_dentry(struct super_block *sb, * the fat_iget lookup again. If that fails, then we are totally out * of luck. But all that is for another day */ - result = d_obtain_alias(inode); - if (!IS_ERR(result)) - d_set_d_op(result, sb->s_root->d_op); - return result; + return d_obtain_alias(inode); } static int @@ -799,8 +795,6 @@ static struct dentry *fat_get_parent(struct dentry *child) brelse(bh); parent = d_obtain_alias(inode); - if (!IS_ERR(parent)) - d_set_d_op(parent, sb->s_root->d_op); out: unlock_super(sb); @@ -1244,7 +1238,8 @@ static int fat_read_root(struct inode *inode) * Read the super block of an MS-DOS FS. */ int fat_fill_super(struct super_block *sb, void *data, int silent, - const struct inode_operations *fs_dir_inode_ops, int isvfat) + const struct inode_operations *fs_dir_inode_ops, int isvfat, + void (*setup)(struct super_block *)) { struct inode *root_inode = NULL, *fat_inode = NULL; struct buffer_head *bh; @@ -1280,6 +1275,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent, if (error) goto out_fail; + setup(sb); /* flavour-specific stuff that needs options */ + error = -EIO; sb_min_blocksize(sb, 512); bh = sb_bread(sb, 0); diff --git a/fs/fat/namei_msdos.c b/fs/fat/namei_msdos.c index 35ffe43afa4bc..711499040eb61 100644 --- a/fs/fat/namei_msdos.c +++ b/fs/fat/namei_msdos.c @@ -227,11 +227,7 @@ static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry, } out: unlock_super(sb); - d_set_d_op(dentry, &msdos_dentry_operations); - dentry = d_splice_alias(inode, dentry); - if (dentry) - d_set_d_op(dentry, &msdos_dentry_operations); - return dentry; + return d_splice_alias(inode, dentry); error: unlock_super(sb); @@ -661,21 +657,16 @@ static const struct inode_operations msdos_dir_inode_operations = { .getattr = fat_getattr, }; -static int msdos_fill_super(struct super_block *sb, void *data, int silent) +static void setup(struct super_block *sb) { - int res; - - lock_super(sb); - res = fat_fill_super(sb, data, silent, &msdos_dir_inode_operations, 0); - if (res) { - unlock_super(sb); - return res; - } - + sb->s_d_op = &msdos_dentry_operations; sb->s_flags |= MS_NOATIME; - d_set_d_op(sb->s_root, &msdos_dentry_operations); - unlock_super(sb); - return 0; +} + +static int msdos_fill_super(struct super_block *sb, void *data, int silent) +{ + return fat_fill_super(sb, data, silent, &msdos_dir_inode_operations, + 0, setup); } static struct dentry *msdos_mount(struct file_system_type *fs_type, diff --git a/fs/fat/namei_vfat.c b/fs/fat/namei_vfat.c index e3ffc5e123326..f88f752babd9c 100644 --- a/fs/fat/namei_vfat.c +++ b/fs/fat/namei_vfat.c @@ -772,13 +772,10 @@ static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry, out: unlock_super(sb); - d_set_d_op(dentry, sb->s_root->d_op); dentry->d_time = dentry->d_parent->d_inode->i_version; dentry = d_splice_alias(inode, dentry); - if (dentry) { - d_set_d_op(dentry, sb->s_root->d_op); + if (dentry) dentry->d_time = dentry->d_parent->d_inode->i_version; - } return dentry; error: @@ -1066,24 +1063,18 @@ static const struct inode_operations vfat_dir_inode_operations = { .getattr = fat_getattr, }; -static int vfat_fill_super(struct super_block *sb, void *data, int silent) +static void setup(struct super_block *sb) { - int res; - - lock_super(sb); - res = fat_fill_super(sb, data, silent, &vfat_dir_inode_operations, 1); - if (res) { - unlock_super(sb); - return res; - } - if (MSDOS_SB(sb)->options.name_check != 's') - d_set_d_op(sb->s_root, &vfat_ci_dentry_ops); + sb->s_d_op = &vfat_ci_dentry_ops; else - d_set_d_op(sb->s_root, &vfat_dentry_ops); + sb->s_d_op = &vfat_dentry_ops; +} - unlock_super(sb); - return 0; +static int vfat_fill_super(struct super_block *sb, void *data, int silent) +{ + return fat_fill_super(sb, data, silent, &vfat_dir_inode_operations, + 1, setup); } static struct dentry *vfat_mount(struct file_system_type *fs_type, From 94b77bd86f8ad458fa7870def78ec3a8a7caa986 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Dec 2010 10:59:31 -0500 Subject: [PATCH 04/41] switch jfs to ->s_d_op, close exportfs races Signed-off-by: Al Viro --- fs/jfs/namei.c | 10 +--------- fs/jfs/super.c | 6 +++--- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 4414e3a42264f..81ead850ddb65 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -1465,9 +1465,6 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc jfs_info("jfs_lookup: name = %s", name); - if (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2) - d_set_d_op(dentry, &jfs_ci_dentry_operations); - if ((name[0] == '.') && (len == 1)) inum = dip->i_ino; else if (strcmp(name, "..") == 0) @@ -1492,12 +1489,7 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, struc return ERR_CAST(ip); } - dentry = d_splice_alias(ip, dentry); - - if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)) - d_set_d_op(dentry, &jfs_ci_dentry_operations); - - return dentry; + return d_splice_alias(ip, dentry); } static struct inode *jfs_nfs_get_inode(struct super_block *sb, diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 3150d766e0d4d..eeca48a031abf 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -515,6 +515,9 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) sb->s_magic = JFS_SUPER_MAGIC; + if (sbi->mntflag & JFS_OS2) + sb->s_d_op = &jfs_ci_dentry_operations; + inode = jfs_iget(sb, ROOT_I); if (IS_ERR(inode)) { ret = PTR_ERR(inode); @@ -524,9 +527,6 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent) if (!sb->s_root) goto out_no_root; - if (sbi->mntflag & JFS_OS2) - d_set_d_op(sb->s_root, &jfs_ci_dentry_operations); - /* logical blocks are represented by 40 bits in pxd_t, etc. */ sb->s_maxbytes = ((u64) sb->s_blocksize) << 40; #if BITS_PER_LONG == 32 From d93e34faf924bd98f158712d63085662e648e389 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Dec 2010 07:41:48 -0500 Subject: [PATCH 05/41] pohmelfs: double-free and leak wrong dentry dropped... Signed-off-by: Al Viro --- drivers/staging/pohmelfs/net.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/staging/pohmelfs/net.c b/drivers/staging/pohmelfs/net.c index 9279897ff1618..b2e9186220888 100644 --- a/drivers/staging/pohmelfs/net.c +++ b/drivers/staging/pohmelfs/net.c @@ -413,7 +413,7 @@ static int pohmelfs_readdir_response(struct netfs_state *st) if (dentry) { alias = d_materialise_unique(dentry, &npi->vfs_inode); if (alias) - dput(dentry); + dput(alias); } dput(dentry); From c35eebe9939f55b9d51631d03301a7af19090dcc Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Dec 2010 11:15:22 -0500 Subject: [PATCH 06/41] switch fuse Signed-off-by: Al Viro --- fs/fuse/dir.c | 1 - fs/fuse/inode.c | 10 ++++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 042af7346ec12..bfed8447ed809 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -350,7 +350,6 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, } entry = newent ? newent : entry; - d_set_d_op(entry, &fuse_dentry_operations); if (outarg_valid) fuse_change_entry_timeout(entry, &outarg); else diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index f62b32cffea9e..9e3f68cc1bd13 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -617,10 +617,8 @@ static struct dentry *fuse_get_dentry(struct super_block *sb, goto out_iput; entry = d_obtain_alias(inode); - if (!IS_ERR(entry) && get_node_id(inode) != FUSE_ROOT_ID) { - d_set_d_op(entry, &fuse_dentry_operations); + if (!IS_ERR(entry) && get_node_id(inode) != FUSE_ROOT_ID) fuse_invalidate_entry_cache(entry); - } return entry; @@ -719,10 +717,8 @@ static struct dentry *fuse_get_parent(struct dentry *child) } parent = d_obtain_alias(inode); - if (!IS_ERR(parent) && get_node_id(inode) != FUSE_ROOT_ID) { - d_set_d_op(parent, &fuse_dentry_operations); + if (!IS_ERR(parent) && get_node_id(inode) != FUSE_ROOT_ID) fuse_invalidate_entry_cache(parent); - } return parent; } @@ -989,6 +985,8 @@ static int fuse_fill_super(struct super_block *sb, void *data, int silent) iput(root); goto err_put_conn; } + /* only now - we want root dentry with NULL ->d_op */ + sb->s_d_op = &fuse_dentry_operations; init_req = fuse_request_alloc(); if (!init_req) From 30304aba6a053f114092cea6643a96ac2902bc5a Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Dec 2010 11:16:30 -0500 Subject: [PATCH 07/41] switch sysv Signed-off-by: Al Viro --- fs/sysv/namei.c | 1 - fs/sysv/super.c | 8 ++++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index b5e68da2db321..b427b1208c263 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -48,7 +48,6 @@ static struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry, st struct inode * inode = NULL; ino_t ino; - d_set_d_op(dentry, dir->i_sb->s_root->d_op); if (dentry->d_name.len > SYSV_NAMELEN) return ERR_PTR(-ENAMETOOLONG); ino = sysv_inode_by_name(dentry); diff --git a/fs/sysv/super.c b/fs/sysv/super.c index 76712aefc4ab1..f60c196913eaf 100644 --- a/fs/sysv/super.c +++ b/fs/sysv/super.c @@ -332,6 +332,10 @@ static int complete_read_super(struct super_block *sb, int silent, int size) sb->s_magic = SYSV_MAGIC_BASE + sbi->s_type; /* set up enough so that it can read an inode */ sb->s_op = &sysv_sops; + if (sbi->s_forced_ro) + sb->s_flags |= MS_RDONLY; + if (sbi->s_truncate) + sb->s_d_op = &sysv_dentry_operations; root_inode = sysv_iget(sb, SYSV_ROOT_INO); if (IS_ERR(root_inode)) { printk("SysV FS: get root inode failed\n"); @@ -343,10 +347,6 @@ static int complete_read_super(struct super_block *sb, int silent, int size) printk("SysV FS: get root dentry failed\n"); return 0; } - if (sbi->s_forced_ro) - sb->s_flags |= MS_RDONLY; - if (sbi->s_truncate) - d_set_d_op(sb->s_root, &sysv_dentry_operations); return 1; } From c6cb412366e8f338baae7300b9f1961f3e559a24 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Dec 2010 11:17:44 -0500 Subject: [PATCH 08/41] minixfs: kill dead code ->d_op of root stays NULL these days on minixfs Signed-off-by: Al Viro --- fs/minix/namei.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 1b9e07728a9fc..ce7337ddfdbfd 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -23,8 +23,6 @@ static struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry, st struct inode * inode = NULL; ino_t ino; - d_set_d_op(dentry, dir->i_sb->s_root->d_op); - if (dentry->d_name.len > minix_sb(dir->i_sb)->s_namelen) return ERR_PTR(-ENAMETOOLONG); From 518c79d28e22f657fec399ef5bf0d50b13f7e9b0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Dec 2010 11:19:14 -0500 Subject: [PATCH 09/41] switch hfs Signed-off-by: Al Viro --- fs/hfs/dir.c | 2 -- fs/hfs/super.c | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index ea4aefe7c652c..afa66aaa22379 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -25,8 +25,6 @@ static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry, struct inode *inode = NULL; int res; - d_set_d_op(dentry, &hfs_dentry_operations); - hfs_find_init(HFS_SB(dir->i_sb)->cat_tree, &fd); hfs_cat_build_key(dir->i_sb, fd.search_key, dir->i_ino, &dentry->d_name); res = hfs_brec_read(&fd, &rec, sizeof(rec)); diff --git a/fs/hfs/super.c b/fs/hfs/super.c index 0bef62aa4f420..1b55f704fb225 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -429,13 +429,12 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent) if (!root_inode) goto bail_no_root; + sb->s_d_op = &hfs_dentry_operations; res = -ENOMEM; sb->s_root = d_alloc_root(root_inode); if (!sb->s_root) goto bail_iput; - d_set_d_op(sb->s_root, &hfs_dentry_operations); - /* everything's okay */ return 0; From eddf790bd41aa153922df223b4692cc606cadb7b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Dec 2010 11:19:23 -0500 Subject: [PATCH 10/41] switch hfsplus Signed-off-by: Al Viro --- fs/hfsplus/dir.c | 1 - fs/hfsplus/super.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index f896dc843026a..4df5059c25da6 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -37,7 +37,6 @@ static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry, sb = dir->i_sb; - d_set_d_op(dentry, &hfsplus_dentry_operations); dentry->d_fsdata = NULL; hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd); hfsplus_cat_build_key(sb, fd.search_key, dir->i_ino, &dentry->d_name); diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 6ee6ad20acf25..9a3b4795f43cd 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -444,13 +444,13 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent) err = PTR_ERR(root); goto cleanup; } + sb->s_d_op = &hfsplus_dentry_operations; sb->s_root = d_alloc_root(root); if (!sb->s_root) { iput(root); err = -ENOMEM; goto cleanup; } - d_set_d_op(sb->s_root, &hfsplus_dentry_operations); str.len = sizeof(HFSP_HIDDENDIR_NAME) - 1; str.name = HFSP_HIDDENDIR_NAME; From 96e1391414f80a8a3bae74ddf58d3c2870e304f0 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Dec 2010 11:20:57 -0500 Subject: [PATCH 11/41] switch adfs Signed-off-by: Al Viro --- fs/adfs/dir.c | 1 - fs/adfs/super.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index bf7693c384f9a..3b4a764ed7805 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c @@ -276,7 +276,6 @@ adfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) struct object_info obj; int error; - d_set_d_op(dentry, &adfs_dentry_operations); lock_kernel(); error = adfs_dir_lookup_byname(dir, &dentry->d_name, &obj); if (error == 0) { diff --git a/fs/adfs/super.c b/fs/adfs/super.c index a4041b52fbca2..2d7954049fbe6 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -473,6 +473,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) asb->s_namelen = ADFS_F_NAME_LEN; } + sb->s_d_op = &adfs_dentry_operations; root = adfs_iget(sb, &root_obj); sb->s_root = d_alloc_root(root); if (!sb->s_root) { @@ -483,8 +484,7 @@ static int adfs_fill_super(struct super_block *sb, void *data, int silent) kfree(asb->s_map); adfs_error(sb, "get root inode failed\n"); goto error; - } else - d_set_d_op(sb->s_root, &adfs_dentry_operations); + } unlock_kernel(); return 0; From 8b244ff2fa58f81f84aa03c82c2c23307a778ce7 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Dec 2010 11:29:39 -0500 Subject: [PATCH 12/41] switch nfs to ->s_d_op Signed-off-by: Al Viro --- fs/nfs/dir.c | 4 ---- fs/nfs/getroot.c | 6 ------ fs/nfs/super.c | 1 + 3 files changed, 1 insertion(+), 10 deletions(-) diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index abe4f0c8dc5f9..95b081bc9e25f 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -439,7 +439,6 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry) if (dentry == NULL) return; - d_set_d_op(dentry, NFS_PROTO(dir)->dentry_ops); inode = nfs_fhget(dentry->d_sb, entry->fh, entry->fattr); if (IS_ERR(inode)) goto out; @@ -1193,8 +1192,6 @@ static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, stru if (dentry->d_name.len > NFS_SERVER(dir)->namelen) goto out; - d_set_d_op(dentry, NFS_PROTO(dir)->dentry_ops); - /* * If we're doing an exclusive create, optimize away the lookup * but don't hash the dentry. @@ -1338,7 +1335,6 @@ static struct dentry *nfs_atomic_lookup(struct inode *dir, struct dentry *dentry res = ERR_PTR(-ENAMETOOLONG); goto out; } - d_set_d_op(dentry, NFS_PROTO(dir)->dentry_ops); /* Let vfs_create() deal with O_EXCL. Instantiate, but don't hash * the dentry. */ diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index 5596c6a2881e0..b5ffe8fa291f7 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c @@ -119,9 +119,6 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) } security_d_instantiate(ret, inode); - - if (ret->d_op == NULL) - d_set_d_op(ret, server->nfs_client->rpc_ops->dentry_ops); out: nfs_free_fattr(fsinfo.fattr); return ret; @@ -227,9 +224,6 @@ struct dentry *nfs4_get_root(struct super_block *sb, struct nfs_fh *mntfh) security_d_instantiate(ret, inode); - if (ret->d_op == NULL) - d_set_d_op(ret, server->nfs_client->rpc_ops->dentry_ops); - out: nfs_free_fattr(fattr); dprintk("<-- nfs4_get_root()\n"); diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 0f9ea73e77892..b68c8607770fc 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -2202,6 +2202,7 @@ static int nfs_set_super(struct super_block *s, void *data) s->s_flags = sb_mntdata->mntflags; s->s_fs_info = server; + s->s_d_op = server->nfs_client->rpc_ops->dentry_ops; ret = set_anon_super(s, server); if (ret == 0) server->s_dev = s->s_dev; From 1c929cfe6d8f2087a337a868fbf6c38d56bb4889 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Dec 2010 11:43:51 -0500 Subject: [PATCH 13/41] switch cifs Signed-off-by: Al Viro --- fs/cifs/cifsfs.c | 6 ++++++ fs/cifs/dir.c | 25 +------------------------ fs/cifs/inode.c | 8 -------- fs/cifs/link.c | 4 ---- fs/cifs/readdir.c | 5 ----- 5 files changed, 7 insertions(+), 41 deletions(-) diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 5e7075d5f1397..d9f652a522a69 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -174,6 +174,12 @@ cifs_read_super(struct super_block *sb, void *data, goto out_no_root; } + /* do that *after* d_alloc_root() - we want NULL ->d_op for root here */ + if (cifs_sb_master_tcon(cifs_sb)->nocase) + sb->s_d_op = &cifs_ci_dentry_ops; + else + sb->s_d_op = &cifs_dentry_ops; + #ifdef CONFIG_CIFS_EXPERIMENTAL if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) { cFYI(1, "export ops supported"); diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index 2e773825835e8..1e95dd6356324 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -130,17 +130,6 @@ build_path_from_dentry(struct dentry *direntry) return full_path; } -static void setup_cifs_dentry(struct cifsTconInfo *tcon, - struct dentry *direntry, - struct inode *newinode) -{ - if (tcon->nocase) - d_set_d_op(direntry, &cifs_ci_dentry_ops); - else - d_set_d_op(direntry, &cifs_dentry_ops); - d_instantiate(direntry, newinode); -} - /* Inode operations in similar order to how they appear in Linux file fs.h */ int @@ -327,7 +316,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode, cifs_create_set_dentry: if (rc == 0) - setup_cifs_dentry(tcon, direntry, newinode); + d_instantiate(direntry, newinode); else cFYI(1, "Create worked, get_inode_info failed rc = %d", rc); @@ -418,10 +407,6 @@ int cifs_mknod(struct inode *inode, struct dentry *direntry, int mode, rc = cifs_get_inode_info_unix(&newinode, full_path, inode->i_sb, xid); - if (pTcon->nocase) - d_set_d_op(direntry, &cifs_ci_dentry_ops); - else - d_set_d_op(direntry, &cifs_dentry_ops); if (rc == 0) d_instantiate(direntry, newinode); @@ -601,10 +586,6 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, parent_dir_inode->i_sb, xid, NULL); if ((rc == 0) && (newInode != NULL)) { - if (pTcon->nocase) - d_set_d_op(direntry, &cifs_ci_dentry_ops); - else - d_set_d_op(direntry, &cifs_dentry_ops); d_add(direntry, newInode); if (posix_open) { filp = lookup_instantiate_filp(nd, direntry, @@ -631,10 +612,6 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, } else if (rc == -ENOENT) { rc = 0; direntry->d_time = jiffies; - if (pTcon->nocase) - d_set_d_op(direntry, &cifs_ci_dentry_ops); - else - d_set_d_op(direntry, &cifs_dentry_ops); d_add(direntry, NULL); /* if it was once a directory (but how can we tell?) we could do shrink_dcache_parent(direntry); */ diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c index 0c7e36910e310..b06b60620240e 100644 --- a/fs/cifs/inode.c +++ b/fs/cifs/inode.c @@ -1324,10 +1324,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) /*BB check (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID ) to see if need to set uid/gid */ inc_nlink(inode); - if (pTcon->nocase) - d_set_d_op(direntry, &cifs_ci_dentry_ops); - else - d_set_d_op(direntry, &cifs_dentry_ops); cifs_unix_basic_to_fattr(&fattr, pInfo, cifs_sb); cifs_fill_uniqueid(inode->i_sb, &fattr); @@ -1368,10 +1364,6 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode) rc = cifs_get_inode_info(&newinode, full_path, NULL, inode->i_sb, xid, NULL); - if (pTcon->nocase) - d_set_d_op(direntry, &cifs_ci_dentry_ops); - else - d_set_d_op(direntry, &cifs_dentry_ops); d_instantiate(direntry, newinode); /* setting nlink not necessary except in cases where we * failed to get it from the server or was set bogus */ diff --git a/fs/cifs/link.c b/fs/cifs/link.c index fe2f6a93c49e3..306769de2fb53 100644 --- a/fs/cifs/link.c +++ b/fs/cifs/link.c @@ -524,10 +524,6 @@ cifs_symlink(struct inode *inode, struct dentry *direntry, const char *symname) cFYI(1, "Create symlink ok, getinodeinfo fail rc = %d", rc); } else { - if (pTcon->nocase) - d_set_d_op(direntry, &cifs_ci_dentry_ops); - else - d_set_d_op(direntry, &cifs_dentry_ops); d_instantiate(direntry, newinode); } } diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c index 76b1b37c9e6b7..7f25cc3d22569 100644 --- a/fs/cifs/readdir.c +++ b/fs/cifs/readdir.c @@ -102,11 +102,6 @@ cifs_readdir_lookup(struct dentry *parent, struct qstr *name, return NULL; } - if (cifs_sb_master_tcon(CIFS_SB(sb))->nocase) - d_set_d_op(dentry, &cifs_ci_dentry_ops); - else - d_set_d_op(dentry, &cifs_dentry_ops); - alias = d_materialise_unique(dentry, inode); if (alias != NULL) { dput(dentry); From 41ced6dcf3dc6b901716fda0dc8de3536da4d39b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Dec 2010 12:06:56 -0500 Subject: [PATCH 14/41] switch gfs2, close races Signed-off-by: Al Viro --- fs/gfs2/export.c | 13 ++----------- fs/gfs2/ops_fstype.c | 2 +- fs/gfs2/ops_inode.c | 2 -- 3 files changed, 3 insertions(+), 14 deletions(-) diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index 97012ecff5601..9023db8184f91 100644 --- a/fs/gfs2/export.c +++ b/fs/gfs2/export.c @@ -126,12 +126,7 @@ static int gfs2_get_name(struct dentry *parent, char *name, static struct dentry *gfs2_get_parent(struct dentry *child) { - struct dentry *dentry; - - dentry = d_obtain_alias(gfs2_lookupi(child->d_inode, &gfs2_qdotdot, 1)); - if (!IS_ERR(dentry)) - d_set_d_op(dentry, &gfs2_dops); - return dentry; + return d_obtain_alias(gfs2_lookupi(child->d_inode, &gfs2_qdotdot, 1)); } static struct dentry *gfs2_get_dentry(struct super_block *sb, @@ -139,7 +134,6 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, { struct gfs2_sbd *sdp = sb->s_fs_info; struct inode *inode; - struct dentry *dentry; inode = gfs2_ilookup(sb, inum->no_addr); if (inode) { @@ -156,10 +150,7 @@ static struct dentry *gfs2_get_dentry(struct super_block *sb, return ERR_CAST(inode); out_inode: - dentry = d_obtain_alias(inode); - if (!IS_ERR(dentry)) - d_set_d_op(dentry, &gfs2_dops); - return dentry; + return d_obtain_alias(inode); } static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid, diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c index 2aeabd4218cce..693f4470a2df6 100644 --- a/fs/gfs2/ops_fstype.c +++ b/fs/gfs2/ops_fstype.c @@ -440,7 +440,6 @@ static int gfs2_lookup_root(struct super_block *sb, struct dentry **dptr, iput(inode); return -ENOMEM; } - d_set_d_op(dentry, &gfs2_dops); *dptr = dentry; return 0; } @@ -1106,6 +1105,7 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent sb->s_magic = GFS2_MAGIC; sb->s_op = &gfs2_super_ops; + sb->s_d_op = &gfs2_dops; sb->s_export_op = &gfs2_export_ops; sb->s_xattr = gfs2_xattr_handlers; sb->s_qcop = &gfs2_quotactl_ops; diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index 1501db4f0e6df..ae140c8abb5c8 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -106,8 +106,6 @@ static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry, { struct inode *inode = NULL; - d_set_d_op(dentry, &gfs2_dops); - inode = gfs2_lookupi(dir, &dentry->d_name, 0); if (inode && IS_ERR(inode)) return ERR_CAST(inode); From ba87167c06ed0049260d9ca36405c0f8af609e07 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Sat, 18 Dec 2010 12:10:00 -0500 Subject: [PATCH 15/41] switch ocfs2, close races Signed-off-by: Al Viro --- fs/ocfs2/export.c | 6 +----- fs/ocfs2/namei.c | 5 ----- fs/ocfs2/super.c | 1 + 3 files changed, 2 insertions(+), 10 deletions(-) diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c index 6adafa5760654..5dbc3062b4fd0 100644 --- a/fs/ocfs2/export.c +++ b/fs/ocfs2/export.c @@ -137,9 +137,7 @@ static struct dentry *ocfs2_get_dentry(struct super_block *sb, } result = d_obtain_alias(inode); - if (!IS_ERR(result)) - d_set_d_op(result, &ocfs2_dentry_ops); - else + if (IS_ERR(result)) mlog_errno(PTR_ERR(result)); bail: @@ -175,8 +173,6 @@ static struct dentry *ocfs2_get_parent(struct dentry *child) } parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0)); - if (!IS_ERR(parent)) - d_set_d_op(parent, &ocfs2_dentry_ops); bail_unlock: ocfs2_inode_unlock(dir, 0); diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 30c5231444527..849fb4a2e814a 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -147,7 +147,6 @@ static struct dentry *ocfs2_lookup(struct inode *dir, struct dentry *dentry, spin_unlock(&oi->ip_lock); bail_add: - d_set_d_op(dentry, &ocfs2_dentry_ops); ret = d_splice_alias(inode, dentry); if (inode) { @@ -415,7 +414,6 @@ static int ocfs2_mknod(struct inode *dir, mlog_errno(status); goto leave; } - d_set_d_op(dentry, &ocfs2_dentry_ops); status = ocfs2_add_entry(handle, dentry, inode, OCFS2_I(inode)->ip_blkno, parent_fe_bh, @@ -743,7 +741,6 @@ static int ocfs2_link(struct dentry *old_dentry, } ihold(inode); - d_set_d_op(dentry, &ocfs2_dentry_ops); d_instantiate(dentry, inode); out_commit: @@ -1797,7 +1794,6 @@ static int ocfs2_symlink(struct inode *dir, mlog_errno(status); goto bail; } - d_set_d_op(dentry, &ocfs2_dentry_ops); status = ocfs2_add_entry(handle, dentry, inode, le64_to_cpu(fe->i_blkno), parent_fe_bh, @@ -2462,7 +2458,6 @@ int ocfs2_mv_orphaned_inode_to_new(struct inode *dir, goto out_commit; } - d_set_d_op(dentry, &ocfs2_dentry_ops); d_instantiate(dentry, inode); status = 0; out_commit: diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 17ff46fa8a103..06d1f749ca894 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -2097,6 +2097,7 @@ static int ocfs2_initialize_super(struct super_block *sb, sb->s_fs_info = osb; sb->s_op = &ocfs2_sops; + sb->s_d_op = &ocfs2_dentry_ops; sb->s_export_op = &ocfs2_export_ops; sb->s_qcop = &ocfs2_quotactl_ops; sb->dq_op = &ocfs2_quota_operations; From af53d29ac13a97304d44343dc3b26154ca595268 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Mon, 20 Dec 2010 10:56:06 -0500 Subject: [PATCH 16/41] switch btrfs, close races Signed-off-by: Al Viro --- fs/btrfs/export.c | 12 ++---------- fs/btrfs/inode.c | 2 -- fs/btrfs/super.c | 1 + 3 files changed, 3 insertions(+), 12 deletions(-) diff --git a/fs/btrfs/export.c b/fs/btrfs/export.c index 0ccf9a8afcdf0..9786963b07e5b 100644 --- a/fs/btrfs/export.c +++ b/fs/btrfs/export.c @@ -65,7 +65,6 @@ static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid, { struct btrfs_fs_info *fs_info = btrfs_sb(sb)->fs_info; struct btrfs_root *root; - struct dentry *dentry; struct inode *inode; struct btrfs_key key; int index; @@ -108,10 +107,7 @@ static struct dentry *btrfs_get_dentry(struct super_block *sb, u64 objectid, return ERR_PTR(-ESTALE); } - dentry = d_obtain_alias(inode); - if (!IS_ERR(dentry)) - d_set_d_op(dentry, &btrfs_dentry_operations); - return dentry; + return d_obtain_alias(inode); fail: srcu_read_unlock(&fs_info->subvol_srcu, index); return ERR_PTR(err); @@ -166,7 +162,6 @@ static struct dentry *btrfs_fh_to_dentry(struct super_block *sb, struct fid *fh, static struct dentry *btrfs_get_parent(struct dentry *child) { struct inode *dir = child->d_inode; - struct dentry *dentry; struct btrfs_root *root = BTRFS_I(dir)->root; struct btrfs_path *path; struct extent_buffer *leaf; @@ -223,10 +218,7 @@ static struct dentry *btrfs_get_parent(struct dentry *child) key.type = BTRFS_INODE_ITEM_KEY; key.offset = 0; - dentry = d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root, NULL)); - if (!IS_ERR(dentry)) - d_set_d_op(dentry, &btrfs_dentry_operations); - return dentry; + return d_obtain_alias(btrfs_iget(root->fs_info->sb, &key, root, NULL)); fail: btrfs_free_path(path); return ERR_PTR(ret); diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index a0ff46a478953..f870aefc59dd5 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -4084,8 +4084,6 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry) int index; int ret; - d_set_d_op(dentry, &btrfs_dentry_operations); - if (dentry->d_name.len > BTRFS_NAME_LEN) return ERR_PTR(-ENAMETOOLONG); diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 883c6fa1367eb..22acdaa78ce1f 100644 --- a/fs/btrfs/super.c +++ b/fs/btrfs/super.c @@ -460,6 +460,7 @@ static int btrfs_fill_super(struct super_block *sb, sb->s_maxbytes = MAX_LFS_FILESIZE; sb->s_magic = BTRFS_SUPER_MAGIC; sb->s_op = &btrfs_super_ops; + sb->s_d_op = &btrfs_dentry_operations; sb->s_export_op = &btrfs_export_ops; sb->s_xattr = btrfs_xattr_handlers; sb->s_time_gran = 1; From 0df6a63f8735a7c8a877878bc215d4312e41ef81 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Tue, 21 Dec 2010 13:29:29 -0500 Subject: [PATCH 17/41] switch cgroup switching it to s_d_op allows to kill the cgroup_lookup() kludge. Signed-off-by: Al Viro --- kernel/cgroup.c | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/kernel/cgroup.c b/kernel/cgroup.c index 51cddc11cd85c..5c5f4cc2e99a8 100644 --- a/kernel/cgroup.c +++ b/kernel/cgroup.c @@ -763,8 +763,6 @@ EXPORT_SYMBOL_GPL(cgroup_unlock); * -> cgroup_mkdir. */ -static struct dentry *cgroup_lookup(struct inode *dir, - struct dentry *dentry, struct nameidata *nd); static int cgroup_mkdir(struct inode *dir, struct dentry *dentry, int mode); static int cgroup_rmdir(struct inode *unused_dir, struct dentry *dentry); static int cgroup_populate_dir(struct cgroup *cgrp); @@ -1451,6 +1449,10 @@ static int cgroup_set_super(struct super_block *sb, void *data) static int cgroup_get_rootdir(struct super_block *sb) { + static const struct dentry_operations cgroup_dops = { + .d_iput = cgroup_diput, + }; + struct inode *inode = cgroup_new_inode(S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR, sb); struct dentry *dentry; @@ -1468,6 +1470,8 @@ static int cgroup_get_rootdir(struct super_block *sb) return -ENOMEM; } sb->s_root = dentry; + /* for everything else we want ->d_op set */ + sb->s_d_op = &cgroup_dops; return 0; } @@ -2191,7 +2195,7 @@ static const struct file_operations cgroup_file_operations = { }; static const struct inode_operations cgroup_dir_inode_operations = { - .lookup = cgroup_lookup, + .lookup = simple_lookup, .mkdir = cgroup_mkdir, .rmdir = cgroup_rmdir, .rename = cgroup_rename, @@ -2207,26 +2211,6 @@ static inline struct cftype *__file_cft(struct file *file) return __d_cft(file->f_dentry); } -static int cgroup_delete_dentry(const struct dentry *dentry) -{ - return 1; -} - -static struct dentry *cgroup_lookup(struct inode *dir, - struct dentry *dentry, struct nameidata *nd) -{ - static const struct dentry_operations cgroup_dentry_operations = { - .d_delete = cgroup_delete_dentry, - .d_iput = cgroup_diput, - }; - - if (dentry->d_name.len > NAME_MAX) - return ERR_PTR(-ENAMETOOLONG); - d_set_d_op(dentry, &cgroup_dentry_operations); - d_add(dentry, NULL); - return NULL; -} - static int cgroup_create_file(struct dentry *dentry, mode_t mode, struct super_block *sb) { From 43d344d7722f9b914849ba0014342111a9a0b03e Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Jan 2011 16:12:05 -0500 Subject: [PATCH 18/41] switch hpfs Signed-off-by: Al Viro --- fs/hpfs/dentry.c | 7 +------ fs/hpfs/dir.c | 1 - fs/hpfs/hpfs_fn.h | 2 +- fs/hpfs/super.c | 2 +- 4 files changed, 3 insertions(+), 9 deletions(-) diff --git a/fs/hpfs/dentry.c b/fs/hpfs/dentry.c index 32c13a94e1e90..05d4816e4e774 100644 --- a/fs/hpfs/dentry.c +++ b/fs/hpfs/dentry.c @@ -58,12 +58,7 @@ static int hpfs_compare_dentry(const struct dentry *parent, return 0; } -static const struct dentry_operations hpfs_dentry_operations = { +const struct dentry_operations hpfs_dentry_operations = { .d_hash = hpfs_hash_dentry, .d_compare = hpfs_compare_dentry, }; - -void hpfs_set_dentry_operations(struct dentry *dentry) -{ - d_set_d_op(dentry, &hpfs_dentry_operations); -} diff --git a/fs/hpfs/dir.c b/fs/hpfs/dir.c index 2338130ccebaa..d32f63a569f7f 100644 --- a/fs/hpfs/dir.c +++ b/fs/hpfs/dir.c @@ -298,7 +298,6 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name end: end_add: - hpfs_set_dentry_operations(dentry); unlock_kernel(); d_add(dentry, result); return NULL; diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index 2fee17d0d9ab3..1c43dbea55e8b 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -233,7 +233,7 @@ void hpfs_mark_4buffers_dirty(struct quad_buffer_head *); /* dentry.c */ -void hpfs_set_dentry_operations(struct dentry *); +extern const struct dentry_operations hpfs_dentry_operations; /* dir.c */ diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index 49935ba78db8a..b30426b1fc978 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -550,6 +550,7 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) /* Fill superblock stuff */ s->s_magic = HPFS_SUPER_MAGIC; s->s_op = &hpfs_sops; + s->s_d_op = &hpfs_dentry_operations; sbi->sb_root = superblock->root; sbi->sb_fs_size = superblock->n_sectors; @@ -651,7 +652,6 @@ static int hpfs_fill_super(struct super_block *s, void *options, int silent) iput(root); goto bail0; } - hpfs_set_dentry_operations(s->s_root); /* * find the root directory's . pointer & finish filling in the inode From b5c7d208ca48e7769aa38731665283790de49840 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Jan 2011 16:19:20 -0500 Subject: [PATCH 19/41] convert smbfs Signed-off-by: Al Viro --- drivers/staging/smbfs/dir.c | 13 ------------- drivers/staging/smbfs/inode.c | 4 ++++ drivers/staging/smbfs/proto.h | 2 ++ 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/drivers/staging/smbfs/dir.c b/drivers/staging/smbfs/dir.c index dd612f50749f6..87a3a9bd58428 100644 --- a/drivers/staging/smbfs/dir.c +++ b/drivers/staging/smbfs/dir.c @@ -403,12 +403,6 @@ smb_delete_dentry(const struct dentry *dentry) void smb_new_dentry(struct dentry *dentry) { - struct smb_sb_info *server = server_from_dentry(dentry); - - if (server->mnt->flags & SMB_MOUNT_CASE) - d_set_d_op(dentry, &smbfs_dentry_operations_case); - else - d_set_d_op(dentry, &smbfs_dentry_operations); dentry->d_time = jiffies; } @@ -440,7 +434,6 @@ smb_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) struct smb_fattr finfo; struct inode *inode; int error; - struct smb_sb_info *server; error = -ENAMETOOLONG; if (dentry->d_name.len > SMB_MAXNAMELEN) @@ -468,12 +461,6 @@ smb_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) inode = smb_iget(dir->i_sb, &finfo); if (inode) { add_entry: - server = server_from_dentry(dentry); - if (server->mnt->flags & SMB_MOUNT_CASE) - d_set_d_op(dentry, &smbfs_dentry_operations_case); - else - d_set_d_op(dentry, &smbfs_dentry_operations); - d_add(dentry, inode); smb_renew_times(dentry); error = 0; diff --git a/drivers/staging/smbfs/inode.c b/drivers/staging/smbfs/inode.c index 244319dc97027..0778589d9e9e4 100644 --- a/drivers/staging/smbfs/inode.c +++ b/drivers/staging/smbfs/inode.c @@ -614,6 +614,10 @@ static int smb_fill_super(struct super_block *sb, void *raw_data, int silent) printk(KERN_ERR "smbfs: failed to start smbiod\n"); goto out_no_smbiod; } + if (server->mnt->flags & SMB_MOUNT_CASE) + sb->s_d_op = &smbfs_dentry_operations_case; + else + sb->s_d_op = &smbfs_dentry_operations; /* * Keep the super block locked while we get the root inode. diff --git a/drivers/staging/smbfs/proto.h b/drivers/staging/smbfs/proto.h index 05939a6f43e62..3883cb16a3f68 100644 --- a/drivers/staging/smbfs/proto.h +++ b/drivers/staging/smbfs/proto.h @@ -38,6 +38,8 @@ extern void smb_install_null_ops(struct smb_ops *ops); extern const struct file_operations smb_dir_operations; extern const struct inode_operations smb_dir_inode_operations; extern const struct inode_operations smb_dir_inode_operations_unix; +extern const struct dentry_operations smbfs_dentry_operations_case; +extern const struct dentry_operations smbfs_dentry_operations; extern void smb_new_dentry(struct dentry *dentry); extern void smb_renew_times(struct dentry *dentry); /* cache.c */ From 9501e4c48e1561443e1a16c2c9917ec6c63118a4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Jan 2011 16:25:02 -0500 Subject: [PATCH 20/41] switch coda Coda ->d_revalidate() actually checks for root, ->d_delete() is irrelevant. So we can use the same d_op for all coda dentries Signed-off-by: Al Viro --- fs/coda/dir.c | 4 +--- fs/coda/inode.c | 1 + include/linux/coda_linux.h | 2 ++ 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 29badd91360fd..9df71f0eb218b 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -61,7 +61,7 @@ static int coda_return_EIO(void) } #define CODA_EIO_ERROR ((void *) (coda_return_EIO)) -static const struct dentry_operations coda_dentry_operations = +const struct dentry_operations coda_dentry_operations = { .d_revalidate = coda_dentry_revalidate, .d_delete = coda_dentry_delete, @@ -126,8 +126,6 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struc return ERR_PTR(error); exit: - d_set_d_op(entry, &coda_dentry_operations); - if (inode && (type & CODA_NOCACHE)) coda_flag_inode(inode, C_VATTR | C_PURGE); diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 50dc7d189f562..bd7fde2721a8b 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -193,6 +193,7 @@ static int coda_fill_super(struct super_block *sb, void *data, int silent) sb->s_blocksize_bits = 12; sb->s_magic = CODA_SUPER_MAGIC; sb->s_op = &coda_super_operations; + sb->s_d_op = &coda_dentry_operations; sb->s_bdi = &vc->bdi; /* get root fid from Venus: this needs the root inode */ diff --git a/include/linux/coda_linux.h b/include/linux/coda_linux.h index 4ccc59c1ea82b..490c56b408647 100644 --- a/include/linux/coda_linux.h +++ b/include/linux/coda_linux.h @@ -27,6 +27,8 @@ extern const struct inode_operations coda_dir_inode_operations; extern const struct inode_operations coda_file_inode_operations; extern const struct inode_operations coda_ioctl_inode_operations; +extern const struct dentry_operations coda_dentry_operations; + extern const struct address_space_operations coda_file_aops; extern const struct address_space_operations coda_symlink_aops; From 31a203df9c109480fc6d48ba0a68763e89199acb Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Jan 2011 16:36:09 -0500 Subject: [PATCH 21/41] take coda-private headers out of include/linux Signed-off-by: Al Viro --- Documentation/magic-number.txt | 2 +- fs/coda/cache.c | 5 ++--- fs/coda/cnode.c | 3 +-- {include/linux => fs/coda}/coda_cache.h | 0 {include/linux => fs/coda}/coda_fs_i.h | 0 fs/coda/coda_linux.c | 3 +-- {include/linux => fs/coda}/coda_linux.h | 2 +- fs/coda/dir.c | 5 ++--- fs/coda/file.c | 3 +-- fs/coda/inode.c | 5 ++--- fs/coda/pioctl.c | 4 ++-- fs/coda/psdev.c | 4 ++-- fs/coda/symlink.c | 4 ++-- fs/coda/upcall.c | 5 ++--- 14 files changed, 19 insertions(+), 26 deletions(-) rename {include/linux => fs/coda}/coda_cache.h (100%) rename {include/linux => fs/coda}/coda_fs_i.h (100%) rename {include/linux => fs/coda}/coda_linux.h (99%) diff --git a/Documentation/magic-number.txt b/Documentation/magic-number.txt index 505f19607542d..4b12abcb2ad3c 100644 --- a/Documentation/magic-number.txt +++ b/Documentation/magic-number.txt @@ -150,7 +150,7 @@ NBD_REPLY_MAGIC 0x96744668 nbd_reply include/linux/nbd.h STL_BOARDMAGIC 0xa2267f52 stlbrd include/linux/stallion.h ENI155_MAGIC 0xa54b872d midway_eprom drivers/atm/eni.h SCI_MAGIC 0xbabeface gs_port drivers/char/sh-sci.h -CODA_MAGIC 0xC0DAC0DA coda_file_info include/linux/coda_fs_i.h +CODA_MAGIC 0xC0DAC0DA coda_file_info fs/coda/coda_fs_i.h DPMEM_MAGIC 0xc0ffee11 gdt_pci_sram drivers/scsi/gdth.h STLI_PORTMAGIC 0xe671c7a1 stliport include/linux/istallion.h YAM_MAGIC 0xF10A7654 yam_port drivers/net/hamradio/yam.c diff --git a/fs/coda/cache.c b/fs/coda/cache.c index 5525e1c660fd5..6901578761841 100644 --- a/fs/coda/cache.c +++ b/fs/coda/cache.c @@ -20,10 +20,9 @@ #include #include -#include #include -#include -#include +#include "coda_linux.h" +#include "coda_cache.h" static atomic_t permission_epoch = ATOMIC_INIT(0); diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c index 602240569c89a..6475877b07632 100644 --- a/fs/coda/cnode.c +++ b/fs/coda/cnode.c @@ -7,9 +7,8 @@ #include #include -#include -#include #include +#include "coda_linux.h" static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2) { diff --git a/include/linux/coda_cache.h b/fs/coda/coda_cache.h similarity index 100% rename from include/linux/coda_cache.h rename to fs/coda/coda_cache.h diff --git a/include/linux/coda_fs_i.h b/fs/coda/coda_fs_i.h similarity index 100% rename from include/linux/coda_fs_i.h rename to fs/coda/coda_fs_i.h diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c index bf4a3fd3c8e33..2bdbcc11b373a 100644 --- a/fs/coda/coda_linux.c +++ b/fs/coda/coda_linux.c @@ -17,9 +17,8 @@ #include #include -#include #include -#include +#include "coda_linux.h" /* initialize the debugging variables */ int coda_fake_statfs; diff --git a/include/linux/coda_linux.h b/fs/coda/coda_linux.h similarity index 99% rename from include/linux/coda_linux.h rename to fs/coda/coda_linux.h index 490c56b408647..9b0c5323890b7 100644 --- a/include/linux/coda_linux.h +++ b/fs/coda/coda_linux.h @@ -20,7 +20,7 @@ #include #include #include -#include +#include "coda_fs_i.h" /* operations */ extern const struct inode_operations coda_dir_inode_operations; diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 9df71f0eb218b..2b8dae4d121ee 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -23,10 +23,9 @@ #include #include -#include #include -#include -#include +#include "coda_linux.h" +#include "coda_cache.h" #include "coda_int.h" diff --git a/fs/coda/file.c b/fs/coda/file.c index c8b50ba4366a3..0433057be3305 100644 --- a/fs/coda/file.c +++ b/fs/coda/file.c @@ -21,10 +21,9 @@ #include #include -#include -#include #include +#include "coda_linux.h" #include "coda_int.h" static ssize_t diff --git a/fs/coda/inode.c b/fs/coda/inode.c index bd7fde2721a8b..261d86f9caec1 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -28,10 +28,9 @@ #include #include -#include #include -#include -#include +#include "coda_linux.h" +#include "coda_cache.h" #include "coda_int.h" diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c index 741f0bd03918e..6cbb3afb36dc2 100644 --- a/fs/coda/pioctl.c +++ b/fs/coda/pioctl.c @@ -19,10 +19,10 @@ #include #include -#include -#include #include +#include "coda_linux.h" + /* pioctl ops */ static int coda_ioctl_permission(struct inode *inode, int mask, unsigned int flags); static long coda_pioctl(struct file *filp, unsigned int cmd, diff --git a/fs/coda/psdev.c b/fs/coda/psdev.c index 62647a8595e47..8f616e0e252c3 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c @@ -43,10 +43,10 @@ #include #include -#include -#include #include +#include "coda_linux.h" + #include "coda_int.h" /* statistics */ diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c index af78f007a2b05..ab94ef63caefe 100644 --- a/fs/coda/symlink.c +++ b/fs/coda/symlink.c @@ -16,9 +16,9 @@ #include #include -#include #include -#include + +#include "coda_linux.h" static int coda_symlink_filler(struct file *file, struct page *page) { diff --git a/fs/coda/upcall.c b/fs/coda/upcall.c index c3563cab97584..9727e0c525793 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -33,10 +33,9 @@ #include #include -#include #include -#include -#include +#include "coda_linux.h" +#include "coda_cache.h" #include "coda_int.h" From d463a0c4b53a8fab505fd9aa3a1a04cb9f411b78 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Jan 2011 16:41:05 -0500 Subject: [PATCH 22/41] switch configfs Signed-off-by: Al Viro --- fs/configfs/configfs_internal.h | 1 + fs/configfs/dir.c | 6 +----- fs/configfs/mount.c | 1 + 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index 026cf68553a41..82bda8fdfc1cb 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h @@ -90,6 +90,7 @@ extern const struct file_operations configfs_file_operations; extern const struct file_operations bin_fops; extern const struct inode_operations configfs_dir_inode_operations; extern const struct inode_operations configfs_symlink_inode_operations; +extern const struct dentry_operations configfs_dentry_ops; extern int configfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname); diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 36637a8c1ed33..90ff3cb10de31 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -72,7 +72,7 @@ static int configfs_d_delete(const struct dentry *dentry) return 1; } -static const struct dentry_operations configfs_dentry_ops = { +const struct dentry_operations configfs_dentry_ops = { .d_iput = configfs_d_iput, /* simple_delete_dentry() isn't exported */ .d_delete = configfs_d_delete, @@ -442,7 +442,6 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den return error; } - d_set_d_op(dentry, &configfs_dentry_ops); d_rehash(dentry); return 0; @@ -489,7 +488,6 @@ static struct dentry * configfs_lookup(struct inode *dir, */ if (dentry->d_name.len > NAME_MAX) return ERR_PTR(-ENAMETOOLONG); - d_set_d_op(dentry, &configfs_dentry_ops); d_add(dentry, NULL); return NULL; } @@ -683,7 +681,6 @@ static int create_default_group(struct config_group *parent_group, ret = -ENOMEM; child = d_alloc(parent, &name); if (child) { - d_set_d_op(child, &configfs_dentry_ops); d_add(child, NULL); ret = configfs_attach_group(&parent_group->cg_item, @@ -1681,7 +1678,6 @@ int configfs_register_subsystem(struct configfs_subsystem *subsys) err = -ENOMEM; dentry = d_alloc(configfs_sb->s_root, &name); if (dentry) { - d_set_d_op(dentry, &configfs_dentry_ops); d_add(dentry, NULL); err = configfs_attach_group(sd->s_element, &group->cg_item, diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index 7d3607febe1c7..ecc62178beda9 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -101,6 +101,7 @@ static int configfs_fill_super(struct super_block *sb, void *data, int silent) configfs_root_group.cg_item.ci_dentry = root; root->d_fsdata = &configfs_root; sb->s_root = root; + sb->s_d_op = &configfs_dentry_ops; /* the rest get that */ return 0; } From a129880dafaa3c80eb0bae714da38088ccc2ce21 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Jan 2011 16:45:19 -0500 Subject: [PATCH 23/41] switch affs either d_op instance would work for root, actually... Signed-off-by: Al Viro --- fs/affs/affs.h | 1 + fs/affs/namei.c | 3 +-- fs/affs/super.c | 6 +++++- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/fs/affs/affs.h b/fs/affs/affs.h index a8cbdeb34025c..0e95f73a70232 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h @@ -201,6 +201,7 @@ extern const struct address_space_operations affs_aops; extern const struct address_space_operations affs_aops_ofs; extern const struct dentry_operations affs_dentry_operations; +extern const struct dentry_operations affs_intl_dentry_operations; static inline void affs_set_blocksize(struct super_block *sb, int size) diff --git a/fs/affs/namei.c b/fs/affs/namei.c index 944a4042fb65a..e3e9efc1fdd82 100644 --- a/fs/affs/namei.c +++ b/fs/affs/namei.c @@ -32,7 +32,7 @@ const struct dentry_operations affs_dentry_operations = { .d_compare = affs_compare_dentry, }; -static const struct dentry_operations affs_intl_dentry_operations = { +const struct dentry_operations affs_intl_dentry_operations = { .d_hash = affs_intl_hash_dentry, .d_compare = affs_intl_compare_dentry, }; @@ -240,7 +240,6 @@ affs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) if (IS_ERR(inode)) return ERR_CAST(inode); } - d_set_d_op(dentry, AFFS_SB(sb)->s_flags & SF_INTL ? &affs_intl_dentry_operations : &affs_dentry_operations); d_add(dentry, inode); return NULL; } diff --git a/fs/affs/super.c b/fs/affs/super.c index d39081bbe7ce9..b31507d0f9b96 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -477,12 +477,16 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent) goto out_error_noinode; } + if (AFFS_SB(sb)->s_flags & SF_INTL) + sb->s_d_op = &affs_intl_dentry_operations; + else + sb->s_d_op = &affs_dentry_operations; + sb->s_root = d_alloc_root(root_inode); if (!sb->s_root) { printk(KERN_ERR "AFFS: Get root inode failed\n"); goto out_error; } - d_set_d_op(sb->s_root, &affs_dentry_operations); pr_debug("AFFS: s_flags=%lX\n",sb->s_flags); return 0; From f772c4a6a320ec25d94ba951881474eeef1b7f48 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Jan 2011 16:47:00 -0500 Subject: [PATCH 24/41] switch hostfs ->d_delete() doesn't matter for s_root anyway Signed-off-by: Al Viro --- fs/hostfs/hostfs_kern.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index d3244d949a4ea..2638c834ed281 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -612,7 +612,6 @@ struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry, goto out_put; d_add(dentry, inode); - d_set_d_op(dentry, &hostfs_dentry_ops); return NULL; out_put: @@ -922,6 +921,7 @@ static int hostfs_fill_sb_common(struct super_block *sb, void *d, int silent) sb->s_blocksize_bits = 10; sb->s_magic = HOSTFS_SUPER_MAGIC; sb->s_op = &hostfs_sbops; + sb->s_d_op = &hostfs_dentry_ops; sb->s_maxbytes = MAX_LFS_FILESIZE; /* NULL is printed as by sprintf: avoid that. */ From c74a1cbb3cac348f276fabc381758f5b0b4713b2 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Jan 2011 16:59:34 -0500 Subject: [PATCH 25/41] pass default dentry_operations to mount_pseudo() Signed-off-by: Al Viro --- arch/ia64/kernel/perfmon.c | 6 ++++-- drivers/mtd/mtdchar.c | 2 +- fs/anon_inodes.c | 21 +++++++++++---------- fs/block_dev.c | 2 +- fs/libfs.c | 4 +++- fs/pipe.c | 4 ++-- include/linux/fs.h | 4 +++- net/socket.c | 30 +++++++++++++++--------------- 8 files changed, 40 insertions(+), 33 deletions(-) diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c index d92d5b5161fc3..ac76da099a6d4 100644 --- a/arch/ia64/kernel/perfmon.c +++ b/arch/ia64/kernel/perfmon.c @@ -617,11 +617,14 @@ pfm_get_unmapped_area(struct file *file, unsigned long addr, unsigned long len, return get_unmapped_area(file, addr, len, pgoff, flags); } +/* forward declaration */ +static static const struct dentry_operations pfmfs_dentry_operations; static struct dentry * pfmfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - return mount_pseudo(fs_type, "pfm:", NULL, PFMFS_MAGIC); + return mount_pseudo(fs_type, "pfm:", NULL, &pfmfs_dentry_operations, + PFMFS_MAGIC); } static struct file_system_type pfm_fs_type = { @@ -2232,7 +2235,6 @@ pfm_alloc_file(pfm_context_t *ctx) } path.mnt = mntget(pfmfs_mnt); - d_set_d_op(path.dentry, &pfmfs_dentry_operations); d_add(path.dentry, inode); file = alloc_file(&path, FMODE_READ, &pfm_file_ops); diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c index f511dd15fd318..ee4bb3330bdfd 100644 --- a/drivers/mtd/mtdchar.c +++ b/drivers/mtd/mtdchar.c @@ -1134,7 +1134,7 @@ static const struct file_operations mtd_fops = { static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - return mount_pseudo(fs_type, "mtd_inode:", NULL, MTD_INODE_FS_MAGIC); + return mount_pseudo(fs_type, "mtd_inode:", NULL, NULL, MTD_INODE_FS_MAGIC); } static struct file_system_type mtd_inodefs_type = { diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 5fd38112a6ca5..549a53cc02835 100644 --- a/fs/anon_inodes.c +++ b/fs/anon_inodes.c @@ -26,12 +26,6 @@ static struct vfsmount *anon_inode_mnt __read_mostly; static struct inode *anon_inode_inode; static const struct file_operations anon_inode_fops; -static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_pseudo(fs_type, "anon_inode:", NULL, ANON_INODE_FS_MAGIC); -} - /* * anon_inodefs_dname() is called from d_path(). */ @@ -41,14 +35,22 @@ static char *anon_inodefs_dname(struct dentry *dentry, char *buffer, int buflen) dentry->d_name.name); } +static const struct dentry_operations anon_inodefs_dentry_operations = { + .d_dname = anon_inodefs_dname, +}; + +static struct dentry *anon_inodefs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + return mount_pseudo(fs_type, "anon_inode:", NULL, + &anon_inodefs_dentry_operations, ANON_INODE_FS_MAGIC); +} + static struct file_system_type anon_inode_fs_type = { .name = "anon_inodefs", .mount = anon_inodefs_mount, .kill_sb = kill_anon_super, }; -static const struct dentry_operations anon_inodefs_dentry_operations = { - .d_dname = anon_inodefs_dname, -}; /* * nop .set_page_dirty method so that people can use .page_mkwrite on @@ -113,7 +115,6 @@ struct file *anon_inode_getfile(const char *name, */ ihold(anon_inode_inode); - d_set_d_op(path.dentry, &anon_inodefs_dentry_operations); d_instantiate(path.dentry, anon_inode_inode); error = -ENFILE; diff --git a/fs/block_dev.c b/fs/block_dev.c index 771f23527010d..88da70355aa35 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -473,7 +473,7 @@ static const struct super_operations bdev_sops = { static struct dentry *bd_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - return mount_pseudo(fs_type, "bdev:", &bdev_sops, 0x62646576); + return mount_pseudo(fs_type, "bdev:", &bdev_sops, NULL, 0x62646576); } static struct file_system_type bd_type = { diff --git a/fs/libfs.c b/fs/libfs.c index 889311e3d06b6..c88eab55aec95 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -217,7 +217,8 @@ static const struct super_operations simple_super_operations = { * will never be mountable) */ struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name, - const struct super_operations *ops, unsigned long magic) + const struct super_operations *ops, + const struct dentry_operations *dops, unsigned long magic) { struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); struct dentry *dentry; @@ -254,6 +255,7 @@ struct dentry *mount_pseudo(struct file_system_type *fs_type, char *name, dentry->d_parent = dentry; d_instantiate(dentry, root); s->s_root = dentry; + s->s_d_op = dops; s->s_flags |= MS_ACTIVE; return dget(s->s_root); diff --git a/fs/pipe.c b/fs/pipe.c index 68f1f8e4e23b7..6b0255a74f362 100644 --- a/fs/pipe.c +++ b/fs/pipe.c @@ -1004,7 +1004,6 @@ struct file *create_write_pipe(int flags) goto err_inode; path.mnt = mntget(pipe_mnt); - d_set_d_op(path.dentry, &pipefs_dentry_operations); d_instantiate(path.dentry, inode); err = -ENFILE; @@ -1266,7 +1265,8 @@ static const struct super_operations pipefs_ops = { static struct dentry *pipefs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *data) { - return mount_pseudo(fs_type, "pipe:", &pipefs_ops, PIPEFS_MAGIC); + return mount_pseudo(fs_type, "pipe:", &pipefs_ops, + &pipefs_dentry_operations, PIPEFS_MAGIC); } static struct file_system_type pipe_fs_type = { diff --git a/include/linux/fs.h b/include/linux/fs.h index 3e4c27486e744..c0701288d2047 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h @@ -1835,7 +1835,9 @@ struct super_block *sget(struct file_system_type *type, int (*set)(struct super_block *,void *), void *data); extern struct dentry *mount_pseudo(struct file_system_type *, char *, - const struct super_operations *ops, unsigned long); + const struct super_operations *ops, + const struct dentry_operations *dops, + unsigned long); extern void simple_set_mnt(struct vfsmount *mnt, struct super_block *sb); static inline void sb_mark_dirty(struct super_block *sb) diff --git a/net/socket.c b/net/socket.c index ccc576a6a5083..ac2219f90d5dd 100644 --- a/net/socket.c +++ b/net/socket.c @@ -306,20 +306,6 @@ static const struct super_operations sockfs_ops = { .statfs = simple_statfs, }; -static struct dentry *sockfs_mount(struct file_system_type *fs_type, - int flags, const char *dev_name, void *data) -{ - return mount_pseudo(fs_type, "socket:", &sockfs_ops, SOCKFS_MAGIC); -} - -static struct vfsmount *sock_mnt __read_mostly; - -static struct file_system_type sock_fs_type = { - .name = "sockfs", - .mount = sockfs_mount, - .kill_sb = kill_anon_super, -}; - /* * sockfs_dname() is called from d_path(). */ @@ -333,6 +319,21 @@ static const struct dentry_operations sockfs_dentry_operations = { .d_dname = sockfs_dname, }; +static struct dentry *sockfs_mount(struct file_system_type *fs_type, + int flags, const char *dev_name, void *data) +{ + return mount_pseudo(fs_type, "socket:", &sockfs_ops, + &sockfs_dentry_operations, SOCKFS_MAGIC); +} + +static struct vfsmount *sock_mnt __read_mostly; + +static struct file_system_type sock_fs_type = { + .name = "sockfs", + .mount = sockfs_mount, + .kill_sb = kill_anon_super, +}; + /* * Obtains the first available file descriptor and sets it up for use. * @@ -368,7 +369,6 @@ static int sock_alloc_file(struct socket *sock, struct file **f, int flags) } path.mnt = mntget(sock_mnt); - d_set_d_op(path.dentry, &sockfs_dentry_operations); d_instantiate(path.dentry, SOCK_INODE(sock)); SOCK_INODE(sock)->i_fop = &socket_file_ops; From 98cd3fb0a2c376f583216ec35f66175a71b2ef67 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Jan 2011 17:10:55 -0500 Subject: [PATCH 26/41] switch 9p here we actually *want* ->d_op for root; setting it allows to get rid of kludge in v9fs_kill_super() since now we have proper ->d_release() for root and don't need to call it manually. Signed-off-by: Al Viro --- fs/9p/v9fs_vfs.h | 1 - fs/9p/vfs_dentry.c | 2 +- fs/9p/vfs_inode.c | 5 ----- fs/9p/vfs_super.c | 8 +++++--- 4 files changed, 6 insertions(+), 10 deletions(-) diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index bab0eac873f40..b789f8e597ece 100644 --- a/fs/9p/v9fs_vfs.h +++ b/fs/9p/v9fs_vfs.h @@ -59,7 +59,6 @@ void v9fs_stat2inode_dotl(struct p9_stat_dotl *, struct inode *); int v9fs_dir_release(struct inode *inode, struct file *filp); int v9fs_file_open(struct inode *inode, struct file *file); void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat); -void v9fs_dentry_release(struct dentry *); int v9fs_uflags2omode(int uflags, int extended); ssize_t v9fs_file_readn(struct file *, char *, char __user *, u32, u64); diff --git a/fs/9p/vfs_dentry.c b/fs/9p/vfs_dentry.c index 466d2a4fc5cb8..233b7d4ffe5e6 100644 --- a/fs/9p/vfs_dentry.c +++ b/fs/9p/vfs_dentry.c @@ -86,7 +86,7 @@ static int v9fs_cached_dentry_delete(const struct dentry *dentry) * */ -void v9fs_dentry_release(struct dentry *dentry) +static void v9fs_dentry_release(struct dentry *dentry) { struct v9fs_dentry *dent; struct p9_fid *temp, *current_fid; diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 5076eeb955024..b76a40bdf4c20 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -699,11 +699,6 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry, goto error_iput; inst_out: - if (v9ses->cache) - d_set_d_op(dentry, &v9fs_cached_dentry_operations); - else - d_set_d_op(dentry, &v9fs_dentry_operations); - d_add(dentry, inode); return NULL; diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index c55c614500ad4..dbaabe3b8131f 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -141,6 +141,11 @@ static struct dentry *v9fs_mount(struct file_system_type *fs_type, int flags, } v9fs_fill_super(sb, v9ses, flags, data); + if (v9ses->cache) + sb->s_d_op = &v9fs_cached_dentry_operations; + else + sb->s_d_op = &v9fs_dentry_operations; + inode = v9fs_get_inode(sb, S_IFDIR | mode); if (IS_ERR(inode)) { retval = PTR_ERR(inode); @@ -217,9 +222,6 @@ static void v9fs_kill_super(struct super_block *s) P9_DPRINTK(P9_DEBUG_VFS, " %p\n", s); - if (s->s_root) - v9fs_dentry_release(s->s_root); /* clunk root */ - kill_anon_super(s); v9fs_session_cancel(v9ses); From 0378c4051a621303ae919f1cee832206a4c1aa68 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Jan 2011 17:25:03 -0500 Subject: [PATCH 27/41] switch ncpfs merge dentry_operations for root and non-root Signed-off-by: Al Viro --- fs/ncpfs/dir.c | 15 ++++----------- fs/ncpfs/inode.c | 2 +- include/linux/ncp_fs.h | 2 +- 3 files changed, 6 insertions(+), 13 deletions(-) diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 28f136d4aaec6..119accd07dd58 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -82,7 +82,7 @@ static int ncp_compare_dentry(const struct dentry *, const struct inode *, unsigned int, const char *, const struct qstr *); static int ncp_delete_dentry(const struct dentry *); -static const struct dentry_operations ncp_dentry_operations = +const struct dentry_operations ncp_dentry_operations = { .d_revalidate = ncp_lookup_validate, .d_hash = ncp_hash_dentry, @@ -90,14 +90,6 @@ static const struct dentry_operations ncp_dentry_operations = .d_delete = ncp_delete_dentry, }; -const struct dentry_operations ncp_root_dentry_operations = -{ - .d_hash = ncp_hash_dentry, - .d_compare = ncp_compare_dentry, - .d_delete = ncp_delete_dentry, -}; - - #define ncp_namespace(i) (NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber]) static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator) @@ -309,6 +301,9 @@ ncp_lookup_validate(struct dentry *dentry, struct nameidata *nd) int res, val = 0, len; __u8 __name[NCP_MAXPATHLEN + 1]; + if (dentry == dentry->d_sb->s_root) + return 1; + if (nd->flags & LOOKUP_RCU) return -ECHILD; @@ -637,7 +632,6 @@ ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, entry->ino = iunique(dir->i_sb, 2); inode = ncp_iget(dir->i_sb, entry); if (inode) { - d_set_d_op(newdent, &ncp_dentry_operations); d_instantiate(newdent, inode); if (!hashed) d_rehash(newdent); @@ -893,7 +887,6 @@ static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struc if (inode) { ncp_new_dentry(dentry); add_entry: - d_set_d_op(dentry, &ncp_dentry_operations); d_add(dentry, inode); error = 0; } diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 9b39a5dd41314..8b8bebbb96014 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -544,6 +544,7 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) sb->s_blocksize_bits = 10; sb->s_magic = NCP_SUPER_MAGIC; sb->s_op = &ncp_sops; + sb->s_d_op = &ncp_dentry_operations; sb->s_bdi = &server->bdi; server = NCP_SBP(sb); @@ -723,7 +724,6 @@ static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) sb->s_root = d_alloc_root(root_inode); if (!sb->s_root) goto out_no_root; - d_set_d_op(sb->s_root, &ncp_root_dentry_operations); return 0; out_no_root: diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h index 1c27f201c8566..2d79c8a58598a 100644 --- a/include/linux/ncp_fs.h +++ b/include/linux/ncp_fs.h @@ -204,7 +204,7 @@ void ncp_update_inode2(struct inode *, struct ncp_entry_info *); /* linux/fs/ncpfs/dir.c */ extern const struct inode_operations ncp_dir_inode_operations; extern const struct file_operations ncp_dir_operations; -extern const struct dentry_operations ncp_root_dentry_operations; +extern const struct dentry_operations ncp_dentry_operations; int ncp_conn_logged_in(struct super_block *); int ncp_date_dos2unix(__le16 time, __le16 date); void ncp_date_unix2dos(int unix_date, __le16 * time, __le16 * date); From 32c419d95f3d1da891ab9bd032a214ee05b94ed4 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Jan 2011 17:37:47 -0500 Subject: [PATCH 28/41] move internal-only parts of ncpfs headers to fs/ncpfs Signed-off-by: Al Viro --- fs/ncpfs/dir.c | 4 +- fs/ncpfs/file.c | 3 +- fs/ncpfs/inode.c | 4 +- fs/ncpfs/ioctl.c | 4 +- fs/ncpfs/mmap.c | 4 +- fs/ncpfs/ncp_fs.h | 98 +++++++++++++++++++++++ {include/linux => fs/ncpfs}/ncp_fs_i.h | 0 {include/linux => fs/ncpfs}/ncp_fs_sb.h | 24 ++++-- fs/ncpfs/ncplib_kernel.c | 2 +- fs/ncpfs/ncplib_kernel.h | 2 - fs/ncpfs/ncpsign_kernel.c | 1 + fs/ncpfs/ncpsign_kernel.h | 2 - fs/ncpfs/sock.c | 2 +- fs/ncpfs/symlink.c | 4 +- include/linux/ncp_fs.h | 100 ------------------------ include/linux/ncp_mount.h | 22 ------ 16 files changed, 126 insertions(+), 150 deletions(-) create mode 100644 fs/ncpfs/ncp_fs.h rename {include/linux => fs/ncpfs}/ncp_fs_i.h (100%) rename {include/linux => fs/ncpfs}/ncp_fs_sb.h (86%) diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 119accd07dd58..f6946bb5cb553 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -21,9 +21,7 @@ #include #include -#include - -#include "ncplib_kernel.h" +#include "ncp_fs.h" static void ncp_read_volume_list(struct file *, void *, filldir_t, struct ncp_cache_control *); diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index cb50aaf981dff..0ed65e0c3dfe2 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -18,8 +18,7 @@ #include #include -#include -#include "ncplib_kernel.h" +#include "ncp_fs.h" static int ncp_fsync(struct file *file, int datasync) { diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 8b8bebbb96014..00a1d1c3d3a49 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -31,11 +31,9 @@ #include #include -#include - #include -#include "ncplib_kernel.h" +#include "ncp_fs.h" #include "getopt.h" #define NCP_DEFAULT_FILE_MODE 0600 diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index d40a547e33770..790e92a9ec63b 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -20,11 +20,9 @@ #include #include -#include - #include -#include "ncplib_kernel.h" +#include "ncp_fs.h" /* maximum limit for ncp_objectname_ioctl */ #define NCP_OBJECT_NAME_MAX_LEN 4096 diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c index 56f5b3a0e1ee3..a7c07b44b100b 100644 --- a/fs/ncpfs/mmap.c +++ b/fs/ncpfs/mmap.c @@ -16,12 +16,12 @@ #include #include #include -#include -#include "ncplib_kernel.h" #include #include +#include "ncp_fs.h" + /* * Fill in the supplied page for mmap * XXX: how are we excluding truncate/invalidate here? Maybe need to lock diff --git a/fs/ncpfs/ncp_fs.h b/fs/ncpfs/ncp_fs.h new file mode 100644 index 0000000000000..31831afe1c3b2 --- /dev/null +++ b/fs/ncpfs/ncp_fs.h @@ -0,0 +1,98 @@ +#include +#include "ncp_fs_i.h" +#include "ncp_fs_sb.h" + +/* define because it is easy to change PRINTK to {*}PRINTK */ +#define PRINTK(format, args...) printk(KERN_DEBUG format , ## args) + +#undef NCPFS_PARANOIA +#ifdef NCPFS_PARANOIA +#define PPRINTK(format, args...) PRINTK(format , ## args) +#else +#define PPRINTK(format, args...) +#endif + +#ifndef DEBUG_NCP +#define DEBUG_NCP 0 +#endif +#if DEBUG_NCP > 0 +#define DPRINTK(format, args...) PRINTK(format , ## args) +#else +#define DPRINTK(format, args...) +#endif +#if DEBUG_NCP > 1 +#define DDPRINTK(format, args...) PRINTK(format , ## args) +#else +#define DDPRINTK(format, args...) +#endif + +#define NCP_MAX_RPC_TIMEOUT (6*HZ) + + +struct ncp_entry_info { + struct nw_info_struct i; + ino_t ino; + int opened; + int access; + unsigned int volume; + __u8 file_handle[6]; +}; + +static inline struct ncp_server *NCP_SBP(const struct super_block *sb) +{ + return sb->s_fs_info; +} + +#define NCP_SERVER(inode) NCP_SBP((inode)->i_sb) +static inline struct ncp_inode_info *NCP_FINFO(const struct inode *inode) +{ + return container_of(inode, struct ncp_inode_info, vfs_inode); +} + +/* linux/fs/ncpfs/inode.c */ +int ncp_notify_change(struct dentry *, struct iattr *); +struct inode *ncp_iget(struct super_block *, struct ncp_entry_info *); +void ncp_update_inode(struct inode *, struct ncp_entry_info *); +void ncp_update_inode2(struct inode *, struct ncp_entry_info *); + +/* linux/fs/ncpfs/dir.c */ +extern const struct inode_operations ncp_dir_inode_operations; +extern const struct file_operations ncp_dir_operations; +extern const struct dentry_operations ncp_dentry_operations; +int ncp_conn_logged_in(struct super_block *); +int ncp_date_dos2unix(__le16 time, __le16 date); +void ncp_date_unix2dos(int unix_date, __le16 * time, __le16 * date); + +/* linux/fs/ncpfs/ioctl.c */ +long ncp_ioctl(struct file *, unsigned int, unsigned long); +long ncp_compat_ioctl(struct file *, unsigned int, unsigned long); + +/* linux/fs/ncpfs/sock.c */ +int ncp_request2(struct ncp_server *server, int function, + void* reply, int max_reply_size); +static inline int ncp_request(struct ncp_server *server, int function) { + return ncp_request2(server, function, server->packet, server->packet_size); +} +int ncp_connect(struct ncp_server *server); +int ncp_disconnect(struct ncp_server *server); +void ncp_lock_server(struct ncp_server *server); +void ncp_unlock_server(struct ncp_server *server); + +/* linux/fs/ncpfs/symlink.c */ +#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) +extern const struct address_space_operations ncp_symlink_aops; +int ncp_symlink(struct inode*, struct dentry*, const char*); +#endif + +/* linux/fs/ncpfs/file.c */ +extern const struct inode_operations ncp_file_inode_operations; +extern const struct file_operations ncp_file_operations; +int ncp_make_open(struct inode *, int); + +/* linux/fs/ncpfs/mmap.c */ +int ncp_mmap(struct file *, struct vm_area_struct *); + +/* linux/fs/ncpfs/ncplib_kernel.c */ +int ncp_make_closed(struct inode *); + +#include "ncplib_kernel.h" diff --git a/include/linux/ncp_fs_i.h b/fs/ncpfs/ncp_fs_i.h similarity index 100% rename from include/linux/ncp_fs_i.h rename to fs/ncpfs/ncp_fs_i.h diff --git a/include/linux/ncp_fs_sb.h b/fs/ncpfs/ncp_fs_sb.h similarity index 86% rename from include/linux/ncp_fs_sb.h rename to fs/ncpfs/ncp_fs_sb.h index d64b0e8943369..4af803f13516c 100644 --- a/include/linux/ncp_fs_sb.h +++ b/fs/ncpfs/ncp_fs_sb.h @@ -13,15 +13,30 @@ #include #include #include - -#ifdef __KERNEL__ - #include #define NCP_DEFAULT_OPTIONS 0 /* 2 for packet signatures */ struct sock; +struct ncp_mount_data_kernel { + unsigned long flags; /* NCP_MOUNT_* flags */ + unsigned int int_flags; /* internal flags */ +#define NCP_IMOUNT_LOGGEDIN_POSSIBLE 0x0001 + __kernel_uid32_t mounted_uid; /* Who may umount() this filesystem? */ + struct pid *wdog_pid; /* Who cares for our watchdog packets? */ + unsigned int ncp_fd; /* The socket to the ncp port */ + unsigned int time_out; /* How long should I wait after + sending a NCP request? */ + unsigned int retry_count; /* And how often should I retry? */ + unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; + __kernel_uid32_t uid; + __kernel_gid32_t gid; + __kernel_mode_t file_mode; + __kernel_mode_t dir_mode; + int info_fd; +}; + struct ncp_server { struct ncp_mount_data_kernel m; /* Nearly all of the mount data is of @@ -158,7 +173,4 @@ static inline void ncp_invalidate_conn(struct ncp_server *server) server->conn_status |= 0x01; } -#endif /* __KERNEL__ */ - #endif - diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c index a95615a0b6ac4..981a95617fc9f 100644 --- a/fs/ncpfs/ncplib_kernel.c +++ b/fs/ncpfs/ncplib_kernel.c @@ -11,7 +11,7 @@ -#include "ncplib_kernel.h" +#include "ncp_fs.h" static inline void assert_server_locked(struct ncp_server *server) { diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h index 1220df75ff228..09881e6aa5ad9 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h @@ -32,8 +32,6 @@ #include #endif /* CONFIG_NCPFS_NLS */ -#include - #define NCP_MIN_SYMLINK_SIZE 8 #define NCP_MAX_SYMLINK_SIZE 512 diff --git a/fs/ncpfs/ncpsign_kernel.c b/fs/ncpfs/ncpsign_kernel.c index d8b2d7e6910b1..08907599dcd23 100644 --- a/fs/ncpfs/ncpsign_kernel.c +++ b/fs/ncpfs/ncpsign_kernel.c @@ -11,6 +11,7 @@ #include #include #include +#include "ncp_fs.h" #include "ncpsign_kernel.h" /* i386: 32-bit, little endian, handles mis-alignment */ diff --git a/fs/ncpfs/ncpsign_kernel.h b/fs/ncpfs/ncpsign_kernel.h index 6451a68381ccf..d9a1438bb1f6e 100644 --- a/fs/ncpfs/ncpsign_kernel.h +++ b/fs/ncpfs/ncpsign_kernel.h @@ -8,8 +8,6 @@ #ifndef _NCPSIGN_KERNEL_H #define _NCPSIGN_KERNEL_H -#include - #ifdef CONFIG_NCPFS_PACKET_SIGNING void __sign_packet(struct ncp_server *server, const char *data, size_t size, __u32 totalsize, void *sign_buff); int sign_verify_reply(struct ncp_server *server, const char *data, size_t size, __u32 totalsize, const void *sign_buff); diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c index 668bd267346e5..3a1587222c8a7 100644 --- a/fs/ncpfs/sock.c +++ b/fs/ncpfs/sock.c @@ -28,7 +28,7 @@ #include #include -#include +#include "ncp_fs.h" #include "ncpsign_kernel.h" diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c index c634fd17b337c..661f861d80c6f 100644 --- a/fs/ncpfs/symlink.c +++ b/fs/ncpfs/symlink.c @@ -25,13 +25,11 @@ #include #include -#include #include #include #include #include -#include "ncplib_kernel.h" - +#include "ncp_fs.h" /* these magic numbers must appear in the symlink file -- this makes it a bit more resilient against the magic attributes being set on random files. */ diff --git a/include/linux/ncp_fs.h b/include/linux/ncp_fs.h index 2d79c8a58598a..e13eefef06534 100644 --- a/include/linux/ncp_fs.h +++ b/include/linux/ncp_fs.h @@ -143,104 +143,4 @@ struct ncp_nls_ioctl #define NCP_MAXPATHLEN 255 #define NCP_MAXNAMELEN 14 -#ifdef __KERNEL__ - -#include -#include - -/* define because it is easy to change PRINTK to {*}PRINTK */ -#define PRINTK(format, args...) printk(KERN_DEBUG format , ## args) - -#undef NCPFS_PARANOIA -#ifdef NCPFS_PARANOIA -#define PPRINTK(format, args...) PRINTK(format , ## args) -#else -#define PPRINTK(format, args...) -#endif - -#ifndef DEBUG_NCP -#define DEBUG_NCP 0 -#endif -#if DEBUG_NCP > 0 -#define DPRINTK(format, args...) PRINTK(format , ## args) -#else -#define DPRINTK(format, args...) -#endif -#if DEBUG_NCP > 1 -#define DDPRINTK(format, args...) PRINTK(format , ## args) -#else -#define DDPRINTK(format, args...) -#endif - -#define NCP_MAX_RPC_TIMEOUT (6*HZ) - - -struct ncp_entry_info { - struct nw_info_struct i; - ino_t ino; - int opened; - int access; - unsigned int volume; - __u8 file_handle[6]; -}; - -static inline struct ncp_server *NCP_SBP(const struct super_block *sb) -{ - return sb->s_fs_info; -} - -#define NCP_SERVER(inode) NCP_SBP((inode)->i_sb) -static inline struct ncp_inode_info *NCP_FINFO(const struct inode *inode) -{ - return container_of(inode, struct ncp_inode_info, vfs_inode); -} - -/* linux/fs/ncpfs/inode.c */ -int ncp_notify_change(struct dentry *, struct iattr *); -struct inode *ncp_iget(struct super_block *, struct ncp_entry_info *); -void ncp_update_inode(struct inode *, struct ncp_entry_info *); -void ncp_update_inode2(struct inode *, struct ncp_entry_info *); - -/* linux/fs/ncpfs/dir.c */ -extern const struct inode_operations ncp_dir_inode_operations; -extern const struct file_operations ncp_dir_operations; -extern const struct dentry_operations ncp_dentry_operations; -int ncp_conn_logged_in(struct super_block *); -int ncp_date_dos2unix(__le16 time, __le16 date); -void ncp_date_unix2dos(int unix_date, __le16 * time, __le16 * date); - -/* linux/fs/ncpfs/ioctl.c */ -long ncp_ioctl(struct file *, unsigned int, unsigned long); -long ncp_compat_ioctl(struct file *, unsigned int, unsigned long); - -/* linux/fs/ncpfs/sock.c */ -int ncp_request2(struct ncp_server *server, int function, - void* reply, int max_reply_size); -static inline int ncp_request(struct ncp_server *server, int function) { - return ncp_request2(server, function, server->packet, server->packet_size); -} -int ncp_connect(struct ncp_server *server); -int ncp_disconnect(struct ncp_server *server); -void ncp_lock_server(struct ncp_server *server); -void ncp_unlock_server(struct ncp_server *server); - -/* linux/fs/ncpfs/symlink.c */ -#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) -extern const struct address_space_operations ncp_symlink_aops; -int ncp_symlink(struct inode*, struct dentry*, const char*); -#endif - -/* linux/fs/ncpfs/file.c */ -extern const struct inode_operations ncp_file_inode_operations; -extern const struct file_operations ncp_file_operations; -int ncp_make_open(struct inode *, int); - -/* linux/fs/ncpfs/mmap.c */ -int ncp_mmap(struct file *, struct vm_area_struct *); - -/* linux/fs/ncpfs/ncplib_kernel.c */ -int ncp_make_closed(struct inode *); - -#endif /* __KERNEL__ */ - #endif /* _LINUX_NCP_FS_H */ diff --git a/include/linux/ncp_mount.h b/include/linux/ncp_mount.h index a2b549eb1ecaf..dfcbea2d889f7 100644 --- a/include/linux/ncp_mount.h +++ b/include/linux/ncp_mount.h @@ -68,26 +68,4 @@ struct ncp_mount_data_v4 { #define NCP_MOUNT_VERSION_V5 (5) /* Text only */ -#ifdef __KERNEL__ - -struct ncp_mount_data_kernel { - unsigned long flags; /* NCP_MOUNT_* flags */ - unsigned int int_flags; /* internal flags */ -#define NCP_IMOUNT_LOGGEDIN_POSSIBLE 0x0001 - __kernel_uid32_t mounted_uid; /* Who may umount() this filesystem? */ - struct pid *wdog_pid; /* Who cares for our watchdog packets? */ - unsigned int ncp_fd; /* The socket to the ncp port */ - unsigned int time_out; /* How long should I wait after - sending a NCP request? */ - unsigned int retry_count; /* And how often should I retry? */ - unsigned char mounted_vol[NCP_VOLNAME_LEN + 1]; - __kernel_uid32_t uid; - __kernel_gid32_t gid; - __kernel_mode_t file_mode; - __kernel_mode_t dir_mode; - int info_fd; -}; - -#endif /* __KERNEL__ */ - #endif From d61dcce2977d9abe855a5fe3570a81242209c23b Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Jan 2011 20:04:20 -0500 Subject: [PATCH 29/41] switch afs Signed-off-by: Al Viro --- fs/afs/dir.c | 4 +--- fs/afs/internal.h | 1 + fs/afs/super.c | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 34a3263d60a4c..e6a4ab980e316 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -62,7 +62,7 @@ const struct inode_operations afs_dir_inode_operations = { .setattr = afs_setattr, }; -static const struct dentry_operations afs_fs_dentry_operations = { +const struct dentry_operations afs_fs_dentry_operations = { .d_revalidate = afs_d_revalidate, .d_delete = afs_d_delete, .d_release = afs_d_release, @@ -582,8 +582,6 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry, } success: - d_set_d_op(dentry, &afs_fs_dentry_operations); - d_add(dentry, inode); _leave(" = 0 { vn=%u u=%u } -> { ino=%lu v=%llu }", fid.vnode, diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 6d4bc1c8ff60c..ab6db5abaf535 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -486,6 +486,7 @@ extern bool afs_cm_incoming_call(struct afs_call *); * dir.c */ extern const struct inode_operations afs_dir_inode_operations; +extern const struct dentry_operations afs_fs_dentry_operations; extern const struct file_operations afs_dir_file_operations; /* diff --git a/fs/afs/super.c b/fs/afs/super.c index f901a9d7c1110..fb240e8766d63 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -336,6 +336,7 @@ static int afs_fill_super(struct super_block *sb, void *data) if (!root) goto error; + sb->s_d_op = &afs_fs_dentry_operations; sb->s_root = root; _leave(" = 0"); From 66cb76666d69502fe982990b2cff5b6d607fd3b1 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Wed, 12 Jan 2011 20:04:37 -0500 Subject: [PATCH 30/41] sanitize ecryptfs ->mount() kill ecryptfs_read_super(), reorder code allowing to use normal d_alloc_root() instead of opencoding it. Signed-off-by: Al Viro --- fs/ecryptfs/inode.c | 1 - fs/ecryptfs/main.c | 155 +++++++++++++++++++------------------------- 2 files changed, 68 insertions(+), 88 deletions(-) diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 337352a947511..64ff023307529 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -441,7 +441,6 @@ static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode, struct qstr lower_name; int rc = 0; - d_set_d_op(ecryptfs_dentry, &ecryptfs_dops); if ((ecryptfs_dentry->d_name.len == 1 && !strcmp(ecryptfs_dentry->d_name.name, ".")) || (ecryptfs_dentry->d_name.len == 2 diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index 351038675376b..9ed4769063273 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -141,21 +141,9 @@ int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry) return rc; } -/** - * ecryptfs_interpose - * @lower_dentry: Existing dentry in the lower filesystem - * @dentry: ecryptfs' dentry - * @sb: ecryptfs's super_block - * @flags: flags to govern behavior of interpose procedure - * - * Interposes upper and lower dentries. - * - * Returns zero on success; non-zero otherwise - */ -int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry, - struct super_block *sb, u32 flags) +static inode *ecryptfs_get_inode(struct inode *lower_inode, + struct super_block *sb) { - struct inode *lower_inode; struct inode *inode; int rc = 0; @@ -189,17 +177,38 @@ int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry, if (special_file(lower_inode->i_mode)) init_special_inode(inode, lower_inode->i_mode, lower_inode->i_rdev); - d_set_d_op(dentry, &ecryptfs_dops); fsstack_copy_attr_all(inode, lower_inode); /* This size will be overwritten for real files w/ headers and * other metadata */ fsstack_copy_inode_size(inode, lower_inode); + return inode; +out: + return ERR_PTR(rc); +} + +/** + * ecryptfs_interpose + * @lower_dentry: Existing dentry in the lower filesystem + * @dentry: ecryptfs' dentry + * @sb: ecryptfs's super_block + * @flags: flags to govern behavior of interpose procedure + * + * Interposes upper and lower dentries. + * + * Returns zero on success; non-zero otherwise + */ +int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry, + struct super_block *sb, u32 flags) +{ + struct inode *lower_inode = lower_dentry->d_inode; + struct inode *inode = ecryptfs_get_inode(lower_inode, sb); + if (IS_ERR(inode) + return PTR_ERR(inode); if (flags & ECRYPTFS_INTERPOSE_FLAG_D_ADD) d_add(dentry, inode); else d_instantiate(dentry, inode); -out: - return rc; + return 0; } enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, @@ -491,60 +500,12 @@ static int ecryptfs_parse_options(struct ecryptfs_sb_info *sbi, char *options) struct kmem_cache *ecryptfs_sb_info_cache; static struct file_system_type ecryptfs_fs_type; -/** - * ecryptfs_read_super - * @sb: The ecryptfs super block - * @dev_name: The path to mount over - * - * Read the super block of the lower filesystem, and use - * ecryptfs_interpose to create our initial inode and super block - * struct. - */ -static int ecryptfs_read_super(struct super_block *sb, const char *dev_name) -{ - struct path path; - int rc; - - rc = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); - if (rc) { - ecryptfs_printk(KERN_WARNING, "path_lookup() failed\n"); - goto out; - } - if (path.dentry->d_sb->s_type == &ecryptfs_fs_type) { - rc = -EINVAL; - printk(KERN_ERR "Mount on filesystem of type " - "eCryptfs explicitly disallowed due to " - "known incompatibilities\n"); - goto out_free; - } - ecryptfs_set_superblock_lower(sb, path.dentry->d_sb); - sb->s_maxbytes = path.dentry->d_sb->s_maxbytes; - sb->s_blocksize = path.dentry->d_sb->s_blocksize; - ecryptfs_set_dentry_lower(sb->s_root, path.dentry); - ecryptfs_set_dentry_lower_mnt(sb->s_root, path.mnt); - rc = ecryptfs_interpose(path.dentry, sb->s_root, sb, 0); - if (rc) - goto out_free; - rc = 0; - goto out; -out_free: - path_put(&path); -out: - return rc; -} - /** * ecryptfs_get_sb * @fs_type * @flags * @dev_name: The path to mount over * @raw_data: The options passed into the kernel - * - * The whole ecryptfs_get_sb process is broken into 3 functions: - * ecryptfs_parse_options(): handle options passed to ecryptfs, if any - * ecryptfs_read_super(): this accesses the lower filesystem and uses - * ecryptfs_interpose to perform most of the linking - * ecryptfs_interpose(): links the lower filesystem into ecryptfs (inode.c) */ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags, const char *dev_name, void *raw_data) @@ -553,6 +514,8 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags struct ecryptfs_sb_info *sbi; struct ecryptfs_dentry_info *root_info; const char *err = "Getting sb failed"; + struct inode *inode; + struct path path; int rc; sbi = kmem_cache_zalloc(ecryptfs_sb_info_cache, GFP_KERNEL); @@ -575,10 +538,8 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags s->s_flags = flags; rc = bdi_setup_and_register(&sbi->bdi, "ecryptfs", BDI_CAP_MAP_COPY); - if (rc) { - deactivate_locked_super(s); - goto out; - } + if (rc) + goto out1; ecryptfs_set_superblock_private(s, sbi); s->s_bdi = &sbi->bdi; @@ -586,34 +547,54 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags /* ->kill_sb() will take care of sbi after that point */ sbi = NULL; s->s_op = &ecryptfs_sops; + s->s_d_op = &ecryptfs_dops; - rc = -ENOMEM; - s->s_root = d_alloc(NULL, &(const struct qstr) { - .hash = 0,.name = "/",.len = 1}); + err = "Reading sb failed"; + rc = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &path); + if (rc) { + ecryptfs_printk(KERN_WARNING, "kern_path() failed\n"); + goto out1; + } + if (path.dentry->d_sb->s_type == &ecryptfs_fs_type) { + rc = -EINVAL; + printk(KERN_ERR "Mount on filesystem of type " + "eCryptfs explicitly disallowed due to " + "known incompatibilities\n"); + goto out_free; + } + ecryptfs_set_superblock_lower(s, path.dentry->d_sb); + s->s_maxbytes = path.dentry->d_sb->s_maxbytes; + s->s_blocksize = path.dentry->d_sb->s_blocksize; + + inode = ecryptfs_get_inode(path.dentry->d_inode, s); + rc = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out_free; + + s->s_root = d_alloc_root(inode); if (!s->s_root) { - deactivate_locked_super(s); - goto out; + iput(inode); + rc = -ENOMEM; + goto out_free; } - d_set_d_op(s->s_root, &ecryptfs_dops); - s->s_root->d_sb = s; - s->s_root->d_parent = s->s_root; + rc = -ENOMEM; root_info = kmem_cache_zalloc(ecryptfs_dentry_info_cache, GFP_KERNEL); - if (!root_info) { - deactivate_locked_super(s); - goto out; - } + if (!root_info) + goto out_free; + /* ->kill_sb() will take care of root_info */ ecryptfs_set_dentry_private(s->s_root, root_info); + ecryptfs_set_dentry_lower(s->s_root, path.dentry); + ecryptfs_set_dentry_lower_mnt(s->s_root, path.mnt); + s->s_flags |= MS_ACTIVE; - rc = ecryptfs_read_super(s, dev_name); - if (rc) { - deactivate_locked_super(s); - err = "Reading sb failed"; - goto out; - } return dget(s->s_root); +out_free: + path_put(&path); +out1: + deactivate_locked_super(s); out: if (sbi) { ecryptfs_destroy_mount_crypt_stat(&sbi->mount_crypt_stat); From 1c977540fda4bf65ab467d110f5d840fc27e7608 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 18 Nov 2010 15:02:45 -0800 Subject: [PATCH 31/41] fs: fix kernel-doc for dcache::d_validate Fix function parameter kernel-doc for d_validate(): Warning(fs/dcache.c:1495): No description found for parameter 'parent' Warning(fs/dcache.c:1495): Excess function parameter 'dparent' description in 'd_validate' Signed-off-by: Randy Dunlap Cc: Alexander Viro Signed-off-by: Al Viro --- fs/dcache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs/dcache.c b/fs/dcache.c index 5ec58267b5bb1..b2e90998ad36c 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1970,7 +1970,7 @@ struct dentry *d_hash_and_lookup(struct dentry *dir, struct qstr *name) /** * d_validate - verify dentry provided from insecure source (deprecated) * @dentry: The dentry alleged to be valid child of @dparent - * @dparent: The parent dentry (known to be valid) + * @parent: The parent dentry (known to be valid) * * An insecure source has sent us a dentry, here we verify it and dget() it. * This is used by ncpfs in its readdir implementation. From 208898c17a97610ce1c01b1cc58e51802a1d52c3 Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Thu, 18 Nov 2010 15:02:49 -0800 Subject: [PATCH 32/41] fs: fix kernel-doc for dcache::prepend_path Fix function kernel-doc warning for prepend_path(): Warning(fs/dcache.c:1924): missing initial short description on line: Signed-off-by: Randy Dunlap Cc: Alexander Viro Signed-off-by: Al Viro --- fs/dcache.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fs/dcache.c b/fs/dcache.c index b2e90998ad36c..0c6d5c549d840 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -2453,8 +2453,7 @@ static int prepend_name(char **buffer, int *buflen, struct qstr *name) } /** - * Prepend path string to a buffer - * + * prepend_path - Prepend path string to a buffer * @path: the dentry/vfsmount to report * @root: root vfsmnt/dentry (may be modified by this function) * @buffer: pointer to the end of the buffer From cccb5a1e698535fa5a734ffe21c7061c97f8d8c5 Mon Sep 17 00:00:00 2001 From: Al Viro Date: Fri, 17 Dec 2010 07:44:05 -0500 Subject: [PATCH 33/41] fix signedness mess in rw_verify_area() on 64bit architectures ... and clean the unsigned-f_pos code, while we are at it. Signed-off-by: Al Viro --- fs/read_write.c | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/fs/read_write.c b/fs/read_write.c index 5d431bacbea96..5520f8ad55044 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -30,18 +30,9 @@ const struct file_operations generic_ro_fops = { EXPORT_SYMBOL(generic_ro_fops); -static int -__negative_fpos_check(struct file *file, loff_t pos, size_t count) +static inline int unsigned_offsets(struct file *file) { - /* - * pos or pos+count is negative here, check overflow. - * too big "count" will be caught in rw_verify_area(). - */ - if ((pos < 0) && (pos + count < pos)) - return -EOVERFLOW; - if (file->f_mode & FMODE_UNSIGNED_OFFSET) - return 0; - return -EINVAL; + return file->f_mode & FMODE_UNSIGNED_OFFSET; } /** @@ -75,7 +66,7 @@ generic_file_llseek_unlocked(struct file *file, loff_t offset, int origin) break; } - if (offset < 0 && __negative_fpos_check(file, offset, 0)) + if (offset < 0 && !unsigned_offsets(file)) return -EINVAL; if (offset > inode->i_sb->s_maxbytes) return -EINVAL; @@ -152,7 +143,7 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) offset += file->f_pos; } retval = -EINVAL; - if (offset >= 0 || !__negative_fpos_check(file, offset, 0)) { + if (offset >= 0 || unsigned_offsets(file)) { if (offset != file->f_pos) { file->f_pos = offset; file->f_version = 0; @@ -252,9 +243,13 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count if (unlikely((ssize_t) count < 0)) return retval; pos = *ppos; - if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) { - retval = __negative_fpos_check(file, pos, count); - if (retval) + if (unlikely(pos < 0)) { + if (!unsigned_offsets(file)) + return retval; + if (count >= -pos) /* both values are in 0..LLONG_MAX */ + return -EOVERFLOW; + } else if (unlikely((loff_t) (pos + count) < 0)) { + if (!unsigned_offsets(file)) return retval; } From e1181ee6575d7970bad15aaa852784b4972d2af8 Mon Sep 17 00:00:00 2001 From: Jeff Layton Date: Tue, 7 Dec 2010 16:19:50 -0500 Subject: [PATCH 34/41] vfs: pass struct file to do_truncate on O_TRUNC opens (try #2) When a file is opened with O_TRUNC, the truncate processing is handled by handle_truncate(). This function however doesn't receive any info about the newly instantiated filp, and therefore can't pass that info along so that the setattr can use it. This makes NFSv4 misbehave. The client does an open and gets a valid stateid, and then doesn't use that stateid on the subsequent truncate. It uses the zero-stateid instead. Most servers ignore this fact and just do the truncate anyway, but some don't like it (notably, RHEL4). It seems more correct that since we have a fully instantiated file at the time that handle_truncate is called, that we pass that along so that the truncate operation can properly use it. Signed-off-by: Jeff Layton Signed-off-by: Al Viro --- fs/namei.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs/namei.c b/fs/namei.c index 24ece10470b67..0b14f6910fc68 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -1950,8 +1950,9 @@ int may_open(struct path *path, int acc_mode, int flag) return break_lease(inode, flag); } -static int handle_truncate(struct path *path) +static int handle_truncate(struct file *filp) { + struct path *path = &filp->f_path; struct inode *inode = path->dentry->d_inode; int error = get_write_access(inode); if (error) @@ -1965,7 +1966,7 @@ static int handle_truncate(struct path *path) if (!error) { error = do_truncate(path->dentry, 0, ATTR_MTIME|ATTR_CTIME|ATTR_OPEN, - NULL); + filp); } put_write_access(inode); return error; @@ -2063,7 +2064,7 @@ static struct file *finish_open(struct nameidata *nd, } if (!IS_ERR(filp)) { if (will_truncate) { - error = handle_truncate(&nd->path); + error = handle_truncate(filp); if (error) { fput(filp); filp = ERR_PTR(error); From 79124f18b335172e1916075c633745e12dae1dac Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 17 Nov 2010 20:46:15 -0500 Subject: [PATCH 35/41] fs: add hole punching to fallocate Hole punching has already been implemented by XFS and OCFS2, and has the potential to be implemented on both BTRFS and EXT4 so we need a generic way to get to this feature. The simplest way in my mind is to add FALLOC_FL_PUNCH_HOLE to fallocate() since it already looks like the normal fallocate() operation. I've tested this patch with XFS and BTRFS to make sure XFS did what it's supposed to do and that BTRFS failed like it was supposed to. Thank you, Signed-off-by: Josef Bacik Signed-off-by: Al Viro --- fs/open.c | 7 ++++++- include/linux/falloc.h | 1 + 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/fs/open.c b/fs/open.c index 4197b9ed023d8..5b6ef7e2859e3 100644 --- a/fs/open.c +++ b/fs/open.c @@ -223,7 +223,12 @@ int do_fallocate(struct file *file, int mode, loff_t offset, loff_t len) return -EINVAL; /* Return error if mode is not supported */ - if (mode && !(mode & FALLOC_FL_KEEP_SIZE)) + if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE)) + return -EOPNOTSUPP; + + /* Punch hole must have keep size set */ + if ((mode & FALLOC_FL_PUNCH_HOLE) && + !(mode & FALLOC_FL_KEEP_SIZE)) return -EOPNOTSUPP; if (!(file->f_mode & FMODE_WRITE)) diff --git a/include/linux/falloc.h b/include/linux/falloc.h index 3c155107d61f3..73e0b628e058c 100644 --- a/include/linux/falloc.h +++ b/include/linux/falloc.h @@ -2,6 +2,7 @@ #define _FALLOC_H_ #define FALLOC_FL_KEEP_SIZE 0x01 /* default is extend size */ +#define FALLOC_FL_PUNCH_HOLE 0x02 /* de-allocates range */ #ifdef __KERNEL__ From c25d246715b87ad37e69e7abd1a0fed781423fa2 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 17 Nov 2010 20:46:16 -0500 Subject: [PATCH 36/41] XFS: handle hole punching via fallocate properly This patch simply allows XFS to handle the hole punching flag in fallocate properly. I've tested this with a little program that does a bunch of random hole punching with FL_KEEP_SIZE and without it to make sure it does the right thing. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Al Viro --- fs/xfs/linux-2.6/xfs_iops.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 94d5fd6a29730..da54403633b61 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -516,6 +516,7 @@ xfs_vn_fallocate( loff_t new_size = 0; xfs_flock64_t bf; xfs_inode_t *ip = XFS_I(inode); + int cmd = XFS_IOC_RESVSP; /* preallocation on directories not yet supported */ error = -ENODEV; @@ -528,6 +529,9 @@ xfs_vn_fallocate( xfs_ilock(ip, XFS_IOLOCK_EXCL); + if (mode & FALLOC_FL_PUNCH_HOLE) + cmd = XFS_IOC_UNRESVSP; + /* check the new inode size is valid before allocating */ if (!(mode & FALLOC_FL_KEEP_SIZE) && offset + len > i_size_read(inode)) { @@ -537,8 +541,7 @@ xfs_vn_fallocate( goto out_unlock; } - error = -xfs_change_file_space(ip, XFS_IOC_RESVSP, &bf, - 0, XFS_ATTR_NOLOCK); + error = -xfs_change_file_space(ip, cmd, &bf, 0, XFS_ATTR_NOLOCK); if (error) goto out_unlock; From db47fef2cd9aab76ab976e8b45a06a1b3ad0e3e4 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 17 Nov 2010 20:46:17 -0500 Subject: [PATCH 37/41] Ocfs2: handle hole punching via fallocate properly This patch just makes ocfs2 use its UNRESERVP ioctl when we get the hole punch flag in fallocate. I didn't test it, but it seems simple enough. Thanks, Acked-by: Jan Kara Acked-by: Joel Becker Signed-off-by: Josef Bacik Signed-off-by: Al Viro --- fs/ocfs2/file.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index bdadbae090940..63e3fca266e00 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1995,6 +1995,7 @@ static long ocfs2_fallocate(struct inode *inode, int mode, loff_t offset, struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct ocfs2_space_resv sr; int change_size = 1; + int cmd = OCFS2_IOC_RESVSP64; if (!ocfs2_writes_unwritten_extents(osb)) return -EOPNOTSUPP; @@ -2005,12 +2006,15 @@ static long ocfs2_fallocate(struct inode *inode, int mode, loff_t offset, if (mode & FALLOC_FL_KEEP_SIZE) change_size = 0; + if (mode & FALLOC_FL_PUNCH_HOLE) + cmd = OCFS2_IOC_UNRESVSP64; + sr.l_whence = 0; sr.l_start = (s64)offset; sr.l_len = (s64)len; - return __ocfs2_change_file_space(NULL, inode, offset, - OCFS2_IOC_RESVSP64, &sr, change_size); + return __ocfs2_change_file_space(NULL, inode, offset, cmd, &sr, + change_size); } int ocfs2_check_range_for_refcount(struct inode *inode, loff_t pos, From d6dc8462f471f7bbb49c42c147bf84de0c977099 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 17 Nov 2010 20:46:18 -0500 Subject: [PATCH 38/41] Ext4: fail if we try to use hole punch Ext4 doesn't have the ability to punch holes yet, so make sure we return EOPNOTSUPP if we try to use hole punching through fallocate. This support can be added later. Thanks, Acked-by: Jan Kara Signed-off-by: Josef Bacik Signed-off-by: Al Viro --- fs/ext4/extents.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index e910720e8bb8e..2e061dffb722e 100644 --- a/fs/ext4/extents.c +++ b/fs/ext4/extents.c @@ -3644,6 +3644,10 @@ long ext4_fallocate(struct inode *inode, int mode, loff_t offset, loff_t len) struct ext4_map_blocks map; unsigned int credits, blkbits = inode->i_blkbits; + /* We only support the FALLOC_FL_KEEP_SIZE mode */ + if (mode && (mode != FALLOC_FL_KEEP_SIZE)) + return -EOPNOTSUPP; + /* * currently supporting (pre)allocate mode for extent-based * files _only_ From 23a8519b55235660f6fb7d6f394a912de9d23208 Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 17 Nov 2010 20:46:19 -0500 Subject: [PATCH 39/41] Btrfs: fail if we try to use hole punch Btrfs doesn't have the ability to punch holes yet, so make sure we return EOPNOTSUPP if we try to use hole punching through fallocate. This support can be added later. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Al Viro --- fs/btrfs/inode.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index f870aefc59dd5..a3798a3aa0d21 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -7115,6 +7115,10 @@ static long btrfs_fallocate(struct inode *inode, int mode, alloc_start = offset & ~mask; alloc_end = (offset + len + mask) & ~mask; + /* We only support the FALLOC_FL_KEEP_SIZE mode */ + if (mode && (mode != FALLOC_FL_KEEP_SIZE)) + return -EOPNOTSUPP; + /* * wait for ordered IO before we have any locks. We'll loop again * below with the locks held. From 9ecf639a9686c9c7e3fd2cd72817ca490c658e6f Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 17 Nov 2010 20:46:20 -0500 Subject: [PATCH 40/41] Gfs2: fail if we try to use hole punch Gfs2 doesn't have the ability to punch holes yet, so make sure we return EOPNOTSUPP if we try to use hole punching through fallocate. This support can be added later. Thanks, Signed-off-by: Josef Bacik Signed-off-by: Al Viro --- fs/gfs2/ops_inode.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index ae140c8abb5c8..040b5a2e65561 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -1425,6 +1425,10 @@ static long gfs2_fallocate(struct inode *inode, int mode, loff_t offset, loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift; next = (next + 1) << sdp->sd_sb.sb_bsize_shift; + /* We only support the FALLOC_FL_KEEP_SIZE mode */ + if (mode && (mode != FALLOC_FL_KEEP_SIZE)) + return -EOPNOTSUPP; + offset = (offset >> sdp->sd_sb.sb_bsize_shift) << sdp->sd_sb.sb_bsize_shift; From 924241575a85249b9d410e38f5b2fcad9035e45c Mon Sep 17 00:00:00 2001 From: Josef Bacik Date: Wed, 5 Jan 2011 15:00:07 -0500 Subject: [PATCH 41/41] fs: add documentation on fallocate hole punching This patch simply adds documentation on how to handle the hole punching mode of fallocate for any filesystem wishing to use it. Signed-off-by: Josef Bacik Signed-off-by: Al Viro --- Documentation/filesystems/porting | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting index 07a32b42cf9ce..266d2059b9b8d 100644 --- a/Documentation/filesystems/porting +++ b/Documentation/filesystems/porting @@ -385,3 +385,12 @@ Documentation/filesystems/vfs.txt for more details. on many or all directory inodes on the way down a path walk (to check for exec permission). These must now be rcu-walk aware (flags & IPERM_RCU). See Documentation/filesystems/vfs.txt for more details. + +-- +[mandatory] + In ->fallocate() you must check the mode option passed in. If your +filesystem does not support hole punching (deallocating space in the middle of a +file) you must return -EOPNOTSUPP if FALLOC_FL_PUNCH_HOLE is set in mode. +Currently you can only have FALLOC_FL_PUNCH_HOLE with FALLOC_FL_KEEP_SIZE set, +so the i_size should not change when hole punching, even when puching the end of +a file off.