diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 10:27:28 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2011-01-13 10:27:28 -0800 |
commit | b2034d474b7e1e8578bd5c2977024b51693269d9 (patch) | |
tree | e43969bf7c2ba89884c2580f56978826f1014520 /fs | |
parent | 27d189c02ba25851973c8582e419c0bded9f7e5b (diff) | |
parent | 924241575a85249b9d410e38f5b2fcad9035e45c (diff) | |
download | lwn-b2034d474b7e1e8578bd5c2977024b51693269d9.tar.gz lwn-b2034d474b7e1e8578bd5c2977024b51693269d9.zip |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (41 commits)
fs: add documentation on fallocate hole punching
Gfs2: fail if we try to use hole punch
Btrfs: fail if we try to use hole punch
Ext4: fail if we try to use hole punch
Ocfs2: handle hole punching via fallocate properly
XFS: handle hole punching via fallocate properly
fs: add hole punching to fallocate
vfs: pass struct file to do_truncate on O_TRUNC opens (try #2)
fix signedness mess in rw_verify_area() on 64bit architectures
fs: fix kernel-doc for dcache::prepend_path
fs: fix kernel-doc for dcache::d_validate
sanitize ecryptfs ->mount()
switch afs
move internal-only parts of ncpfs headers to fs/ncpfs
switch ncpfs
switch 9p
pass default dentry_operations to mount_pseudo()
switch hostfs
switch affs
switch configfs
...
Diffstat (limited to 'fs')
94 files changed, 740 insertions, 396 deletions
diff --git a/fs/9p/v9fs_vfs.h b/fs/9p/v9fs_vfs.h index bab0eac873f4..b789f8e597ec 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 466d2a4fc5cb..233b7d4ffe5e 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 5076eeb95502..b76a40bdf4c2 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 c55c614500ad..dbaabe3b8131 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); diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index bf7693c384f9..3b4a764ed780 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 a4041b52fbca..2d7954049fbe 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; diff --git a/fs/affs/affs.h b/fs/affs/affs.h index a8cbdeb34025..0e95f73a7023 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 944a4042fb65..e3e9efc1fdd8 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 d39081bbe7ce..b31507d0f9b9 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -477,12 +477,16 @@ got_root: 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; diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 34a3263d60a4..e6a4ab980e31 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 6d4bc1c8ff60..ab6db5abaf53 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 f901a9d7c111..fb240e8766d6 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"); diff --git a/fs/anon_inodes.c b/fs/anon_inodes.c index 98edb657b84d..cbe57f3c4d89 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 771f23527010..88da70355aa3 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/btrfs/export.c b/fs/btrfs/export.c index 0ccf9a8afcdf..9786963b07e5 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 a0ff46a47895..a3798a3aa0d2 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); @@ -7117,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. diff --git a/fs/btrfs/super.c b/fs/btrfs/super.c index 883c6fa1367e..22acdaa78ce1 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; diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 5e7075d5f139..d9f652a522a6 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 2e773825835e..1e95dd635632 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c @@ -130,17 +130,6 @@ cifs_bp_rename_retry: 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_get_file_info: 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 0c7e36910e31..b06b60620240 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 @@ mkdir_get_info: 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 fe2f6a93c49e..306769de2fb5 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 76b1b37c9e6b..7f25cc3d2256 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); diff --git a/fs/coda/cache.c b/fs/coda/cache.c index 5525e1c660fd..690157876184 100644 --- a/fs/coda/cache.c +++ b/fs/coda/cache.c @@ -20,10 +20,9 @@ #include <linux/spinlock.h> #include <linux/coda.h> -#include <linux/coda_linux.h> #include <linux/coda_psdev.h> -#include <linux/coda_fs_i.h> -#include <linux/coda_cache.h> +#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 602240569c89..6475877b0763 100644 --- a/fs/coda/cnode.c +++ b/fs/coda/cnode.c @@ -7,9 +7,8 @@ #include <linux/time.h> #include <linux/coda.h> -#include <linux/coda_linux.h> -#include <linux/coda_fs_i.h> #include <linux/coda_psdev.h> +#include "coda_linux.h" static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2) { diff --git a/fs/coda/coda_cache.h b/fs/coda/coda_cache.h new file mode 100644 index 000000000000..c910b5eb1ceb --- /dev/null +++ b/fs/coda/coda_cache.h @@ -0,0 +1,22 @@ +/* Coda filesystem -- Linux Minicache + * + * Copyright (C) 1989 - 1997 Carnegie Mellon University + * + * Carnegie Mellon University encourages users of this software to + * contribute improvements to the Coda project. Contact Peter Braam + * <coda@cs.cmu.edu> + */ + +#ifndef _CFSNC_HEADER_ +#define _CFSNC_HEADER_ + +/* credential cache */ +void coda_cache_enter(struct inode *inode, int mask); +void coda_cache_clear_inode(struct inode *); +void coda_cache_clear_all(struct super_block *sb); +int coda_cache_check(struct inode *inode, int mask); + +/* for downcalls and attributes and lookups */ +void coda_flag_inode_children(struct inode *inode, int flag); + +#endif /* _CFSNC_HEADER_ */ diff --git a/fs/coda/coda_fs_i.h b/fs/coda/coda_fs_i.h new file mode 100644 index 000000000000..e35071b1de0e --- /dev/null +++ b/fs/coda/coda_fs_i.h @@ -0,0 +1,58 @@ +/* + * coda_fs_i.h + * + * Copyright (C) 1998 Carnegie Mellon University + * + */ + +#ifndef _LINUX_CODA_FS_I +#define _LINUX_CODA_FS_I + +#include <linux/types.h> +#include <linux/list.h> +#include <linux/spinlock.h> +#include <linux/coda.h> + +/* + * coda fs inode data + * c_lock protects accesses to c_flags, c_mapcount, c_cached_epoch, c_uid and + * c_cached_perm. + * vfs_inode is set only when the inode is created and never changes. + * c_fid is set when the inode is created and should be considered immutable. + */ +struct coda_inode_info { + struct CodaFid c_fid; /* Coda identifier */ + u_short c_flags; /* flags (see below) */ + unsigned int c_mapcount; /* nr of times this inode is mapped */ + unsigned int c_cached_epoch; /* epoch for cached permissions */ + vuid_t c_uid; /* fsuid for cached permissions */ + unsigned int c_cached_perm; /* cached access permissions */ + spinlock_t c_lock; + struct inode vfs_inode; +}; + +/* + * coda fs file private data + */ +#define CODA_MAGIC 0xC0DAC0DA +struct coda_file_info { + int cfi_magic; /* magic number */ + struct file *cfi_container; /* container file for this cnode */ + unsigned int cfi_mapcount; /* nr of times this file is mapped */ +}; + +#define CODA_FTOC(file) ((struct coda_file_info *)((file)->private_data)) + +/* flags */ +#define C_VATTR 0x1 /* Validity of vattr in inode */ +#define C_FLUSH 0x2 /* used after a flush */ +#define C_DYING 0x4 /* from venus (which died) */ +#define C_PURGE 0x8 + +int coda_cnode_make(struct inode **, struct CodaFid *, struct super_block *); +struct inode *coda_iget(struct super_block *sb, struct CodaFid *fid, struct coda_vattr *attr); +int coda_cnode_makectl(struct inode **inode, struct super_block *sb); +struct inode *coda_fid_to_inode(struct CodaFid *fid, struct super_block *sb); +void coda_replace_fid(struct inode *, struct CodaFid *, struct CodaFid *); + +#endif diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c index bf4a3fd3c8e3..2bdbcc11b373 100644 --- a/fs/coda/coda_linux.c +++ b/fs/coda/coda_linux.c @@ -17,9 +17,8 @@ #include <linux/string.h> #include <linux/coda.h> -#include <linux/coda_linux.h> #include <linux/coda_psdev.h> -#include <linux/coda_fs_i.h> +#include "coda_linux.h" /* initialize the debugging variables */ int coda_fake_statfs; diff --git a/fs/coda/coda_linux.h b/fs/coda/coda_linux.h new file mode 100644 index 000000000000..9b0c5323890b --- /dev/null +++ b/fs/coda/coda_linux.h @@ -0,0 +1,101 @@ +/* + * Coda File System, Linux Kernel module + * + * Original version, adapted from cfs_mach.c, (C) Carnegie Mellon University + * Linux modifications (C) 1996, Peter J. Braam + * Rewritten for Linux 2.1 (C) 1997 Carnegie Mellon University + * + * Carnegie Mellon University encourages users of this software to + * contribute improvements to the Coda project. + */ + +#ifndef _LINUX_CODA_FS +#define _LINUX_CODA_FS + +#include <linux/kernel.h> +#include <linux/param.h> +#include <linux/mm.h> +#include <linux/vmalloc.h> +#include <linux/slab.h> +#include <linux/wait.h> +#include <linux/types.h> +#include <linux/fs.h> +#include "coda_fs_i.h" + +/* operations */ +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; + +extern const struct file_operations coda_dir_operations; +extern const struct file_operations coda_file_operations; +extern const struct file_operations coda_ioctl_operations; + +/* operations shared over more than one file */ +int coda_open(struct inode *i, struct file *f); +int coda_release(struct inode *i, struct file *f); +int coda_permission(struct inode *inode, int mask, unsigned int flags); +int coda_revalidate_inode(struct dentry *); +int coda_getattr(struct vfsmount *, struct dentry *, struct kstat *); +int coda_setattr(struct dentry *, struct iattr *); + +/* this file: heloers */ +char *coda_f2s(struct CodaFid *f); +int coda_isroot(struct inode *i); +int coda_iscontrol(const char *name, size_t length); + +void coda_vattr_to_iattr(struct inode *, struct coda_vattr *); +void coda_iattr_to_vattr(struct iattr *, struct coda_vattr *); +unsigned short coda_flags_to_cflags(unsigned short); + +/* sysctl.h */ +void coda_sysctl_init(void); +void coda_sysctl_clean(void); + +#define CODA_ALLOC(ptr, cast, size) do { \ + if (size < PAGE_SIZE) \ + ptr = kmalloc((unsigned long) size, GFP_KERNEL); \ + else \ + ptr = (cast)vmalloc((unsigned long) size); \ + if (!ptr) \ + printk("kernel malloc returns 0 at %s:%d\n", __FILE__, __LINE__); \ + else memset( ptr, 0, size ); \ +} while (0) + + +#define CODA_FREE(ptr,size) \ + do { if (size < PAGE_SIZE) kfree((ptr)); else vfree((ptr)); } while (0) + +/* inode to cnode access functions */ + +static inline struct coda_inode_info *ITOC(struct inode *inode) +{ + return list_entry(inode, struct coda_inode_info, vfs_inode); +} + +static __inline__ struct CodaFid *coda_i2f(struct inode *inode) +{ + return &(ITOC(inode)->c_fid); +} + +static __inline__ char *coda_i2s(struct inode *inode) +{ + return coda_f2s(&(ITOC(inode)->c_fid)); +} + +/* this will not zap the inode away */ +static __inline__ void coda_flag_inode(struct inode *inode, int flag) +{ + struct coda_inode_info *cii = ITOC(inode); + + spin_lock(&cii->c_lock); + cii->c_flags |= flag; + spin_unlock(&cii->c_lock); +} + +#endif diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 29badd91360f..2b8dae4d121e 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -23,10 +23,9 @@ #include <asm/uaccess.h> #include <linux/coda.h> -#include <linux/coda_linux.h> #include <linux/coda_psdev.h> -#include <linux/coda_fs_i.h> -#include <linux/coda_cache.h> +#include "coda_linux.h" +#include "coda_cache.h" #include "coda_int.h" @@ -61,7 +60,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 +125,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/file.c b/fs/coda/file.c index c8b50ba4366a..0433057be330 100644 --- a/fs/coda/file.c +++ b/fs/coda/file.c @@ -21,10 +21,9 @@ #include <asm/uaccess.h> #include <linux/coda.h> -#include <linux/coda_linux.h> -#include <linux/coda_fs_i.h> #include <linux/coda_psdev.h> +#include "coda_linux.h" #include "coda_int.h" static ssize_t diff --git a/fs/coda/inode.c b/fs/coda/inode.c index f065a5d31a19..871b27715465 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -28,10 +28,9 @@ #include <linux/vmalloc.h> #include <linux/coda.h> -#include <linux/coda_linux.h> #include <linux/coda_psdev.h> -#include <linux/coda_fs_i.h> -#include <linux/coda_cache.h> +#include "coda_linux.h" +#include "coda_cache.h" #include "coda_int.h" @@ -193,6 +192,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/fs/coda/pioctl.c b/fs/coda/pioctl.c index 741f0bd03918..6cbb3afb36dc 100644 --- a/fs/coda/pioctl.c +++ b/fs/coda/pioctl.c @@ -19,10 +19,10 @@ #include <asm/uaccess.h> #include <linux/coda.h> -#include <linux/coda_linux.h> -#include <linux/coda_fs_i.h> #include <linux/coda_psdev.h> +#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 62647a8595e4..8f616e0e252c 100644 --- a/fs/coda/psdev.c +++ b/fs/coda/psdev.c @@ -43,10 +43,10 @@ #include <asm/uaccess.h> #include <linux/coda.h> -#include <linux/coda_linux.h> -#include <linux/coda_fs_i.h> #include <linux/coda_psdev.h> +#include "coda_linux.h" + #include "coda_int.h" /* statistics */ diff --git a/fs/coda/symlink.c b/fs/coda/symlink.c index af78f007a2b0..ab94ef63caef 100644 --- a/fs/coda/symlink.c +++ b/fs/coda/symlink.c @@ -16,9 +16,9 @@ #include <linux/pagemap.h> #include <linux/coda.h> -#include <linux/coda_linux.h> #include <linux/coda_psdev.h> -#include <linux/coda_fs_i.h> + +#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 c3563cab9758..9727e0c52579 100644 --- a/fs/coda/upcall.c +++ b/fs/coda/upcall.c @@ -33,10 +33,9 @@ #include <linux/vfs.h> #include <linux/coda.h> -#include <linux/coda_linux.h> #include <linux/coda_psdev.h> -#include <linux/coda_fs_i.h> -#include <linux/coda_cache.h> +#include "coda_linux.h" +#include "coda_cache.h" #include "coda_int.h" diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index 026cf68553a4..82bda8fdfc1c 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 36637a8c1ed3..90ff3cb10de3 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 7d3607febe1c..ecc62178beda 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; } diff --git a/fs/dcache.c b/fs/dcache.c index 5699d4c027cb..0c6d5c549d84 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); @@ -1966,7 +1970,7 @@ out: /** * 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. @@ -2449,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 diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 337352a94751..64ff02330752 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 351038675376..9ed476906327 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, @@ -492,59 +501,11 @@ 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); diff --git a/fs/ext4/extents.c b/fs/ext4/extents.c index d202d765dad2..c4068f6abf03 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_ diff --git a/fs/fat/fat.h b/fs/fat/fat.h index d75a77f85c28..f50408901f7e 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 206351af7c58..86753fe10bd1 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 35ffe43afa4b..711499040eb6 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 e3ffc5e12332..f88f752babd9 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, diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 042af7346ec1..bfed8447ed80 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 f62b32cffea9..9e3f68cc1bd1 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) diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c index 97012ecff560..9023db8184f9 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 2aeabd4218cc..693f4470a2df 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 1501db4f0e6d..040b5a2e6556 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); @@ -1427,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; diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index ea4aefe7c652..afa66aaa2237 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 0bef62aa4f42..1b55f704fb22 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; diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index f896dc843026..4df5059c25da 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 6ee6ad20acf2..9a3b4795f43c 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; diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index d3244d949a4e..2638c834ed28 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 <NULL> by sprintf: avoid that. */ diff --git a/fs/hpfs/dentry.c b/fs/hpfs/dentry.c index 32c13a94e1e9..05d4816e4e77 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 2338130cceba..d32f63a569f7 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 2fee17d0d9ab..1c43dbea55e8 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 49935ba78db8..b30426b1fc97 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 diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index 844a7903c72f..a0f3833c0dbf 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -939,17 +939,18 @@ root_found: 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 679a849c3b27..4fb3e8074fd4 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); diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 4414e3a42264..81ead850ddb6 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 3150d766e0d4..eeca48a031ab 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 diff --git a/fs/libfs.c b/fs/libfs.c index 889311e3d06b..c88eab55aec9 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/minix/namei.c b/fs/minix/namei.c index 1b9e07728a9f..ce7337ddfdbf 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); diff --git a/fs/namei.c b/fs/namei.c index 24ece10470b6..0b14f6910fc6 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); diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 28f136d4aaec..f6946bb5cb55 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -21,9 +21,7 @@ #include <asm/uaccess.h> #include <asm/byteorder.h> -#include <linux/ncp_fs.h> - -#include "ncplib_kernel.h" +#include "ncp_fs.h" static void ncp_read_volume_list(struct file *, void *, filldir_t, struct ncp_cache_control *); @@ -82,7 +80,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 +88,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 +299,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 +630,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 +885,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/file.c b/fs/ncpfs/file.c index cb50aaf981df..0ed65e0c3dfe 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -18,8 +18,7 @@ #include <linux/vmalloc.h> #include <linux/sched.h> -#include <linux/ncp_fs.h> -#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 9b39a5dd4131..00a1d1c3d3a4 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -31,11 +31,9 @@ #include <linux/seq_file.h> #include <linux/namei.h> -#include <linux/ncp_fs.h> - #include <net/sock.h> -#include "ncplib_kernel.h" +#include "ncp_fs.h" #include "getopt.h" #define NCP_DEFAULT_FILE_MODE 0600 @@ -544,6 +542,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 +722,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/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c index d40a547e3377..790e92a9ec63 100644 --- a/fs/ncpfs/ioctl.c +++ b/fs/ncpfs/ioctl.c @@ -20,11 +20,9 @@ #include <linux/vmalloc.h> #include <linux/sched.h> -#include <linux/ncp_fs.h> - #include <asm/uaccess.h> -#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 56f5b3a0e1ee..a7c07b44b100 100644 --- a/fs/ncpfs/mmap.c +++ b/fs/ncpfs/mmap.c @@ -16,12 +16,12 @@ #include <linux/mman.h> #include <linux/string.h> #include <linux/fcntl.h> -#include <linux/ncp_fs.h> -#include "ncplib_kernel.h" #include <asm/uaccess.h> #include <asm/system.h> +#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 000000000000..31831afe1c3b --- /dev/null +++ b/fs/ncpfs/ncp_fs.h @@ -0,0 +1,98 @@ +#include <linux/ncp_fs.h> +#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/fs/ncpfs/ncp_fs_i.h b/fs/ncpfs/ncp_fs_i.h new file mode 100644 index 000000000000..4b0bec477846 --- /dev/null +++ b/fs/ncpfs/ncp_fs_i.h @@ -0,0 +1,29 @@ +/* + * ncp_fs_i.h + * + * Copyright (C) 1995 Volker Lendecke + * + */ + +#ifndef _LINUX_NCP_FS_I +#define _LINUX_NCP_FS_I + +/* + * This is the ncpfs part of the inode structure. This must contain + * all the information we need to work with an inode after creation. + */ +struct ncp_inode_info { + __le32 dirEntNum; + __le32 DosDirNum; + __u8 volNumber; + __le32 nwattr; + struct mutex open_mutex; + atomic_t opened; + int access; + int flags; +#define NCPI_KLUDGE_SYMLINK 0x0001 + __u8 file_handle[6]; + struct inode vfs_inode; +}; + +#endif /* _LINUX_NCP_FS_I */ diff --git a/fs/ncpfs/ncp_fs_sb.h b/fs/ncpfs/ncp_fs_sb.h new file mode 100644 index 000000000000..4af803f13516 --- /dev/null +++ b/fs/ncpfs/ncp_fs_sb.h @@ -0,0 +1,176 @@ +/* + * ncp_fs_sb.h + * + * Copyright (C) 1995, 1996 by Volker Lendecke + * + */ + +#ifndef _NCP_FS_SB +#define _NCP_FS_SB + +#include <linux/types.h> +#include <linux/ncp_mount.h> +#include <linux/net.h> +#include <linux/mutex.h> +#include <linux/backing-dev.h> +#include <linux/workqueue.h> + +#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 + interest for us later, so we store + it completely. */ + + __u8 name_space[NCP_NUMBER_OF_VOLUMES + 2]; + + struct file *ncp_filp; /* File pointer to ncp socket */ + struct socket *ncp_sock;/* ncp socket */ + struct file *info_filp; + struct socket *info_sock; + + u8 sequence; + u8 task; + u16 connection; /* Remote connection number */ + + u8 completion; /* Status message from server */ + u8 conn_status; /* Bit 4 = 1 ==> Server going down, no + requests allowed anymore. + Bit 0 = 1 ==> Server is down. */ + + int buffer_size; /* Negotiated bufsize */ + + int reply_size; /* Size of last reply */ + + int packet_size; + unsigned char *packet; /* Here we prepare requests and + receive replies */ + unsigned char *txbuf; /* Storage for current request */ + unsigned char *rxbuf; /* Storage for reply to current request */ + + int lock; /* To prevent mismatch in protocols. */ + struct mutex mutex; + + int current_size; /* for packet preparation */ + int has_subfunction; + int ncp_reply_size; + + int root_setuped; + struct mutex root_setup_lock; + + /* info for packet signing */ + int sign_wanted; /* 1=Server needs signed packets */ + int sign_active; /* 0=don't do signing, 1=do */ + char sign_root[8]; /* generated from password and encr. key */ + char sign_last[16]; + + /* Authentication info: NDS or BINDERY, username */ + struct { + int auth_type; + size_t object_name_len; + void* object_name; + int object_type; + } auth; + /* Password info */ + struct { + size_t len; + void* data; + } priv; + struct rw_semaphore auth_rwsem; + + /* nls info: codepage for volume and charset for I/O */ + struct nls_table *nls_vol; + struct nls_table *nls_io; + + /* maximum age in jiffies */ + atomic_t dentry_ttl; + + /* miscellaneous */ + unsigned int flags; + + spinlock_t requests_lock; /* Lock accesses to tx.requests, tx.creq and rcv.creq when STREAM mode */ + + void (*data_ready)(struct sock* sk, int len); + void (*error_report)(struct sock* sk); + void (*write_space)(struct sock* sk); /* STREAM mode only */ + struct { + struct work_struct tq; /* STREAM/DGRAM: data/error ready */ + struct ncp_request_reply* creq; /* STREAM/DGRAM: awaiting reply from this request */ + struct mutex creq_mutex; /* DGRAM only: lock accesses to rcv.creq */ + + unsigned int state; /* STREAM only: receiver state */ + struct { + __u32 magic __packed; + __u32 len __packed; + __u16 type __packed; + __u16 p1 __packed; + __u16 p2 __packed; + __u16 p3 __packed; + __u16 type2 __packed; + } buf; /* STREAM only: temporary buffer */ + unsigned char* ptr; /* STREAM only: pointer to data */ + size_t len; /* STREAM only: length of data to receive */ + } rcv; + struct { + struct list_head requests; /* STREAM only: queued requests */ + struct work_struct tq; /* STREAM only: transmitter ready */ + struct ncp_request_reply* creq; /* STREAM only: currently transmitted entry */ + } tx; + struct timer_list timeout_tm; /* DGRAM only: timeout timer */ + struct work_struct timeout_tq; /* DGRAM only: associated queue, we run timers from process context */ + int timeout_last; /* DGRAM only: current timeout length */ + int timeout_retries; /* DGRAM only: retries left */ + struct { + size_t len; + __u8 data[128]; + } unexpected_packet; + struct backing_dev_info bdi; +}; + +extern void ncp_tcp_rcv_proc(struct work_struct *work); +extern void ncp_tcp_tx_proc(struct work_struct *work); +extern void ncpdgram_rcv_proc(struct work_struct *work); +extern void ncpdgram_timeout_proc(struct work_struct *work); +extern void ncpdgram_timeout_call(unsigned long server); +extern void ncp_tcp_data_ready(struct sock* sk, int len); +extern void ncp_tcp_write_space(struct sock* sk); +extern void ncp_tcp_error_report(struct sock* sk); + +#define NCP_FLAG_UTF8 1 + +#define NCP_CLR_FLAG(server, flag) ((server)->flags &= ~(flag)) +#define NCP_SET_FLAG(server, flag) ((server)->flags |= (flag)) +#define NCP_IS_FLAG(server, flag) ((server)->flags & (flag)) + +static inline int ncp_conn_valid(struct ncp_server *server) +{ + return ((server->conn_status & 0x11) == 0); +} + +static inline void ncp_invalidate_conn(struct ncp_server *server) +{ + server->conn_status |= 0x01; +} + +#endif diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c index a95615a0b6ac..981a95617fc9 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 1220df75ff22..09881e6aa5ad 100644 --- a/fs/ncpfs/ncplib_kernel.h +++ b/fs/ncpfs/ncplib_kernel.h @@ -32,8 +32,6 @@ #include <linux/ctype.h> #endif /* CONFIG_NCPFS_NLS */ -#include <linux/ncp_fs.h> - #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 d8b2d7e6910b..08907599dcd2 100644 --- a/fs/ncpfs/ncpsign_kernel.c +++ b/fs/ncpfs/ncpsign_kernel.c @@ -11,6 +11,7 @@ #include <linux/string.h> #include <linux/ncp.h> #include <linux/bitops.h> +#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 6451a68381cc..d9a1438bb1f6 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 <linux/ncp_fs.h> - #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 668bd267346e..3a1587222c8a 100644 --- a/fs/ncpfs/sock.c +++ b/fs/ncpfs/sock.c @@ -28,7 +28,7 @@ #include <linux/poll.h> #include <linux/file.h> -#include <linux/ncp_fs.h> +#include "ncp_fs.h" #include "ncpsign_kernel.h" diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c index c634fd17b337..661f861d80c6 100644 --- a/fs/ncpfs/symlink.c +++ b/fs/ncpfs/symlink.c @@ -25,13 +25,11 @@ #include <linux/errno.h> #include <linux/fs.h> -#include <linux/ncp_fs.h> #include <linux/time.h> #include <linux/slab.h> #include <linux/mm.h> #include <linux/stat.h> -#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/fs/nfs/dir.c b/fs/nfs/dir.c index abe4f0c8dc5f..95b081bc9e25 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 5596c6a2881e..b5ffe8fa291f 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 0f9ea73e7789..b68c8607770f 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; diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c index 6adafa576065..5dbc3062b4fd 100644 --- a/fs/ocfs2/export.c +++ b/fs/ocfs2/export.c @@ -137,9 +137,7 @@ check_gen: } 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/file.c b/fs/ocfs2/file.c index bdadbae09094..63e3fca266e0 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, diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index 30c523144452..849fb4a2e814 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 17ff46fa8a10..06d1f749ca89 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; diff --git a/fs/open.c b/fs/open.c index 4197b9ed023d..5b6ef7e2859e 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/fs/pipe.c b/fs/pipe.c index 04151e2aee96..e2e95fb46a1e 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/fs/read_write.c b/fs/read_write.c index 5d431bacbea9..5520f8ad5504 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; } diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index b5e68da2db32..b427b1208c26 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 76712aefc4ab..f60c196913ea 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; } diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 94d5fd6a2973..da54403633b6 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; |