diff options
Diffstat (limited to 'fs')
316 files changed, 4679 insertions, 2792 deletions
diff --git a/fs/9p/vfs_file.c b/fs/9p/vfs_file.c index 9f17b0cacdd..6c78343cf69 100644 --- a/fs/9p/vfs_file.c +++ b/fs/9p/vfs_file.c @@ -110,7 +110,7 @@ static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl) if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) { filemap_write_and_wait(inode->i_mapping); - invalidate_inode_pages(&inode->i_data); + invalidate_mapping_pages(&inode->i_data, 0, -1); } return res; @@ -234,7 +234,7 @@ v9fs_file_write(struct file *filp, const char __user * data, total += result; } while (count); - invalidate_inode_pages2(inode->i_mapping); + invalidate_inode_pages2(inode->i_mapping); return total; } diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c index 9109ba1d696..5cf22134826 100644 --- a/fs/9p/vfs_inode.c +++ b/fs/9p/vfs_inode.c @@ -41,10 +41,10 @@ #include "v9fs_vfs.h" #include "fid.h" -static struct inode_operations v9fs_dir_inode_operations; -static struct inode_operations v9fs_dir_inode_operations_ext; -static struct inode_operations v9fs_file_inode_operations; -static struct inode_operations v9fs_symlink_inode_operations; +static const struct inode_operations v9fs_dir_inode_operations; +static const struct inode_operations v9fs_dir_inode_operations_ext; +static const struct inode_operations v9fs_file_inode_operations; +static const struct inode_operations v9fs_symlink_inode_operations; /** * unixmode2p9mode - convert unix mode bits to plan 9 @@ -585,17 +585,14 @@ static int v9fs_vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) if (IS_ERR(inode)) { err = PTR_ERR(inode); inode = NULL; - goto clean_up_fids; + v9fs_fid_destroy(vfid); + goto error; } dentry->d_op = &v9fs_dentry_operations; d_instantiate(dentry, inode); return 0; -clean_up_fids: - if (vfid) - v9fs_fid_destroy(vfid); - clean_up_dfid: v9fs_fid_clunk(v9ses, dfid); @@ -1306,7 +1303,7 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) return retval; } -static struct inode_operations v9fs_dir_inode_operations_ext = { +static const struct inode_operations v9fs_dir_inode_operations_ext = { .create = v9fs_vfs_create, .lookup = v9fs_vfs_lookup, .symlink = v9fs_vfs_symlink, @@ -1321,7 +1318,7 @@ static struct inode_operations v9fs_dir_inode_operations_ext = { .setattr = v9fs_vfs_setattr, }; -static struct inode_operations v9fs_dir_inode_operations = { +static const struct inode_operations v9fs_dir_inode_operations = { .create = v9fs_vfs_create, .lookup = v9fs_vfs_lookup, .unlink = v9fs_vfs_unlink, @@ -1333,12 +1330,12 @@ static struct inode_operations v9fs_dir_inode_operations = { .setattr = v9fs_vfs_setattr, }; -static struct inode_operations v9fs_file_inode_operations = { +static const struct inode_operations v9fs_file_inode_operations = { .getattr = v9fs_vfs_getattr, .setattr = v9fs_vfs_setattr, }; -static struct inode_operations v9fs_symlink_inode_operations = { +static const struct inode_operations v9fs_symlink_inode_operations = { .readlink = v9fs_vfs_readlink, .follow_link = v9fs_vfs_follow_link, .put_link = v9fs_vfs_put_link, diff --git a/fs/9p/vfs_super.c b/fs/9p/vfs_super.c index 63320d4e15d..0ec42f66545 100644 --- a/fs/9p/vfs_super.c +++ b/fs/9p/vfs_super.c @@ -45,7 +45,7 @@ #include "fid.h" static void v9fs_clear_inode(struct inode *); -static struct super_operations v9fs_super_ops; +static const struct super_operations v9fs_super_ops; /** * v9fs_clear_inode - release an inode @@ -263,7 +263,7 @@ v9fs_umount_begin(struct vfsmount *vfsmnt, int flags) v9fs_session_cancel(v9ses); } -static struct super_operations v9fs_super_ops = { +static const struct super_operations v9fs_super_ops = { .statfs = simple_statfs, .clear_inode = v9fs_clear_inode, .show_options = v9fs_show_options, diff --git a/fs/Kconfig b/fs/Kconfig index 5e8e9d9ccb3..488521ed9e9 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -674,12 +674,6 @@ config ZISOFS necessary to create such a filesystem. Say Y here if you want to be able to read such compressed CD-ROMs. -config ZISOFS_FS -# for fs/nls/Config.in - tristate - depends on ZISOFS - default ISO9660_FS - config UDF_FS tristate "UDF file system support" help @@ -1094,7 +1088,7 @@ config AFFS_FS config ECRYPT_FS tristate "eCrypt filesystem layer support (EXPERIMENTAL)" - depends on EXPERIMENTAL && KEYS && CRYPTO + depends on EXPERIMENTAL && KEYS && CRYPTO && NET help Encrypted filesystem that operates on the VFS layer. See <file:Documentation/ecryptfs.txt> to learn more about diff --git a/fs/adfs/adfs.h b/fs/adfs/adfs.h index 29217ff36d4..936f2af39c4 100644 --- a/fs/adfs/adfs.h +++ b/fs/adfs/adfs.h @@ -84,7 +84,7 @@ void __adfs_error(struct super_block *sb, const char *function, */ /* dir_*.c */ -extern struct inode_operations adfs_dir_inode_operations; +extern const struct inode_operations adfs_dir_inode_operations; extern const struct file_operations adfs_dir_operations; extern struct dentry_operations adfs_dentry_operations; extern struct adfs_dir_ops adfs_f_dir_ops; @@ -93,7 +93,7 @@ extern struct adfs_dir_ops adfs_fplus_dir_ops; extern int adfs_dir_update(struct super_block *sb, struct object_info *obj); /* file.c */ -extern struct inode_operations adfs_file_inode_operations; +extern const struct inode_operations adfs_file_inode_operations; extern const struct file_operations adfs_file_operations; static inline __u32 signed_asl(__u32 val, signed int shift) diff --git a/fs/adfs/dir.c b/fs/adfs/dir.c index 2b8903893d3..fc1a8dc64d7 100644 --- a/fs/adfs/dir.c +++ b/fs/adfs/dir.c @@ -295,7 +295,7 @@ adfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) /* * directories can handle most operations... */ -struct inode_operations adfs_dir_inode_operations = { +const struct inode_operations adfs_dir_inode_operations = { .lookup = adfs_lookup, .setattr = adfs_notify_change, }; diff --git a/fs/adfs/file.c b/fs/adfs/file.c index 6101ea679cb..f544a285592 100644 --- a/fs/adfs/file.c +++ b/fs/adfs/file.c @@ -36,6 +36,6 @@ const struct file_operations adfs_file_operations = { .sendfile = generic_file_sendfile, }; -struct inode_operations adfs_file_inode_operations = { +const struct inode_operations adfs_file_inode_operations = { .setattr = adfs_notify_change, }; diff --git a/fs/adfs/super.c b/fs/adfs/super.c index 5023351a7af..2e5f2c8371e 100644 --- a/fs/adfs/super.c +++ b/fs/adfs/super.c @@ -254,7 +254,7 @@ static void destroy_inodecache(void) kmem_cache_destroy(adfs_inode_cachep); } -static struct super_operations adfs_sops = { +static const struct super_operations adfs_sops = { .alloc_inode = adfs_alloc_inode, .destroy_inode = adfs_destroy_inode, .write_inode = adfs_write_inode, diff --git a/fs/affs/affs.h b/fs/affs/affs.h index 1dc8438ef38..7db2d287e9f 100644 --- a/fs/affs/affs.h +++ b/fs/affs/affs.h @@ -188,9 +188,9 @@ extern void affs_dir_truncate(struct inode *); /* jump tables */ -extern struct inode_operations affs_file_inode_operations; -extern struct inode_operations affs_dir_inode_operations; -extern struct inode_operations affs_symlink_inode_operations; +extern const struct inode_operations affs_file_inode_operations; +extern const struct inode_operations affs_dir_inode_operations; +extern const struct inode_operations affs_symlink_inode_operations; extern const struct file_operations affs_file_operations; extern const struct file_operations affs_file_operations_ofs; extern const struct file_operations affs_dir_operations; diff --git a/fs/affs/dir.c b/fs/affs/dir.c index cad3ee34006..6e3f282424b 100644 --- a/fs/affs/dir.c +++ b/fs/affs/dir.c @@ -26,7 +26,7 @@ const struct file_operations affs_dir_operations = { /* * directories can handle most operations... */ -struct inode_operations affs_dir_inode_operations = { +const struct inode_operations affs_dir_inode_operations = { .create = affs_create, .lookup = affs_lookup, .link = affs_link, diff --git a/fs/affs/file.c b/fs/affs/file.c index 05b5e22de75..4aa8079e71b 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -38,7 +38,7 @@ const struct file_operations affs_file_operations = { .sendfile = generic_file_sendfile, }; -struct inode_operations affs_file_inode_operations = { +const struct inode_operations affs_file_inode_operations = { .truncate = affs_truncate, .setattr = affs_notify_change, }; diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 44d439cb69f..fce6848a464 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -12,7 +12,7 @@ #include "affs.h" -extern struct inode_operations affs_symlink_inode_operations; +extern const struct inode_operations affs_symlink_inode_operations; extern struct timezone sys_tz; void diff --git a/fs/affs/super.c b/fs/affs/super.c index 3de93e79994..a324045d855 100644 --- a/fs/affs/super.c +++ b/fs/affs/super.c @@ -112,7 +112,7 @@ static void destroy_inodecache(void) kmem_cache_destroy(affs_inode_cachep); } -static struct super_operations affs_sops = { +static const struct super_operations affs_sops = { .alloc_inode = affs_alloc_inode, .destroy_inode = affs_destroy_inode, .read_inode = affs_read_inode, diff --git a/fs/affs/symlink.c b/fs/affs/symlink.c index f802256a593..41782539c90 100644 --- a/fs/affs/symlink.c +++ b/fs/affs/symlink.c @@ -70,7 +70,7 @@ const struct address_space_operations affs_symlink_aops = { .readpage = affs_symlink_readpage, }; -struct inode_operations affs_symlink_inode_operations = { +const struct inode_operations affs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link, diff --git a/fs/afs/dir.c b/fs/afs/dir.c index 4acd0413405..9908462bcad 100644 --- a/fs/afs/dir.c +++ b/fs/afs/dir.c @@ -37,7 +37,7 @@ const struct file_operations afs_dir_file_operations = { .readdir = afs_dir_readdir, }; -struct inode_operations afs_dir_inode_operations = { +const struct inode_operations afs_dir_inode_operations = { .lookup = afs_dir_lookup, .getattr = afs_inode_getattr, #if 0 /* TODO */ diff --git a/fs/afs/file.c b/fs/afs/file.c index 2e8c42639ea..eeff14c3f74 100644 --- a/fs/afs/file.c +++ b/fs/afs/file.c @@ -30,7 +30,7 @@ static int afs_file_readpage(struct file *file, struct page *page); static void afs_file_invalidatepage(struct page *page, unsigned long offset); static int afs_file_releasepage(struct page *page, gfp_t gfp_flags); -struct inode_operations afs_file_inode_operations = { +const struct inode_operations afs_file_inode_operations = { .getattr = afs_inode_getattr, }; diff --git a/fs/afs/internal.h b/fs/afs/internal.h index e88b3b65ae4..5151d5da2c2 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h @@ -63,14 +63,14 @@ extern struct cachefs_index_def afs_cache_cell_index_def; /* * dir.c */ -extern struct inode_operations afs_dir_inode_operations; +extern const struct inode_operations afs_dir_inode_operations; extern const struct file_operations afs_dir_file_operations; /* * file.c */ extern const struct address_space_operations afs_fs_aops; -extern struct inode_operations afs_file_inode_operations; +extern const struct inode_operations afs_file_inode_operations; #ifdef AFS_CACHING_SUPPORT extern int afs_cache_get_page_cookie(struct page *page, @@ -104,7 +104,7 @@ extern struct cachefs_netfs afs_cache_netfs; /* * mntpt.c */ -extern struct inode_operations afs_mntpt_inode_operations; +extern const struct inode_operations afs_mntpt_inode_operations; extern const struct file_operations afs_mntpt_file_operations; extern struct afs_timer afs_mntpt_expiry_timer; extern struct afs_timer_ops afs_mntpt_expiry_timer_ops; diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c index 8f74e845082..fdf23b2a211 100644 --- a/fs/afs/mntpt.c +++ b/fs/afs/mntpt.c @@ -36,7 +36,7 @@ const struct file_operations afs_mntpt_file_operations = { .open = afs_mntpt_open, }; -struct inode_operations afs_mntpt_inode_operations = { +const struct inode_operations afs_mntpt_inode_operations = { .lookup = afs_mntpt_lookup, .follow_link = afs_mntpt_follow_link, .readlink = page_readlink, diff --git a/fs/afs/super.c b/fs/afs/super.c index 18d9b77ba40..eb7e32349da 100644 --- a/fs/afs/super.c +++ b/fs/afs/super.c @@ -56,7 +56,7 @@ struct file_system_type afs_fs_type = { .fs_flags = FS_BINARY_MOUNTDATA, }; -static struct super_operations afs_super_ops = { +static const struct super_operations afs_super_ops = { .statfs = simple_statfs, .alloc_inode = afs_alloc_inode, .drop_inode = generic_delete_inode, @@ -132,7 +132,7 @@ static int aio_setup_ring(struct kioctx *ctx) dprintk("attempting mmap of %lu bytes\n", info->mmap_size); down_write(&ctx->mm->mmap_sem); info->mmap_base = do_mmap(NULL, 0, info->mmap_size, - PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, + PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, 0); if (IS_ERR((void *)info->mmap_base)) { up_write(&ctx->mm->mmap_sem); @@ -211,11 +211,10 @@ static struct kioctx *ioctx_alloc(unsigned nr_events) if ((unsigned long)nr_events > aio_max_nr) return ERR_PTR(-EAGAIN); - ctx = kmem_cache_alloc(kioctx_cachep, GFP_KERNEL); + ctx = kmem_cache_zalloc(kioctx_cachep, GFP_KERNEL); if (!ctx) return ERR_PTR(-ENOMEM); - memset(ctx, 0, sizeof(*ctx)); ctx->max_reqs = nr_events; mm = ctx->mm = current->mm; atomic_inc(&mm->mm_count); diff --git a/fs/autofs/autofs_i.h b/fs/autofs/autofs_i.h index 906ba5ce226..4ef544434b5 100644 --- a/fs/autofs/autofs_i.h +++ b/fs/autofs/autofs_i.h @@ -142,8 +142,8 @@ struct autofs_dir_ent *autofs_expire(struct super_block *,struct autofs_sb_info /* Operations structures */ -extern struct inode_operations autofs_root_inode_operations; -extern struct inode_operations autofs_symlink_inode_operations; +extern const struct inode_operations autofs_root_inode_operations; +extern const struct inode_operations autofs_symlink_inode_operations; extern const struct file_operations autofs_root_operations; /* Initializing function */ diff --git a/fs/autofs/inode.c b/fs/autofs/inode.c index f968d134280..aa0b61ff827 100644 --- a/fs/autofs/inode.c +++ b/fs/autofs/inode.c @@ -52,7 +52,7 @@ out_kill_sb: static void autofs_read_inode(struct inode *inode); -static struct super_operations autofs_sops = { +static const struct super_operations autofs_sops = { .read_inode = autofs_read_inode, .statfs = simple_statfs, }; diff --git a/fs/autofs/root.c b/fs/autofs/root.c index e698c51d2b0..f2597205939 100644 --- a/fs/autofs/root.c +++ b/fs/autofs/root.c @@ -32,7 +32,7 @@ const struct file_operations autofs_root_operations = { .ioctl = autofs_root_ioctl, }; -struct inode_operations autofs_root_inode_operations = { +const struct inode_operations autofs_root_inode_operations = { .lookup = autofs_root_lookup, .unlink = autofs_root_unlink, .symlink = autofs_root_symlink, diff --git a/fs/autofs/symlink.c b/fs/autofs/symlink.c index c74f2eb6577..7ce9cb2c9ce 100644 --- a/fs/autofs/symlink.c +++ b/fs/autofs/symlink.c @@ -20,7 +20,7 @@ static void *autofs_follow_link(struct dentry *dentry, struct nameidata *nd) return NULL; } -struct inode_operations autofs_symlink_inode_operations = { +const struct inode_operations autofs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = autofs_follow_link }; diff --git a/fs/autofs4/autofs_i.h b/fs/autofs4/autofs_i.h index 216b1a364cc..6b4cec3f272 100644 --- a/fs/autofs4/autofs_i.h +++ b/fs/autofs4/autofs_i.h @@ -168,11 +168,11 @@ int autofs4_expire_multi(struct super_block *, struct vfsmount *, /* Operations structures */ -extern struct inode_operations autofs4_symlink_inode_operations; -extern struct inode_operations autofs4_dir_inode_operations; -extern struct inode_operations autofs4_root_inode_operations; -extern struct inode_operations autofs4_indirect_root_inode_operations; -extern struct inode_operations autofs4_direct_root_inode_operations; +extern const struct inode_operations autofs4_symlink_inode_operations; +extern const struct inode_operations autofs4_dir_inode_operations; +extern const struct inode_operations autofs4_root_inode_operations; +extern const struct inode_operations autofs4_indirect_root_inode_operations; +extern const struct inode_operations autofs4_direct_root_inode_operations; extern const struct file_operations autofs4_dir_operations; extern const struct file_operations autofs4_root_operations; diff --git a/fs/autofs4/inode.c b/fs/autofs4/inode.c index e8f6c5ad3e9..5e458e096ef 100644 --- a/fs/autofs4/inode.c +++ b/fs/autofs4/inode.c @@ -196,7 +196,7 @@ static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt) return 0; } -static struct super_operations autofs4_sops = { +static const struct super_operations autofs4_sops = { .statfs = simple_statfs, .show_options = autofs4_show_options, }; diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c index 8d05b9f7578..47fee96c218 100644 --- a/fs/autofs4/root.c +++ b/fs/autofs4/root.c @@ -47,7 +47,7 @@ const struct file_operations autofs4_dir_operations = { .readdir = autofs4_dir_readdir, }; -struct inode_operations autofs4_indirect_root_inode_operations = { +const struct inode_operations autofs4_indirect_root_inode_operations = { .lookup = autofs4_lookup, .unlink = autofs4_dir_unlink, .symlink = autofs4_dir_symlink, @@ -55,7 +55,7 @@ struct inode_operations autofs4_indirect_root_inode_operations = { .rmdir = autofs4_dir_rmdir, }; -struct inode_operations autofs4_direct_root_inode_operations = { +const struct inode_operations autofs4_direct_root_inode_operations = { .lookup = autofs4_lookup, .unlink = autofs4_dir_unlink, .mkdir = autofs4_dir_mkdir, @@ -63,7 +63,7 @@ struct inode_operations autofs4_direct_root_inode_operations = { .follow_link = autofs4_follow_link, }; -struct inode_operations autofs4_dir_inode_operations = { +const struct inode_operations autofs4_dir_inode_operations = { .lookup = autofs4_lookup, .unlink = autofs4_dir_unlink, .symlink = autofs4_dir_symlink, diff --git a/fs/autofs4/symlink.c b/fs/autofs4/symlink.c index 2ea2c98fd84..b4ea82934d2 100644 --- a/fs/autofs4/symlink.c +++ b/fs/autofs4/symlink.c @@ -19,7 +19,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) return NULL; } -struct inode_operations autofs4_symlink_inode_operations = { +const struct inode_operations autofs4_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = autofs4_follow_link }; diff --git a/fs/bad_inode.c b/fs/bad_inode.c index 869f5193ecc..efeab2fab40 100644 --- a/fs/bad_inode.c +++ b/fs/bad_inode.c @@ -291,7 +291,7 @@ static int bad_inode_removexattr(struct dentry *dentry, const char *name) return -EIO; } -static struct inode_operations bad_inode_ops = +static const struct inode_operations bad_inode_ops = { .create = bad_inode_create, .lookup = bad_inode_lookup, diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c index 481e59b9d91..cc6cc8ed2e3 100644 --- a/fs/befs/linuxvfs.c +++ b/fs/befs/linuxvfs.c @@ -68,7 +68,7 @@ static const struct file_operations befs_dir_operations = { .readdir = befs_readdir, }; -static struct inode_operations befs_dir_inode_operations = { +static const struct inode_operations befs_dir_inode_operations = { .lookup = befs_lookup, }; @@ -78,7 +78,7 @@ static const struct address_space_operations befs_aops = { .bmap = befs_bmap, }; -static struct inode_operations befs_symlink_inode_operations = { +static const struct inode_operations befs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = befs_follow_link, .put_link = befs_put_link, diff --git a/fs/bfs/bfs.h b/fs/bfs/bfs.h index 31973bbbf05..130f6c66c5b 100644 --- a/fs/bfs/bfs.h +++ b/fs/bfs/bfs.h @@ -48,12 +48,12 @@ static inline struct bfs_inode_info *BFS_I(struct inode *inode) /* file.c */ -extern struct inode_operations bfs_file_inops; +extern const struct inode_operations bfs_file_inops; extern const struct file_operations bfs_file_operations; extern const struct address_space_operations bfs_aops; /* dir.c */ -extern struct inode_operations bfs_dir_inops; +extern const struct inode_operations bfs_dir_inops; extern const struct file_operations bfs_dir_operations; #endif /* _FS_BFS_BFS_H */ diff --git a/fs/bfs/dir.c b/fs/bfs/dir.c index 2a746e688df..097f1497f74 100644 --- a/fs/bfs/dir.c +++ b/fs/bfs/dir.c @@ -260,7 +260,7 @@ end_rename: return error; } -struct inode_operations bfs_dir_inops = { +const struct inode_operations bfs_dir_inops = { .create = bfs_create, .lookup = bfs_lookup, .link = bfs_link, diff --git a/fs/bfs/file.c b/fs/bfs/file.c index a9164a87f8d..ef4d1fa04e6 100644 --- a/fs/bfs/file.c +++ b/fs/bfs/file.c @@ -164,4 +164,4 @@ const struct address_space_operations bfs_aops = { .bmap = bfs_bmap, }; -struct inode_operations bfs_file_inops; +const struct inode_operations bfs_file_inops; diff --git a/fs/bfs/inode.c b/fs/bfs/inode.c index 134c99941a6..93d6219243a 100644 --- a/fs/bfs/inode.c +++ b/fs/bfs/inode.c @@ -270,7 +270,7 @@ static void destroy_inodecache(void) kmem_cache_destroy(bfs_inode_cachep); } -static struct super_operations bfs_sops = { +static const struct super_operations bfs_sops = { .alloc_inode = bfs_alloc_inode, .destroy_inode = bfs_destroy_inode, .read_inode = bfs_read_inode, diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c index a4d933a5120..5810aa1339f 100644 --- a/fs/binfmt_elf_fdpic.c +++ b/fs/binfmt_elf_fdpic.c @@ -372,7 +372,7 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm, down_write(¤t->mm->mmap_sem); current->mm->start_brk = do_mmap(NULL, 0, stack_size, PROT_READ | PROT_WRITE | PROT_EXEC, - MAP_PRIVATE | MAP_ANON | MAP_GROWSDOWN, + MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN, 0); if (IS_ERR_VALUE(current->mm->start_brk)) { diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c index ae8595d4985..7b0265d7f3a 100644 --- a/fs/binfmt_flat.c +++ b/fs/binfmt_flat.c @@ -419,7 +419,7 @@ static int load_flat_file(struct linux_binprm * bprm, unsigned long textpos = 0, datapos = 0, result; unsigned long realdatastart = 0; unsigned long text_len, data_len, bss_len, stack_len, flags; - unsigned long memp = 0; /* for finding the brk area */ + unsigned long len, reallen, memp = 0; unsigned long extra, rlim; unsigned long *reloc = 0, *rp; struct inode *inode; @@ -540,10 +540,18 @@ static int load_flat_file(struct linux_binprm * bprm, goto err; } + len = data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long); down_write(¤t->mm->mmap_sem); - realdatastart = do_mmap(0, 0, data_len + extra + - MAX_SHARED_LIBS * sizeof(unsigned long), - PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0); + realdatastart = do_mmap(0, 0, len, + PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE, 0); + /* Remap to use all availabe slack region space */ + if (realdatastart && (realdatastart < (unsigned long)-4096)) { + reallen = ksize(realdatastart); + if (reallen > len) { + realdatastart = do_mremap(realdatastart, len, + reallen, MREMAP_FIXED, realdatastart); + } + } up_write(¤t->mm->mmap_sem); if (realdatastart == 0 || realdatastart >= (unsigned long)-4096) { @@ -584,11 +592,20 @@ static int load_flat_file(struct linux_binprm * bprm, } else { + len = text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long); down_write(¤t->mm->mmap_sem); - textpos = do_mmap(0, 0, text_len + data_len + extra + - MAX_SHARED_LIBS * sizeof(unsigned long), - PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0); + textpos = do_mmap(0, 0, len, + PROT_READ | PROT_EXEC | PROT_WRITE, MAP_PRIVATE, 0); + /* Remap to use all availabe slack region space */ + if (textpos && (textpos < (unsigned long) -4096)) { + reallen = ksize(textpos); + if (reallen > len) { + textpos = do_mremap(textpos, len, reallen, + MREMAP_FIXED, textpos); + } + } up_write(¤t->mm->mmap_sem); + if (!textpos || textpos >= (unsigned long) -4096) { if (!textpos) textpos = (unsigned long) -ENOMEM; diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c index c2e08252af3..e6f57990b12 100644 --- a/fs/binfmt_misc.c +++ b/fs/binfmt_misc.c @@ -719,7 +719,7 @@ static const struct file_operations bm_status_operations = { /* Superblock handling */ -static struct super_operations s_ops = { +static const struct super_operations s_ops = { .statfs = simple_statfs, .clear_inode = bm_clear_inode, }; diff --git a/fs/block_dev.c b/fs/block_dev.c index fc7028b685f..0c59b703e9d 100644 --- a/fs/block_dev.c +++ b/fs/block_dev.c @@ -489,7 +489,7 @@ static void bdev_clear_inode(struct inode *inode) spin_unlock(&bdev_lock); } -static struct super_operations bdev_sops = { +static const struct super_operations bdev_sops = { .statfs = simple_statfs, .alloc_inode = bdev_alloc_inode, .destroy_inode = bdev_destroy_inode, diff --git a/fs/buffer.c b/fs/buffer.c index 1ad674fd348..f99c509697c 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -78,6 +78,7 @@ EXPORT_SYMBOL(__lock_buffer); void fastcall unlock_buffer(struct buffer_head *bh) { + smp_mb__before_clear_bit(); clear_buffer_locked(bh); smp_mb__after_clear_bit(); wake_up_bit(&bh->b_state, BH_Lock); @@ -345,7 +346,7 @@ void invalidate_bdev(struct block_device *bdev, int destroy_dirty_buffers) * We really want to use invalidate_inode_pages2() for * that, but not until that's cleaned up. */ - invalidate_inode_pages(mapping); + invalidate_mapping_pages(mapping, 0, -1); } /* @@ -1282,11 +1283,11 @@ static void bh_lru_install(struct buffer_head *bh) * Look up the bh in this cpu's LRU. If it's there, move it to the head. */ static struct buffer_head * -lookup_bh_lru(struct block_device *bdev, sector_t block, int size) +lookup_bh_lru(struct block_device *bdev, sector_t block, unsigned size) { struct buffer_head *ret = NULL; struct bh_lru *lru; - int i; + unsigned int i; check_irqs_on(); bh_lru_lock(); @@ -1318,7 +1319,7 @@ lookup_bh_lru(struct block_device *bdev, sector_t block, int size) * NULL */ struct buffer_head * -__find_get_block(struct block_device *bdev, sector_t block, int size) +__find_get_block(struct block_device *bdev, sector_t block, unsigned size) { struct buffer_head *bh = lookup_bh_lru(bdev, block, size); @@ -1346,7 +1347,7 @@ EXPORT_SYMBOL(__find_get_block); * attempt is failing. FIXME, perhaps? */ struct buffer_head * -__getblk(struct block_device *bdev, sector_t block, int size) +__getblk(struct block_device *bdev, sector_t block, unsigned size) { struct buffer_head *bh = __find_get_block(bdev, block, size); @@ -1360,7 +1361,7 @@ EXPORT_SYMBOL(__getblk); /* * Do async read-ahead on a buffer.. */ -void __breadahead(struct block_device *bdev, sector_t block, int size) +void __breadahead(struct block_device *bdev, sector_t block, unsigned size) { struct buffer_head *bh = __getblk(bdev, block, size); if (likely(bh)) { @@ -1380,7 +1381,7 @@ EXPORT_SYMBOL(__breadahead); * It returns NULL if the block was unreadable. */ struct buffer_head * -__bread(struct block_device *bdev, sector_t block, int size) +__bread(struct block_device *bdev, sector_t block, unsigned size) { struct buffer_head *bh = __getblk(bdev, block, size); @@ -1439,6 +1440,7 @@ static void discard_buffer(struct buffer_head * bh) clear_buffer_req(bh); clear_buffer_new(bh); clear_buffer_delay(bh); + clear_buffer_unwritten(bh); unlock_buffer(bh); } @@ -1822,6 +1824,7 @@ static int __block_prepare_write(struct inode *inode, struct page *page, continue; } if (!buffer_uptodate(bh) && !buffer_delay(bh) && + !buffer_unwritten(bh) && (block_start < from || block_end > to)) { ll_rw_block(READ, 1, &bh); *wait_bh++=bh; @@ -2543,7 +2546,7 @@ int block_truncate_page(struct address_space *mapping, if (PageUptodate(page)) set_buffer_uptodate(bh); - if (!buffer_uptodate(bh) && !buffer_delay(bh)) { + if (!buffer_uptodate(bh) && !buffer_delay(bh) && !buffer_unwritten(bh)) { err = -EIO; ll_rw_block(READ, 1, &bh); wait_on_buffer(bh); diff --git a/fs/char_dev.c b/fs/char_dev.c index a885f46ca00..e6194e2b9bb 100644 --- a/fs/char_dev.c +++ b/fs/char_dev.c @@ -108,6 +108,13 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor, /* temporary */ if (major == 0) { for (i = ARRAY_SIZE(chrdevs)-1; i > 0; i--) { + /* + * Disallow the LANANA-assigned LOCAL/EXPERIMENTAL + * majors + */ + if ((60 <= i && i <= 63) || (120 <= i && i <= 127) || + (240 <= i && i <= 254)) + continue; if (chrdevs[i] == NULL) break; } diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 93ef09971d2..e8287c4c6eb 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c @@ -64,7 +64,7 @@ extern struct task_struct * oplockThread; /* remove sparse warning */ struct task_struct * oplockThread = NULL; extern struct task_struct * dnotifyThread; /* remove sparse warning */ struct task_struct * dnotifyThread = NULL; -static struct super_operations cifs_super_ops; +static const struct super_operations cifs_super_ops; unsigned int CIFSMaxBufSize = CIFS_MAX_MSGSIZE; module_param(CIFSMaxBufSize, int, 0); MODULE_PARM_DESC(CIFSMaxBufSize,"Network buffer size (not including header). Default: 16384 Range: 8192 to 130048"); @@ -453,7 +453,7 @@ static int cifs_remount(struct super_block *sb, int *flags, char *data) return 0; } -static struct super_operations cifs_super_ops = { +static const struct super_operations cifs_super_ops = { .read_inode = cifs_read_inode, .put_super = cifs_put_super, .statfs = cifs_statfs, @@ -533,7 +533,7 @@ static struct file_system_type cifs_fs_type = { .kill_sb = kill_anon_super, /* .fs_flags */ }; -struct inode_operations cifs_dir_inode_ops = { +const struct inode_operations cifs_dir_inode_ops = { .create = cifs_create, .lookup = cifs_lookup, .getattr = cifs_getattr, @@ -555,7 +555,7 @@ struct inode_operations cifs_dir_inode_ops = { #endif }; -struct inode_operations cifs_file_inode_ops = { +const struct inode_operations cifs_file_inode_ops = { /* revalidate:cifs_revalidate, */ .setattr = cifs_setattr, .getattr = cifs_getattr, /* do we need this anymore? */ @@ -569,7 +569,7 @@ struct inode_operations cifs_file_inode_ops = { #endif }; -struct inode_operations cifs_symlink_inode_ops = { +const struct inode_operations cifs_symlink_inode_ops = { .readlink = generic_readlink, .follow_link = cifs_follow_link, .put_link = cifs_put_link, diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index 8aa66dcf13b..01ae24af9cf 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h @@ -36,13 +36,13 @@ extern const struct address_space_operations cifs_addr_ops; extern const struct address_space_operations cifs_addr_ops_smallbuf; /* Functions related to super block operations */ -/* extern struct super_operations cifs_super_ops;*/ +/* extern const struct super_operations cifs_super_ops;*/ extern void cifs_read_inode(struct inode *); extern void cifs_delete_inode(struct inode *); /* extern void cifs_write_inode(struct inode *); *//* BB not needed yet */ /* Functions related to inodes */ -extern struct inode_operations cifs_dir_inode_ops; +extern const struct inode_operations cifs_dir_inode_ops; extern int cifs_create(struct inode *, struct dentry *, int, struct nameidata *); extern struct dentry * cifs_lookup(struct inode *, struct dentry *, @@ -58,8 +58,8 @@ extern int cifs_revalidate(struct dentry *); extern int cifs_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int cifs_setattr(struct dentry *, struct iattr *); -extern struct inode_operations cifs_file_inode_ops; -extern struct inode_operations cifs_symlink_inode_ops; +extern const struct inode_operations cifs_file_inode_ops; +extern const struct inode_operations cifs_symlink_inode_ops; /* Functions related to files and directories */ extern const struct file_operations cifs_file_ops; diff --git a/fs/coda/cnode.c b/fs/coda/cnode.c index 4c9fecbfa91..28c872747f8 100644 --- a/fs/coda/cnode.c +++ b/fs/coda/cnode.c @@ -16,7 +16,7 @@ static inline int coda_fideq(struct CodaFid *fid1, struct CodaFid *fid2) return memcmp(fid1, fid2, sizeof(*fid1)) == 0; } -static struct inode_operations coda_symlink_inode_operations = { +static const struct inode_operations coda_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link, diff --git a/fs/coda/dir.c b/fs/coda/dir.c index 0c6f7f3b3dd..9ddf5ed6216 100644 --- a/fs/coda/dir.c +++ b/fs/coda/dir.c @@ -66,7 +66,7 @@ static struct dentry_operations coda_dentry_operations = .d_delete = coda_dentry_delete, }; -struct inode_operations coda_dir_inode_operations = +const struct inode_operations coda_dir_inode_operations = { .create = coda_create, .lookup = coda_lookup, diff --git a/fs/coda/inode.c b/fs/coda/inode.c index 01395defed8..614175a3b02 100644 --- a/fs/coda/inode.c +++ b/fs/coda/inode.c @@ -90,7 +90,7 @@ static int coda_remount(struct super_block *sb, int *flags, char *data) } /* exported operations */ -static struct super_operations coda_super_operations = +static const struct super_operations coda_super_operations = { .alloc_inode = coda_alloc_inode, .destroy_inode = coda_destroy_inode, @@ -271,7 +271,7 @@ int coda_setattr(struct dentry *de, struct iattr *iattr) return error; } -struct inode_operations coda_file_inode_operations = { +const struct inode_operations coda_file_inode_operations = { .permission = coda_permission, .getattr = coda_getattr, .setattr = coda_setattr, diff --git a/fs/coda/pioctl.c b/fs/coda/pioctl.c index 214822be87b..2bf3026adc8 100644 --- a/fs/coda/pioctl.c +++ b/fs/coda/pioctl.c @@ -30,7 +30,7 @@ static int coda_pioctl(struct inode * inode, struct file * filp, unsigned int cmd, unsigned long user_data); /* exported from this file */ -struct inode_operations coda_ioctl_inode_operations = +const struct inode_operations coda_ioctl_inode_operations = { .permission = coda_ioctl_permission, .setattr = coda_setattr, diff --git a/fs/coda/sysctl.c b/fs/coda/sysctl.c index 1c82e9a7d7c..db3b1a9c9a5 100644 --- a/fs/coda/sysctl.c +++ b/fs/coda/sysctl.c @@ -15,6 +15,7 @@ #include <linux/mm.h> #include <linux/sysctl.h> #include <linux/proc_fs.h> +#include <linux/seq_file.h> #include <linux/slab.h> #include <linux/stat.h> #include <linux/ctype.h> @@ -84,15 +85,11 @@ static int do_reset_coda_cache_inv_stats( ctl_table * table, int write, return 0; } -static int coda_vfs_stats_get_info( char * buffer, char ** start, - off_t offset, int length) +static int proc_vfs_stats_show(struct seq_file *m, void *v) { - int len=0; - off_t begin; struct coda_vfs_stats * ps = & coda_vfs_stat; - /* this works as long as we are below 1024 characters! */ - len += sprintf( buffer, + seq_printf(m, "Coda VFS statistics\n" "===================\n\n" "File Operations:\n" @@ -132,28 +129,14 @@ static int coda_vfs_stats_get_info( char * buffer, char ** start, ps->rmdir, ps->rename, ps->permission); - - begin = offset; - *start = buffer + begin; - len -= begin; - - if ( len > length ) - len = length; - if ( len < 0 ) - len = 0; - - return len; + return 0; } -static int coda_cache_inv_stats_get_info( char * buffer, char ** start, - off_t offset, int length) +static int proc_cache_inv_stats_show(struct seq_file *m, void *v) { - int len=0; - off_t begin; struct coda_cache_inv_stats * ps = & coda_cache_inv_stat; - /* this works as long as we are below 1024 characters! */ - len += sprintf( buffer, + seq_printf(m, "Coda cache invalidation statistics\n" "==================================\n\n" "flush\t\t%9d\n" @@ -170,19 +153,35 @@ static int coda_cache_inv_stats_get_info( char * buffer, char ** start, ps->zap_vnode, ps->purge_fid, ps->replace ); - - begin = offset; - *start = buffer + begin; - len -= begin; + return 0; +} - if ( len > length ) - len = length; - if ( len < 0 ) - len = 0; +static int proc_vfs_stats_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_vfs_stats_show, NULL); +} - return len; +static int proc_cache_inv_stats_open(struct inode *inode, struct file *file) +{ + return single_open(file, proc_cache_inv_stats_show, NULL); } +static const struct file_operations proc_vfs_stats_fops = { + .owner = THIS_MODULE, + .open = proc_vfs_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + +static const struct file_operations proc_cache_inv_stats_fops = { + .owner = THIS_MODULE, + .open = proc_cache_inv_stats_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; + static ctl_table coda_table[] = { {CODA_TIMEOUT, "timeout", &coda_timeout, sizeof(int), 0644, NULL, &proc_dointvec}, {CODA_HARD, "hard", &coda_hard, sizeof(int), 0644, NULL, &proc_dointvec}, @@ -212,9 +211,6 @@ static struct proc_dir_entry* proc_fs_coda; #endif -#define coda_proc_create(name,get_info) \ - create_proc_info_entry(name, 0, proc_fs_coda, get_info) - void coda_sysctl_init(void) { reset_coda_vfs_stats(); @@ -223,9 +219,15 @@ void coda_sysctl_init(void) #ifdef CONFIG_PROC_FS proc_fs_coda = proc_mkdir("coda", proc_root_fs); if (proc_fs_coda) { + struct proc_dir_entry *pde; + proc_fs_coda->owner = THIS_MODULE; - coda_proc_create("vfs_stats", coda_vfs_stats_get_info); - coda_proc_create("cache_inv_stats", coda_cache_inv_stats_get_info); + pde = create_proc_entry("vfs_stats", 0, proc_fs_coda); + if (pde) + pde->proc_fops = &proc_vfs_stats_fops; + pde = create_proc_entry("cache_inv_stats", 0, proc_fs_coda); + if (pde) + pde->proc_fops = &proc_cache_inv_stats_fops; } #endif diff --git a/fs/configfs/configfs_internal.h b/fs/configfs/configfs_internal.h index f92cd303d2c..7b48c034b31 100644 --- a/fs/configfs/configfs_internal.h +++ b/fs/configfs/configfs_internal.h @@ -75,8 +75,8 @@ extern struct super_block * configfs_sb; extern const struct file_operations configfs_dir_operations; extern const struct file_operations configfs_file_operations; extern const struct file_operations bin_fops; -extern struct inode_operations configfs_dir_inode_operations; -extern struct inode_operations configfs_symlink_inode_operations; +extern const struct inode_operations configfs_dir_inode_operations; +extern const struct inode_operations configfs_symlink_inode_operations; 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 1814ba44680..34750d5e4ff 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -72,11 +72,10 @@ static struct configfs_dirent *configfs_new_dirent(struct configfs_dirent * pare { struct configfs_dirent * sd; - sd = kmem_cache_alloc(configfs_dir_cachep, GFP_KERNEL); + sd = kmem_cache_zalloc(configfs_dir_cachep, GFP_KERNEL); if (!sd) return NULL; - memset(sd, 0, sizeof(*sd)); atomic_set(&sd->s_count, 1); INIT_LIST_HEAD(&sd->s_links); INIT_LIST_HEAD(&sd->s_children); @@ -931,7 +930,7 @@ static int configfs_rmdir(struct inode *dir, struct dentry *dentry) return 0; } -struct inode_operations configfs_dir_inode_operations = { +const struct inode_operations configfs_dir_inode_operations = { .mkdir = configfs_mkdir, .rmdir = configfs_rmdir, .symlink = configfs_symlink, diff --git a/fs/configfs/inode.c b/fs/configfs/inode.c index fb18917954a..2ec9beac17c 100644 --- a/fs/configfs/inode.c +++ b/fs/configfs/inode.c @@ -49,7 +49,7 @@ static struct backing_dev_info configfs_backing_dev_info = { .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, }; -static struct inode_operations configfs_inode_operations ={ +static const struct inode_operations configfs_inode_operations ={ .setattr = configfs_setattr, }; diff --git a/fs/configfs/mount.c b/fs/configfs/mount.c index ed678529ebb..6f573004cd7 100644 --- a/fs/configfs/mount.c +++ b/fs/configfs/mount.c @@ -41,7 +41,7 @@ struct super_block * configfs_sb = NULL; struct kmem_cache *configfs_dir_cachep; static int configfs_mnt_count = 0; -static struct super_operations configfs_ops = { +static const struct super_operations configfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, }; diff --git a/fs/configfs/symlink.c b/fs/configfs/symlink.c index fb65e0800a8..22700d2857d 100644 --- a/fs/configfs/symlink.c +++ b/fs/configfs/symlink.c @@ -272,7 +272,7 @@ static void configfs_put_link(struct dentry *dentry, struct nameidata *nd, } } -struct inode_operations configfs_symlink_inode_operations = { +const struct inode_operations configfs_symlink_inode_operations = { .follow_link = configfs_follow_link, .readlink = generic_readlink, .put_link = configfs_put_link, diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 6db03fb089d..facd0c89be8 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c @@ -27,8 +27,8 @@ #include <asm/uaccess.h> -static struct super_operations cramfs_ops; -static struct inode_operations cramfs_dir_inode_operations; +static const struct super_operations cramfs_ops; +static const struct inode_operations cramfs_dir_inode_operations; static const struct file_operations cramfs_directory_operations; static const struct address_space_operations cramfs_aops; @@ -518,11 +518,11 @@ static const struct file_operations cramfs_directory_operations = { .readdir = cramfs_readdir, }; -static struct inode_operations cramfs_dir_inode_operations = { +static const struct inode_operations cramfs_dir_inode_operations = { .lookup = cramfs_lookup, }; -static struct super_operations cramfs_ops = { +static const struct super_operations cramfs_ops = { .put_super = cramfs_put_super, .remount_fs = cramfs_remount, .statfs = cramfs_statfs, diff --git a/fs/dcache.c b/fs/dcache.c index d68631f18df..b5f61393291 100644 --- a/fs/dcache.c +++ b/fs/dcache.c @@ -1739,45 +1739,41 @@ shouldnt_be_hashed: * @rootmnt: vfsmnt to which the root dentry belongs * @buffer: buffer to return value in * @buflen: buffer length + * @fail_deleted: what to return for deleted files * - * Convert a dentry into an ASCII path name. If the entry has been deleted - * the string " (deleted)" is appended. Note that this is ambiguous. + * Convert a dentry into an ASCII path name. If the entry has been deleted, + * then if @fail_deleted is true, ERR_PTR(-ENOENT) is returned. Otherwise, + * the the string " (deleted)" is appended. Note that this is ambiguous. * - * Returns the buffer or an error code if the path was too long. - * - * "buflen" should be positive. Caller holds the dcache_lock. + * Returns the buffer or an error code. */ -static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, - struct dentry *root, struct vfsmount *rootmnt, - char *buffer, int buflen) +static char *__d_path(struct dentry *dentry, struct vfsmount *vfsmnt, + struct dentry *root, struct vfsmount *rootmnt, + char *buffer, int buflen, int fail_deleted) { - char * end = buffer+buflen; - char * retval; - int namelen; + int namelen, is_slash; + + if (buflen < 2) + return ERR_PTR(-ENAMETOOLONG); + buffer += --buflen; + *buffer = '\0'; - *--end = '\0'; - buflen--; + spin_lock(&dcache_lock); if (!IS_ROOT(dentry) && d_unhashed(dentry)) { - buflen -= 10; - end -= 10; - if (buflen < 0) + if (fail_deleted) { + buffer = ERR_PTR(-ENOENT); + goto out; + } + if (buflen < 10) goto Elong; - memcpy(end, " (deleted)", 10); + buflen -= 10; + buffer -= 10; + memcpy(buffer, " (deleted)", 10); } - - if (buflen < 1) - goto Elong; - /* Get '/' right */ - retval = end-1; - *retval = '/'; - - for (;;) { + while (dentry != root || vfsmnt != rootmnt) { struct dentry * parent; - if (dentry == root && vfsmnt == rootmnt) - break; if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { - /* Global root? */ spin_lock(&vfsmount_lock); if (vfsmnt->mnt_parent == vfsmnt) { spin_unlock(&vfsmount_lock); @@ -1791,33 +1787,60 @@ static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, parent = dentry->d_parent; prefetch(parent); namelen = dentry->d_name.len; - buflen -= namelen + 1; - if (buflen < 0) + if (buflen <= namelen) goto Elong; - end -= namelen; - memcpy(end, dentry->d_name.name, namelen); - *--end = '/'; - retval = end; + buflen -= namelen + 1; + buffer -= namelen; + memcpy(buffer, dentry->d_name.name, namelen); + *--buffer = '/'; dentry = parent; } + /* Get '/' right */ + if (*buffer != '/') + *--buffer = '/'; - return retval; +out: + spin_unlock(&dcache_lock); + return buffer; global_root: + /* + * We went past the (vfsmount, dentry) we were looking for and have + * either hit a root dentry, a lazily unmounted dentry, an + * unconnected dentry, or the file is on a pseudo filesystem. + */ namelen = dentry->d_name.len; - buflen -= namelen; - if (buflen < 0) + is_slash = (namelen == 1 && *dentry->d_name.name == '/'); + if (is_slash || (dentry->d_sb->s_flags & MS_NOUSER)) { + /* + * Make sure we won't return a pathname starting with '/'. + * + * Historically, we also glue together the root dentry and + * remaining name for pseudo filesystems like pipefs, which + * have the MS_NOUSER flag set. This results in pathnames + * like "pipe:[439336]". + */ + if (*buffer == '/') { + buffer++; + buflen++; + } + if (is_slash) + goto out; + } + if (buflen < namelen) goto Elong; - retval -= namelen-1; /* hit the slash */ - memcpy(retval, dentry->d_name.name, namelen); - return retval; + buffer -= namelen; + memcpy(buffer, dentry->d_name.name, namelen); + goto out; + Elong: - return ERR_PTR(-ENAMETOOLONG); + buffer = ERR_PTR(-ENAMETOOLONG); + goto out; } /* write full pathname into buffer and return start of pathname */ -char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, - char *buf, int buflen) +char *d_path(struct dentry *dentry, struct vfsmount *vfsmnt, char *buf, + int buflen) { char *res; struct vfsmount *rootmnt; @@ -1827,9 +1850,7 @@ char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, rootmnt = mntget(current->fs->rootmnt); root = dget(current->fs->root); read_unlock(¤t->fs->lock); - spin_lock(&dcache_lock); - res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen); - spin_unlock(&dcache_lock); + res = __d_path(dentry, vfsmnt, root, rootmnt, buf, buflen, 0); dput(root); mntput(rootmnt); return res; @@ -1855,10 +1876,10 @@ char * d_path(struct dentry *dentry, struct vfsmount *vfsmnt, */ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) { - int error; + int error, len; struct vfsmount *pwdmnt, *rootmnt; struct dentry *pwd, *root; - char *page = (char *) __get_free_page(GFP_USER); + char *page = (char *) __get_free_page(GFP_USER), *cwd; if (!page) return -ENOMEM; @@ -1870,29 +1891,18 @@ asmlinkage long sys_getcwd(char __user *buf, unsigned long size) root = dget(current->fs->root); read_unlock(¤t->fs->lock); - error = -ENOENT; - /* Has the current directory has been unlinked? */ - spin_lock(&dcache_lock); - if (pwd->d_parent == pwd || !d_unhashed(pwd)) { - unsigned long len; - char * cwd; - - cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE); - spin_unlock(&dcache_lock); - - error = PTR_ERR(cwd); - if (IS_ERR(cwd)) - goto out; + cwd = __d_path(pwd, pwdmnt, root, rootmnt, page, PAGE_SIZE, 1); + error = PTR_ERR(cwd); + if (IS_ERR(cwd)) + goto out; - error = -ERANGE; - len = PAGE_SIZE + page - cwd; - if (len <= size) { - error = len; - if (copy_to_user(buf, cwd, len)) - error = -EFAULT; - } - } else - spin_unlock(&dcache_lock); + error = -ERANGE; + len = PAGE_SIZE + page - cwd; + if (len <= size) { + error = len; + if (copy_to_user(buf, cwd, len)) + error = -EFAULT; + } out: dput(pwd); diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c index bf3901ab174..8d130cc8532 100644 --- a/fs/debugfs/file.c +++ b/fs/debugfs/file.c @@ -254,7 +254,7 @@ static ssize_t read_file_blob(struct file *file, char __user *user_buf, blob->size); } -static struct file_operations fops_blob = { +static const struct file_operations fops_blob = { .read = read_file_blob, .open = default_open, }; diff --git a/fs/devpts/inode.c b/fs/devpts/inode.c index 5f7b5a6025b..643e57b622b 100644 --- a/fs/devpts/inode.c +++ b/fs/devpts/inode.c @@ -91,7 +91,7 @@ static int devpts_remount(struct super_block *sb, int *flags, char *data) return 0; } -static struct super_operations devpts_sops = { +static const struct super_operations devpts_sops = { .statfs = simple_statfs, .remount_fs = devpts_remount, }; diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c index ca94a837a5b..61ba670b9e0 100644 --- a/fs/dlm/debug_fs.c +++ b/fs/dlm/debug_fs.c @@ -287,7 +287,7 @@ static int rsb_open(struct inode *inode, struct file *file) return 0; } -static struct file_operations rsb_fops = { +static const struct file_operations rsb_fops = { .owner = THIS_MODULE, .open = rsb_open, .read = seq_read, @@ -331,7 +331,7 @@ static ssize_t waiters_read(struct file *file, char __user *userbuf, return rv; } -static struct file_operations waiters_fops = { +static const struct file_operations waiters_fops = { .owner = THIS_MODULE, .open = waiters_open, .read = waiters_read diff --git a/fs/dlm/lowcomms-tcp.c b/fs/dlm/lowcomms-tcp.c index f1efd17b261..07e0a122c32 100644 --- a/fs/dlm/lowcomms-tcp.c +++ b/fs/dlm/lowcomms-tcp.c @@ -268,12 +268,12 @@ static void close_connection(struct connection *con, bool and_other) static int receive_from_sock(struct connection *con) { int ret = 0; - struct msghdr msg; - struct iovec iov[2]; - mm_segment_t fs; + struct msghdr msg = {}; + struct kvec iov[2]; unsigned len; int r; int call_again_soon = 0; + int nvec; mutex_lock(&con->sock_mutex); @@ -293,21 +293,13 @@ static int receive_from_sock(struct connection *con) cbuf_init(&con->cb, PAGE_CACHE_SIZE); } - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_iovlen = 1; - msg.msg_iov = iov; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_flags = 0; - /* * iov[0] is the bit of the circular buffer between the current end * point (cb.base + cb.len) and the end of the buffer. */ iov[0].iov_len = con->cb.base - cbuf_data(&con->cb); iov[0].iov_base = page_address(con->rx_page) + cbuf_data(&con->cb); - iov[1].iov_len = 0; + nvec = 1; /* * iov[1] is the bit of the circular buffer between the start of the @@ -317,15 +309,12 @@ static int receive_from_sock(struct connection *con) iov[0].iov_len = PAGE_CACHE_SIZE - cbuf_data(&con->cb); iov[1].iov_len = con->cb.base; iov[1].iov_base = page_address(con->rx_page); - msg.msg_iovlen = 2; + nvec = 2; } len = iov[0].iov_len + iov[1].iov_len; - fs = get_fs(); - set_fs(get_ds()); - r = ret = sock_recvmsg(con->sock, &msg, len, + r = ret = kernel_recvmsg(con->sock, &msg, iov, nvec, len, MSG_DONTWAIT | MSG_NOSIGNAL); - set_fs(fs); if (ret <= 0) goto out_close; diff --git a/fs/dlm/memory.c b/fs/dlm/memory.c index 5352b03ff5a..f858fef6e41 100644 --- a/fs/dlm/memory.c +++ b/fs/dlm/memory.c @@ -76,9 +76,7 @@ struct dlm_lkb *allocate_lkb(struct dlm_ls *ls) { struct dlm_lkb *lkb; - lkb = kmem_cache_alloc(lkb_cache, GFP_KERNEL); - if (lkb) - memset(lkb, 0, sizeof(*lkb)); + lkb = kmem_cache_zalloc(lkb_cache, GFP_KERNEL); return lkb; } diff --git a/fs/dlm/user.c b/fs/dlm/user.c index d378b7fe2a1..40db61dc95f 100644 --- a/fs/dlm/user.c +++ b/fs/dlm/user.c @@ -25,7 +25,7 @@ static const char *name_prefix="dlm"; static struct miscdevice ctl_device; -static struct file_operations device_fops; +static const struct file_operations device_fops; #ifdef CONFIG_COMPAT @@ -759,7 +759,7 @@ static int ctl_device_close(struct inode *inode, struct file *file) return 0; } -static struct file_operations device_fops = { +static const struct file_operations device_fops = { .open = device_open, .release = device_close, .read = device_read, @@ -768,7 +768,7 @@ static struct file_operations device_fops = { .owner = THIS_MODULE, }; -static struct file_operations ctl_device_fops = { +static const struct file_operations ctl_device_fops = { .open = ctl_device_open, .release = ctl_device_close, .write = device_write, diff --git a/fs/dquot.c b/fs/dquot.c index 0952cc474d9..9eb166f9148 100644 --- a/fs/dquot.c +++ b/fs/dquot.c @@ -79,6 +79,7 @@ #include <linux/buffer_head.h> #include <linux/capability.h> #include <linux/quotaops.h> +#include <linux/writeback.h> /* for inode_lock, oddly enough.. */ #include <asm/uaccess.h> @@ -600,11 +601,10 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type) { struct dquot *dquot; - dquot = kmem_cache_alloc(dquot_cachep, GFP_NOFS); + dquot = kmem_cache_zalloc(dquot_cachep, GFP_NOFS); if(!dquot) return NODQUOT; - memset((caddr_t)dquot, 0, sizeof(struct dquot)); mutex_init(&dquot->dq_lock); INIT_LIST_HEAD(&dquot->dq_free); INIT_LIST_HEAD(&dquot->dq_inuse); @@ -688,23 +688,27 @@ static int dqinit_needed(struct inode *inode, int type) /* This routine is guarded by dqonoff_mutex mutex */ static void add_dquot_ref(struct super_block *sb, int type) { - struct list_head *p; + struct inode *inode; restart: - file_list_lock(); - list_for_each(p, &sb->s_files) { - struct file *filp = list_entry(p, struct file, f_u.fu_list); - struct inode *inode = filp->f_path.dentry->d_inode; - if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) { - struct dentry *dentry = dget(filp->f_path.dentry); - file_list_unlock(); - sb->dq_op->initialize(inode, type); - dput(dentry); - /* As we may have blocked we had better restart... */ - goto restart; - } + spin_lock(&inode_lock); + list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { + if (!atomic_read(&inode->i_writecount)) + continue; + if (!dqinit_needed(inode, type)) + continue; + if (inode->i_state & (I_FREEING|I_WILL_FREE)) + continue; + + __iget(inode); + spin_unlock(&inode_lock); + + sb->dq_op->initialize(inode, type); + iput(inode); + /* As we may have blocked we had better restart... */ + goto restart; } - file_list_unlock(); + spin_unlock(&inode_lock); } /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */ @@ -756,15 +760,30 @@ static void put_dquot_list(struct list_head *tofree_head) } } +static void remove_dquot_ref(struct super_block *sb, int type, + struct list_head *tofree_head) +{ + struct inode *inode; + + spin_lock(&inode_lock); + list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { + if (!IS_NOQUOTA(inode)) + remove_inode_dquot_ref(inode, type, tofree_head); + } + spin_unlock(&inode_lock); +} + /* Gather all references from inodes and drop them */ static void drop_dquot_ref(struct super_block *sb, int type) { LIST_HEAD(tofree_head); - down_write(&sb_dqopt(sb)->dqptr_sem); - remove_dquot_ref(sb, type, &tofree_head); - up_write(&sb_dqopt(sb)->dqptr_sem); - put_dquot_list(&tofree_head); + if (sb->dq_op) { + down_write(&sb_dqopt(sb)->dqptr_sem); + remove_dquot_ref(sb, type, &tofree_head); + up_write(&sb_dqopt(sb)->dqptr_sem); + put_dquot_list(&tofree_head); + } } static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number) diff --git a/fs/drop_caches.c b/fs/drop_caches.c index 4e4762389bd..03ea7696fe3 100644 --- a/fs/drop_caches.c +++ b/fs/drop_caches.c @@ -20,7 +20,7 @@ static void drop_pagecache_sb(struct super_block *sb) list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { if (inode->i_state & (I_FREEING|I_WILL_FREE)) continue; - invalidate_inode_pages(inode->i_mapping); + invalidate_mapping_pages(inode->i_mapping, 0, -1); } spin_unlock(&inode_lock); } diff --git a/fs/ecryptfs/Makefile b/fs/ecryptfs/Makefile index ca6562451ee..1f1107237ea 100644 --- a/fs/ecryptfs/Makefile +++ b/fs/ecryptfs/Makefile @@ -4,4 +4,4 @@ obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o -ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o crypto.o keystore.o debug.o +ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o crypto.o keystore.o messaging.o netlink.o debug.o diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c index 7196f50fe15..6ac630625b7 100644 --- a/fs/ecryptfs/crypto.c +++ b/fs/ecryptfs/crypto.c @@ -3,7 +3,7 @@ * * Copyright (C) 1997-2004 Erez Zadok * Copyright (C) 2001-2004 Stony Brook University - * Copyright (C) 2004-2006 International Business Machines Corp. + * Copyright (C) 2004-2007 International Business Machines Corp. * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> * Michael C. Thompson <mcthomps@us.ibm.com> * @@ -207,7 +207,7 @@ ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat) mutex_init(&crypt_stat->cs_mutex); mutex_init(&crypt_stat->cs_tfm_mutex); mutex_init(&crypt_stat->cs_hash_tfm_mutex); - ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_STRUCT_INITIALIZED); + crypt_stat->flags |= ECRYPTFS_STRUCT_INITIALIZED; } /** @@ -305,8 +305,7 @@ static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat, int rc = 0; BUG_ON(!crypt_stat || !crypt_stat->tfm - || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags, - ECRYPTFS_STRUCT_INITIALIZED)); + || !(crypt_stat->flags & ECRYPTFS_STRUCT_INITIALIZED)); if (unlikely(ecryptfs_verbosity > 0)) { ecryptfs_printk(KERN_DEBUG, "Key size [%d]; key:\n", crypt_stat->key_size); @@ -429,10 +428,10 @@ static int ecryptfs_read_in_page(struct ecryptfs_page_crypt_context *ctx, goto out; } } else { - rc = ecryptfs_grab_and_map_lower_page(lower_page, NULL, - lower_inode, - lower_page_idx); - if (rc) { + *lower_page = grab_cache_page(lower_inode->i_mapping, + lower_page_idx); + if (!(*lower_page)) { + rc = -EINVAL; ecryptfs_printk( KERN_ERR, "Error attempting to grab and map " "lower page with index [0x%.16x]; rc = [%d]\n", @@ -485,7 +484,7 @@ int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx) lower_inode = ecryptfs_inode_to_lower(ctx->page->mapping->host); inode_info = ecryptfs_inode_to_private(ctx->page->mapping->host); crypt_stat = &inode_info->crypt_stat; - if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)) { + if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { rc = ecryptfs_copy_page_to_lower(ctx->page, lower_inode, ctx->param.lower_file); if (rc) @@ -617,7 +616,7 @@ int ecryptfs_decrypt_page(struct file *file, struct page *page) crypt_stat = &(ecryptfs_inode_to_private( page->mapping->host)->crypt_stat); lower_inode = ecryptfs_inode_to_lower(page->mapping->host); - if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED)) { + if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { rc = ecryptfs_do_readpage(file, page, page->index); if (rc) ecryptfs_printk(KERN_ERR, "Error attempting to copy " @@ -828,9 +827,7 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat) mutex_unlock(&crypt_stat->cs_tfm_mutex); goto out; } - crypto_blkcipher_set_flags(crypt_stat->tfm, - (ECRYPTFS_DEFAULT_CHAINING_MODE - | CRYPTO_TFM_REQ_WEAK_KEY)); + crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY); mutex_unlock(&crypt_stat->cs_tfm_mutex); rc = 0; out: @@ -865,7 +862,10 @@ void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat) ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE; } else crypt_stat->header_extent_size = PAGE_CACHE_SIZE; - crypt_stat->num_header_extents_at_front = 1; + if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) + crypt_stat->num_header_extents_at_front = 0; + else + crypt_stat->num_header_extents_at_front = 1; } /** @@ -881,7 +881,7 @@ int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat) BUG_ON(crypt_stat->iv_bytes > MD5_DIGEST_SIZE); BUG_ON(crypt_stat->iv_bytes <= 0); - if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID)) { + if (!(crypt_stat->flags & ECRYPTFS_KEY_VALID)) { rc = -EINVAL; ecryptfs_printk(KERN_WARNING, "Session key not valid; " "cannot generate root IV\n"); @@ -898,8 +898,7 @@ int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat) out: if (rc) { memset(crypt_stat->root_iv, 0, crypt_stat->iv_bytes); - ECRYPTFS_SET_FLAG(crypt_stat->flags, - ECRYPTFS_SECURITY_WARNING); + crypt_stat->flags |= ECRYPTFS_SECURITY_WARNING; } return rc; } @@ -907,7 +906,7 @@ out: static void ecryptfs_generate_new_key(struct ecryptfs_crypt_stat *crypt_stat) { get_random_bytes(crypt_stat->key, crypt_stat->key_size); - ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID); + crypt_stat->flags |= ECRYPTFS_KEY_VALID; ecryptfs_compute_root_iv(crypt_stat); if (unlikely(ecryptfs_verbosity > 0)) { ecryptfs_printk(KERN_DEBUG, "Generated new session key:\n"); @@ -917,6 +916,22 @@ static void ecryptfs_generate_new_key(struct ecryptfs_crypt_stat *crypt_stat) } /** + * ecryptfs_copy_mount_wide_flags_to_inode_flags + * + * This function propagates the mount-wide flags to individual inode + * flags. + */ +static void ecryptfs_copy_mount_wide_flags_to_inode_flags( + struct ecryptfs_crypt_stat *crypt_stat, + struct ecryptfs_mount_crypt_stat *mount_crypt_stat) +{ + if (mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED) + crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; + if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) + crypt_stat->flags |= ECRYPTFS_VIEW_AS_ENCRYPTED; +} + +/** * ecryptfs_set_default_crypt_stat_vals * @crypt_stat * @@ -926,10 +941,12 @@ static void ecryptfs_set_default_crypt_stat_vals( struct ecryptfs_crypt_stat *crypt_stat, struct ecryptfs_mount_crypt_stat *mount_crypt_stat) { + ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat, + mount_crypt_stat); ecryptfs_set_default_sizes(crypt_stat); strcpy(crypt_stat->cipher, ECRYPTFS_DEFAULT_CIPHER); crypt_stat->key_size = ECRYPTFS_DEFAULT_KEY_BYTES; - ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID); + crypt_stat->flags &= ~(ECRYPTFS_KEY_VALID); crypt_stat->file_version = ECRYPTFS_FILE_VERSION; crypt_stat->mount_crypt_stat = mount_crypt_stat; } @@ -969,8 +986,10 @@ int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry) if (mount_crypt_stat->global_auth_tok) { ecryptfs_printk(KERN_DEBUG, "Initializing context for new " "file using mount_crypt_stat\n"); - ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); - ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID); + crypt_stat->flags |= ECRYPTFS_ENCRYPTED; + crypt_stat->flags |= ECRYPTFS_KEY_VALID; + ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat, + mount_crypt_stat); memcpy(crypt_stat->keysigs[crypt_stat->num_keysigs++], mount_crypt_stat->global_auth_tok_sig, ECRYPTFS_SIG_SIZE_HEX); @@ -1003,7 +1022,7 @@ int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry) * * Returns one if marker found; zero if not found */ -int contains_ecryptfs_marker(char *data) +static int contains_ecryptfs_marker(char *data) { u32 m_1, m_2; @@ -1029,7 +1048,8 @@ struct ecryptfs_flag_map_elem { /* Add support for additional flags by adding elements here. */ static struct ecryptfs_flag_map_elem ecryptfs_flag_map[] = { {0x00000001, ECRYPTFS_ENABLE_HMAC}, - {0x00000002, ECRYPTFS_ENCRYPTED} + {0x00000002, ECRYPTFS_ENCRYPTED}, + {0x00000004, ECRYPTFS_METADATA_IN_XATTR} }; /** @@ -1052,11 +1072,9 @@ static int ecryptfs_process_flags(struct ecryptfs_crypt_stat *crypt_stat, for (i = 0; i < ((sizeof(ecryptfs_flag_map) / sizeof(struct ecryptfs_flag_map_elem))); i++) if (flags & ecryptfs_flag_map[i].file_flag) { - ECRYPTFS_SET_FLAG(crypt_stat->flags, - ecryptfs_flag_map[i].local_flag); + crypt_stat->flags |= ecryptfs_flag_map[i].local_flag; } else - ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, - ecryptfs_flag_map[i].local_flag); + crypt_stat->flags &= ~(ecryptfs_flag_map[i].local_flag); /* Version is in top 8 bits of the 32-bit flag vector */ crypt_stat->file_version = ((flags >> 24) & 0xFF); (*bytes_read) = 4; @@ -1093,8 +1111,7 @@ write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat, for (i = 0; i < ((sizeof(ecryptfs_flag_map) / sizeof(struct ecryptfs_flag_map_elem))); i++) - if (ECRYPTFS_CHECK_FLAG(crypt_stat->flags, - ecryptfs_flag_map[i].local_flag)) + if (crypt_stat->flags & ecryptfs_flag_map[i].local_flag) flags |= ecryptfs_flag_map[i].file_flag; /* Version is in top 8 bits of the 32-bit flag vector */ flags |= ((((u8)crypt_stat->file_version) << 24) & 0xFF000000); @@ -1189,8 +1206,8 @@ int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code) * * Returns zero on success; non-zero otherwise */ -int ecryptfs_read_header_region(char *data, struct dentry *dentry, - struct vfsmount *mnt) +static int ecryptfs_read_header_region(char *data, struct dentry *dentry, + struct vfsmount *mnt) { struct file *lower_file; mm_segment_t oldfs; @@ -1219,9 +1236,25 @@ out: return rc; } -static void -write_header_metadata(char *virt, struct ecryptfs_crypt_stat *crypt_stat, - size_t *written) +int ecryptfs_read_and_validate_header_region(char *data, struct dentry *dentry, + struct vfsmount *mnt) +{ + int rc; + + rc = ecryptfs_read_header_region(data, dentry, mnt); + if (rc) + goto out; + if (!contains_ecryptfs_marker(data + ECRYPTFS_FILE_SIZE_BYTES)) + rc = -EINVAL; +out: + return rc; +} + + +void +ecryptfs_write_header_metadata(char *virt, + struct ecryptfs_crypt_stat *crypt_stat, + size_t *written) { u32 header_extent_size; u16 num_header_extents_at_front; @@ -1270,9 +1303,9 @@ struct kmem_cache *ecryptfs_header_cache_2; * * Returns zero on success */ -int ecryptfs_write_headers_virt(char *page_virt, - struct ecryptfs_crypt_stat *crypt_stat, - struct dentry *ecryptfs_dentry) +static int ecryptfs_write_headers_virt(char *page_virt, size_t *size, + struct ecryptfs_crypt_stat *crypt_stat, + struct dentry *ecryptfs_dentry) { int rc; size_t written; @@ -1283,7 +1316,8 @@ int ecryptfs_write_headers_virt(char *page_virt, offset += written; write_ecryptfs_flags((page_virt + offset), crypt_stat, &written); offset += written; - write_header_metadata((page_virt + offset), crypt_stat, &written); + ecryptfs_write_header_metadata((page_virt + offset), crypt_stat, + &written); offset += written; rc = ecryptfs_generate_key_packet_set((page_virt + offset), crypt_stat, ecryptfs_dentry, &written, @@ -1291,11 +1325,70 @@ int ecryptfs_write_headers_virt(char *page_virt, if (rc) ecryptfs_printk(KERN_WARNING, "Error generating key packet " "set; rc = [%d]\n", rc); + if (size) { + offset += written; + *size = offset; + } + return rc; +} + +static int ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat, + struct file *lower_file, + char *page_virt) +{ + mm_segment_t oldfs; + int current_header_page; + int header_pages; + ssize_t size; + int rc = 0; + + lower_file->f_pos = 0; + oldfs = get_fs(); + set_fs(get_ds()); + size = vfs_write(lower_file, (char __user *)page_virt, PAGE_CACHE_SIZE, + &lower_file->f_pos); + if (size < 0) { + rc = (int)size; + printk(KERN_ERR "Error attempting to write lower page; " + "rc = [%d]\n", rc); + set_fs(oldfs); + goto out; + } + header_pages = ((crypt_stat->header_extent_size + * crypt_stat->num_header_extents_at_front) + / PAGE_CACHE_SIZE); + memset(page_virt, 0, PAGE_CACHE_SIZE); + current_header_page = 1; + while (current_header_page < header_pages) { + size = vfs_write(lower_file, (char __user *)page_virt, + PAGE_CACHE_SIZE, &lower_file->f_pos); + if (size < 0) { + rc = (int)size; + printk(KERN_ERR "Error attempting to write lower page; " + "rc = [%d]\n", rc); + set_fs(oldfs); + goto out; + } + current_header_page++; + } + set_fs(oldfs); +out: + return rc; +} + +static int ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry, + struct ecryptfs_crypt_stat *crypt_stat, + char *page_virt, size_t size) +{ + int rc; + + rc = ecryptfs_setxattr(ecryptfs_dentry, ECRYPTFS_XATTR_NAME, page_virt, + size, 0); return rc; } /** - * ecryptfs_write_headers + * ecryptfs_write_metadata * @lower_file: The lower file struct, which was returned from dentry_open * * Write the file headers out. This will likely involve a userspace @@ -1306,22 +1399,18 @@ int ecryptfs_write_headers_virt(char *page_virt, * * Returns zero on success; non-zero on error */ -int ecryptfs_write_headers(struct dentry *ecryptfs_dentry, - struct file *lower_file) +int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry, + struct file *lower_file) { - mm_segment_t oldfs; struct ecryptfs_crypt_stat *crypt_stat; char *page_virt; - int current_header_page; - int header_pages; + size_t size; int rc = 0; crypt_stat = &ecryptfs_inode_to_private( ecryptfs_dentry->d_inode)->crypt_stat; - if (likely(ECRYPTFS_CHECK_FLAG(crypt_stat->flags, - ECRYPTFS_ENCRYPTED))) { - if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, - ECRYPTFS_KEY_VALID)) { + if (likely(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { + if (!(crypt_stat->flags & ECRYPTFS_KEY_VALID)) { ecryptfs_printk(KERN_DEBUG, "Key is " "invalid; bailing out\n"); rc = -EINVAL; @@ -1334,54 +1423,42 @@ int ecryptfs_write_headers(struct dentry *ecryptfs_dentry, goto out; } /* Released in this function */ - page_virt = kmem_cache_alloc(ecryptfs_header_cache_0, GFP_USER); + page_virt = kmem_cache_zalloc(ecryptfs_header_cache_0, GFP_USER); if (!page_virt) { ecryptfs_printk(KERN_ERR, "Out of memory\n"); rc = -ENOMEM; goto out; } - memset(page_virt, 0, PAGE_CACHE_SIZE); - rc = ecryptfs_write_headers_virt(page_virt, crypt_stat, - ecryptfs_dentry); + rc = ecryptfs_write_headers_virt(page_virt, &size, crypt_stat, + ecryptfs_dentry); if (unlikely(rc)) { ecryptfs_printk(KERN_ERR, "Error whilst writing headers\n"); memset(page_virt, 0, PAGE_CACHE_SIZE); goto out_free; } - ecryptfs_printk(KERN_DEBUG, - "Writing key packet set to underlying file\n"); - lower_file->f_pos = 0; - oldfs = get_fs(); - set_fs(get_ds()); - ecryptfs_printk(KERN_DEBUG, "Calling lower_file->f_op->" - "write() w/ header page; lower_file->f_pos = " - "[0x%.16x]\n", lower_file->f_pos); - lower_file->f_op->write(lower_file, (char __user *)page_virt, - PAGE_CACHE_SIZE, &lower_file->f_pos); - header_pages = ((crypt_stat->header_extent_size - * crypt_stat->num_header_extents_at_front) - / PAGE_CACHE_SIZE); - memset(page_virt, 0, PAGE_CACHE_SIZE); - current_header_page = 1; - while (current_header_page < header_pages) { - ecryptfs_printk(KERN_DEBUG, "Calling lower_file->f_op->" - "write() w/ zero'd page; lower_file->f_pos = " - "[0x%.16x]\n", lower_file->f_pos); - lower_file->f_op->write(lower_file, (char __user *)page_virt, - PAGE_CACHE_SIZE, &lower_file->f_pos); - current_header_page++; + if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) + rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, + crypt_stat, page_virt, + size); + else + rc = ecryptfs_write_metadata_to_contents(crypt_stat, lower_file, + page_virt); + if (rc) { + printk(KERN_ERR "Error writing metadata out to lower file; " + "rc = [%d]\n", rc); + goto out_free; } - set_fs(oldfs); - ecryptfs_printk(KERN_DEBUG, - "Done writing key packet set to underlying file.\n"); out_free: kmem_cache_free(ecryptfs_header_cache_0, page_virt); out: return rc; } +#define ECRYPTFS_DONT_VALIDATE_HEADER_SIZE 0 +#define ECRYPTFS_VALIDATE_HEADER_SIZE 1 static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat, - char *virt, int *bytes_read) + char *virt, int *bytes_read, + int validate_header_size) { int rc = 0; u32 header_extent_size; @@ -1396,9 +1473,10 @@ static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat, crypt_stat->num_header_extents_at_front = (int)num_header_extents_at_front; (*bytes_read) = 6; - if ((crypt_stat->header_extent_size - * crypt_stat->num_header_extents_at_front) - < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) { + if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE) + && ((crypt_stat->header_extent_size + * crypt_stat->num_header_extents_at_front) + < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) { rc = -EINVAL; ecryptfs_printk(KERN_WARNING, "Invalid header extent size: " "[%d]\n", crypt_stat->header_extent_size); @@ -1429,7 +1507,8 @@ static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat) */ static int ecryptfs_read_headers_virt(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat, - struct dentry *ecryptfs_dentry) + struct dentry *ecryptfs_dentry, + int validate_header_size) { int rc = 0; int offset; @@ -1463,7 +1542,7 @@ static int ecryptfs_read_headers_virt(char *page_virt, offset += bytes_read; if (crypt_stat->file_version >= 1) { rc = parse_header_metadata(crypt_stat, (page_virt + offset), - &bytes_read); + &bytes_read, validate_header_size); if (rc) { ecryptfs_printk(KERN_WARNING, "Error reading header " "metadata; rc = [%d]\n", rc); @@ -1478,12 +1557,60 @@ out: } /** - * ecryptfs_read_headers + * ecryptfs_read_xattr_region + * + * Attempts to read the crypto metadata from the extended attribute + * region of the lower file. + */ +int ecryptfs_read_xattr_region(char *page_virt, struct dentry *ecryptfs_dentry) +{ + ssize_t size; + int rc = 0; + + size = ecryptfs_getxattr(ecryptfs_dentry, ECRYPTFS_XATTR_NAME, + page_virt, ECRYPTFS_DEFAULT_EXTENT_SIZE); + if (size < 0) { + printk(KERN_DEBUG "Error attempting to read the [%s] " + "xattr from the lower file; return value = [%zd]\n", + ECRYPTFS_XATTR_NAME, size); + rc = -EINVAL; + goto out; + } +out: + return rc; +} + +int ecryptfs_read_and_validate_xattr_region(char *page_virt, + struct dentry *ecryptfs_dentry) +{ + int rc; + + rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_dentry); + if (rc) + goto out; + if (!contains_ecryptfs_marker(page_virt + ECRYPTFS_FILE_SIZE_BYTES)) { + printk(KERN_WARNING "Valid data found in [%s] xattr, but " + "the marker is invalid\n", ECRYPTFS_XATTR_NAME); + rc = -EINVAL; + } +out: + return rc; +} + +/** + * ecryptfs_read_metadata + * + * Common entry point for reading file metadata. From here, we could + * retrieve the header information from the header region of the file, + * the xattr region of the file, or some other repostory that is + * stored separately from the file itself. The current implementation + * supports retrieving the metadata information from the file contents + * and from the xattr region. * * Returns zero if valid headers found and parsed; non-zero otherwise */ -int ecryptfs_read_headers(struct dentry *ecryptfs_dentry, - struct file *lower_file) +int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry, + struct file *lower_file) { int rc = 0; char *page_virt = NULL; @@ -1491,7 +1618,12 @@ int ecryptfs_read_headers(struct dentry *ecryptfs_dentry, ssize_t bytes_read; struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat = + &ecryptfs_superblock_to_private( + ecryptfs_dentry->d_sb)->mount_crypt_stat; + ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat, + mount_crypt_stat); /* Read the first page from the underlying file */ page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, GFP_USER); if (!page_virt) { @@ -1512,11 +1644,36 @@ int ecryptfs_read_headers(struct dentry *ecryptfs_dentry, goto out; } rc = ecryptfs_read_headers_virt(page_virt, crypt_stat, - ecryptfs_dentry); + ecryptfs_dentry, + ECRYPTFS_VALIDATE_HEADER_SIZE); if (rc) { - ecryptfs_printk(KERN_DEBUG, "Valid eCryptfs headers not " - "found\n"); - rc = -EINVAL; + rc = ecryptfs_read_xattr_region(page_virt, + ecryptfs_dentry); + if (rc) { + printk(KERN_DEBUG "Valid eCryptfs headers not found in " + "file header region or xattr region\n"); + rc = -EINVAL; + goto out; + } + rc = ecryptfs_read_headers_virt(page_virt, crypt_stat, + ecryptfs_dentry, + ECRYPTFS_DONT_VALIDATE_HEADER_SIZE); + if (rc) { + printk(KERN_DEBUG "Valid eCryptfs headers not found in " + "file xattr region either\n"); + rc = -EINVAL; + } + if (crypt_stat->mount_crypt_stat->flags + & ECRYPTFS_XATTR_METADATA_ENABLED) { + crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; + } else { + printk(KERN_WARNING "Attempt to access file with " + "crypto metadata only in the extended attribute " + "region, but eCryptfs was mounted without " + "xattr support enabled. eCryptfs will not treat " + "this like an encrypted file.\n"); + rc = -EINVAL; + } } out: if (page_virt) { diff --git a/fs/ecryptfs/debug.c b/fs/ecryptfs/debug.c index 61f8e894284..434c7efd80f 100644 --- a/fs/ecryptfs/debug.c +++ b/fs/ecryptfs/debug.c @@ -36,7 +36,7 @@ void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok) ecryptfs_printk(KERN_DEBUG, "Auth tok at mem loc [%p]:\n", auth_tok); - if (ECRYPTFS_CHECK_FLAG(auth_tok->flags, ECRYPTFS_PRIVATE_KEY)) { + if (auth_tok->flags & ECRYPTFS_PRIVATE_KEY) { ecryptfs_printk(KERN_DEBUG, " * private key type\n"); ecryptfs_printk(KERN_DEBUG, " * (NO PRIVATE KEY SUPPORT " "IN ECRYPTFS VERSION 0.1)\n"); @@ -46,8 +46,8 @@ void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok) ECRYPTFS_SALT_SIZE); salt[ECRYPTFS_SALT_SIZE * 2] = '\0'; ecryptfs_printk(KERN_DEBUG, " * salt = [%s]\n", salt); - if (ECRYPTFS_CHECK_FLAG(auth_tok->token.password.flags, - ECRYPTFS_PERSISTENT_PASSWORD)) { + if (auth_tok->token.password.flags & + ECRYPTFS_PERSISTENT_PASSWORD) { ecryptfs_printk(KERN_DEBUG, " * persistent\n"); } memcpy(sig, auth_tok->token.password.signature, diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h index afb64bdbe6a..b3609b7cdf1 100644 --- a/fs/ecryptfs/ecryptfs_kernel.h +++ b/fs/ecryptfs/ecryptfs_kernel.h @@ -4,8 +4,10 @@ * * Copyright (C) 1997-2003 Erez Zadok * Copyright (C) 2001-2003 Stony Brook University - * Copyright (C) 2004-2006 International Business Machines Corp. + * Copyright (C) 2004-2007 International Business Machines Corp. * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> + * Trevor S. Highland <trevor.highland@gmail.com> + * Tyler Hicks <tyhicks@ou.edu> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -31,22 +33,25 @@ #include <linux/fs_stack.h> #include <linux/namei.h> #include <linux/scatterlist.h> +#include <linux/hash.h> /* Version verification for shared data structures w/ userspace */ #define ECRYPTFS_VERSION_MAJOR 0x00 #define ECRYPTFS_VERSION_MINOR 0x04 -#define ECRYPTFS_SUPPORTED_FILE_VERSION 0x01 +#define ECRYPTFS_SUPPORTED_FILE_VERSION 0x02 /* These flags indicate which features are supported by the kernel * module; userspace tools such as the mount helper read * ECRYPTFS_VERSIONING_MASK from a sysfs handle in order to determine * how to behave. */ -#define ECRYPTFS_VERSIONING_PASSPHRASE 0x00000001 -#define ECRYPTFS_VERSIONING_PUBKEY 0x00000002 +#define ECRYPTFS_VERSIONING_PASSPHRASE 0x00000001 +#define ECRYPTFS_VERSIONING_PUBKEY 0x00000002 #define ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH 0x00000004 -#define ECRYPTFS_VERSIONING_POLICY 0x00000008 +#define ECRYPTFS_VERSIONING_POLICY 0x00000008 +#define ECRYPTFS_VERSIONING_XATTR 0x00000010 #define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \ - | ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH) - + | ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH \ + | ECRYPTFS_VERSIONING_PUBKEY \ + | ECRYPTFS_VERSIONING_XATTR) #define ECRYPTFS_MAX_PASSWORD_LENGTH 64 #define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH #define ECRYPTFS_SALT_SIZE 8 @@ -60,10 +65,25 @@ #define ECRYPTFS_MAX_KEY_BYTES 64 #define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512 #define ECRYPTFS_DEFAULT_IV_BYTES 16 -#define ECRYPTFS_FILE_VERSION 0x01 +#define ECRYPTFS_FILE_VERSION 0x02 #define ECRYPTFS_DEFAULT_HEADER_EXTENT_SIZE 8192 #define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096 #define ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE 8192 +#define ECRYPTFS_DEFAULT_MSG_CTX_ELEMS 32 +#define ECRYPTFS_DEFAULT_SEND_TIMEOUT HZ +#define ECRYPTFS_MAX_MSG_CTX_TTL (HZ*3) +#define ECRYPTFS_NLMSG_HELO 100 +#define ECRYPTFS_NLMSG_QUIT 101 +#define ECRYPTFS_NLMSG_REQUEST 102 +#define ECRYPTFS_NLMSG_RESPONSE 103 +#define ECRYPTFS_MAX_PKI_NAME_BYTES 16 +#define ECRYPTFS_DEFAULT_NUM_USERS 4 +#define ECRYPTFS_MAX_NUM_USERS 32768 +#define ECRYPTFS_TRANSPORT_NETLINK 0 +#define ECRYPTFS_TRANSPORT_CONNECTOR 1 +#define ECRYPTFS_TRANSPORT_RELAYFS 2 +#define ECRYPTFS_DEFAULT_TRANSPORT ECRYPTFS_TRANSPORT_NETLINK +#define ECRYPTFS_XATTR_NAME "user.ecryptfs" #define RFC2440_CIPHER_DES3_EDE 0x02 #define RFC2440_CIPHER_CAST_5 0x03 @@ -74,9 +94,7 @@ #define RFC2440_CIPHER_TWOFISH 0x0a #define RFC2440_CIPHER_CAST_6 0x0b -#define ECRYPTFS_SET_FLAG(flag_bit_vector, flag) (flag_bit_vector |= (flag)) -#define ECRYPTFS_CLEAR_FLAG(flag_bit_vector, flag) (flag_bit_vector &= ~(flag)) -#define ECRYPTFS_CHECK_FLAG(flag_bit_vector, flag) (flag_bit_vector & (flag)) +#define RFC2440_CIPHER_RSA 0x01 /** * For convenience, we may need to pass around the encrypted session @@ -114,6 +132,14 @@ struct ecryptfs_password { enum ecryptfs_token_types {ECRYPTFS_PASSWORD, ECRYPTFS_PRIVATE_KEY}; +struct ecryptfs_private_key { + u32 key_size; + u32 data_len; + u8 signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1]; + char pki_type[ECRYPTFS_MAX_PKI_NAME_BYTES + 1]; + u8 data[]; +}; + /* May be a password or a private key */ struct ecryptfs_auth_tok { u16 version; /* 8-bit major and 8-bit minor */ @@ -123,7 +149,7 @@ struct ecryptfs_auth_tok { u8 reserved[32]; union { struct ecryptfs_password password; - /* Private key is in future eCryptfs releases */ + struct ecryptfs_private_key private_key; } token; } __attribute__ ((packed)); @@ -176,10 +202,14 @@ ecryptfs_get_key_payload_data(struct key *key) #define ECRYPTFS_FILE_SIZE_BYTES 8 #define ECRYPTFS_DEFAULT_CIPHER "aes" #define ECRYPTFS_DEFAULT_KEY_BYTES 16 -#define ECRYPTFS_DEFAULT_CHAINING_MODE CRYPTO_TFM_MODE_CBC #define ECRYPTFS_DEFAULT_HASH "md5" +#define ECRYPTFS_TAG_1_PACKET_TYPE 0x01 #define ECRYPTFS_TAG_3_PACKET_TYPE 0x8C #define ECRYPTFS_TAG_11_PACKET_TYPE 0xED +#define ECRYPTFS_TAG_64_PACKET_TYPE 0x40 +#define ECRYPTFS_TAG_65_PACKET_TYPE 0x41 +#define ECRYPTFS_TAG_66_PACKET_TYPE 0x42 +#define ECRYPTFS_TAG_67_PACKET_TYPE 0x43 #define MD5_DIGEST_SIZE 16 /** @@ -196,6 +226,8 @@ struct ecryptfs_crypt_stat { #define ECRYPTFS_ENABLE_HMAC 0x00000020 #define ECRYPTFS_ENCRYPT_IV_PAGES 0x00000040 #define ECRYPTFS_KEY_VALID 0x00000080 +#define ECRYPTFS_METADATA_IN_XATTR 0x00000100 +#define ECRYPTFS_VIEW_AS_ENCRYPTED 0x00000200 u32 flags; unsigned int file_version; size_t iv_bytes; @@ -242,6 +274,8 @@ struct ecryptfs_dentry_info { struct ecryptfs_mount_crypt_stat { /* Pointers to memory we do not own, do not free these */ #define ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED 0x00000001 +#define ECRYPTFS_XATTR_METADATA_ENABLED 0x00000002 +#define ECRYPTFS_ENCRYPTED_VIEW_ENABLED 0x00000004 u32 flags; struct ecryptfs_auth_tok *global_auth_tok; struct key *global_auth_tok_key; @@ -272,6 +306,33 @@ struct ecryptfs_auth_tok_list_item { struct ecryptfs_auth_tok auth_tok; }; +struct ecryptfs_message { + u32 index; + u32 data_len; + u8 data[]; +}; + +struct ecryptfs_msg_ctx { +#define ECRYPTFS_MSG_CTX_STATE_FREE 0x0001 +#define ECRYPTFS_MSG_CTX_STATE_PENDING 0x0002 +#define ECRYPTFS_MSG_CTX_STATE_DONE 0x0003 + u32 state; + unsigned int index; + unsigned int counter; + struct ecryptfs_message *msg; + struct task_struct *task; + struct list_head node; + struct mutex mux; +}; + +extern unsigned int ecryptfs_transport; + +struct ecryptfs_daemon_id { + pid_t pid; + uid_t uid; + struct hlist_node id_chain; +}; + static inline struct ecryptfs_file_info * ecryptfs_file_to_private(struct file *file) { @@ -385,13 +446,16 @@ void __ecryptfs_printk(const char *fmt, ...); extern const struct file_operations ecryptfs_main_fops; extern const struct file_operations ecryptfs_dir_fops; -extern struct inode_operations ecryptfs_main_iops; -extern struct inode_operations ecryptfs_dir_iops; -extern struct inode_operations ecryptfs_symlink_iops; -extern struct super_operations ecryptfs_sops; +extern const struct inode_operations ecryptfs_main_iops; +extern const struct inode_operations ecryptfs_dir_iops; +extern const struct inode_operations ecryptfs_symlink_iops; +extern const struct super_operations ecryptfs_sops; extern struct dentry_operations ecryptfs_dops; extern struct address_space_operations ecryptfs_aops; extern int ecryptfs_verbosity; +extern unsigned int ecryptfs_message_buf_len; +extern signed long ecryptfs_message_wait_timeout; +extern unsigned int ecryptfs_number_of_users; extern struct kmem_cache *ecryptfs_auth_tok_list_item_cache; extern struct kmem_cache *ecryptfs_file_info_cache; @@ -401,6 +465,7 @@ extern struct kmem_cache *ecryptfs_sb_info_cache; extern struct kmem_cache *ecryptfs_header_cache_0; extern struct kmem_cache *ecryptfs_header_cache_1; extern struct kmem_cache *ecryptfs_header_cache_2; +extern struct kmem_cache *ecryptfs_xattr_cache; extern struct kmem_cache *ecryptfs_lower_page_cache; int ecryptfs_interpose(struct dentry *hidden_dentry, @@ -427,9 +492,13 @@ int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat); int ecryptfs_crypto_api_algify_cipher_name(char **algified_name, char *cipher_name, char *chaining_modifier); -int ecryptfs_write_inode_size_to_header(struct file *lower_file, - struct inode *lower_inode, - struct inode *inode); +#define ECRYPTFS_LOWER_I_MUTEX_NOT_HELD 0 +#define ECRYPTFS_LOWER_I_MUTEX_HELD 1 +int ecryptfs_write_inode_size_to_metadata(struct file *lower_file, + struct inode *lower_inode, + struct inode *inode, + struct dentry *ecryptfs_dentry, + int lower_i_mutex_held); int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, struct file *lower_file, unsigned long lower_page_index, int byte_offset, @@ -442,26 +511,20 @@ int ecryptfs_copy_page_to_lower(struct page *page, struct inode *lower_inode, struct file *lower_file); int ecryptfs_do_readpage(struct file *file, struct page *page, pgoff_t lower_page_index); -int ecryptfs_grab_and_map_lower_page(struct page **lower_page, - char **lower_virt, - struct inode *lower_inode, - unsigned long lower_page_index); int ecryptfs_writepage_and_release_lower_page(struct page *lower_page, struct inode *lower_inode, struct writeback_control *wbc); int ecryptfs_encrypt_page(struct ecryptfs_page_crypt_context *ctx); int ecryptfs_decrypt_page(struct file *file, struct page *page); -int ecryptfs_write_headers(struct dentry *ecryptfs_dentry, +int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry, + struct file *lower_file); +int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry, struct file *lower_file); -int ecryptfs_write_headers_virt(char *page_virt, - struct ecryptfs_crypt_stat *crypt_stat, - struct dentry *ecryptfs_dentry); -int ecryptfs_read_headers(struct dentry *ecryptfs_dentry, - struct file *lower_file); int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry); -int contains_ecryptfs_marker(char *data); -int ecryptfs_read_header_region(char *data, struct dentry *dentry, - struct vfsmount *mnt); +int ecryptfs_read_and_validate_header_region(char *data, struct dentry *dentry, + struct vfsmount *mnt); +int ecryptfs_read_and_validate_xattr_region(char *page_virt, + struct dentry *ecryptfs_dentry); u16 ecryptfs_code_for_cipher_string(struct ecryptfs_crypt_stat *crypt_stat); int ecryptfs_cipher_code_to_string(char *str, u16 cipher_code); void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat); @@ -484,5 +547,37 @@ int ecryptfs_open_lower_file(struct file **lower_file, struct dentry *lower_dentry, struct vfsmount *lower_mnt, int flags); int ecryptfs_close_lower_file(struct file *lower_file); +ssize_t ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value, + size_t size); +int +ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t size, int flags); +int ecryptfs_read_xattr_region(char *page_virt, struct dentry *ecryptfs_dentry); +int ecryptfs_process_helo(unsigned int transport, uid_t uid, pid_t pid); +int ecryptfs_process_quit(uid_t uid, pid_t pid); +int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t uid, + pid_t pid, u32 seq); +int ecryptfs_send_message(unsigned int transport, char *data, int data_len, + struct ecryptfs_msg_ctx **msg_ctx); +int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx, + struct ecryptfs_message **emsg); +int ecryptfs_init_messaging(unsigned int transport); +void ecryptfs_release_messaging(unsigned int transport); + +int ecryptfs_send_netlink(char *data, int data_len, + struct ecryptfs_msg_ctx *msg_ctx, u16 msg_type, + u16 msg_flags, pid_t daemon_pid); +int ecryptfs_init_netlink(void); +void ecryptfs_release_netlink(void); + +int ecryptfs_send_connector(char *data, int data_len, + struct ecryptfs_msg_ctx *msg_ctx, u16 msg_type, + u16 msg_flags, pid_t daemon_pid); +int ecryptfs_init_connector(void); +void ecryptfs_release_connector(void); +void +ecryptfs_write_header_metadata(char *virt, + struct ecryptfs_crypt_stat *crypt_stat, + size_t *written); #endif /* #ifndef ECRYPTFS_KERNEL_H */ diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c index c5a2e5298f1..bd969adf70d 100644 --- a/fs/ecryptfs/file.c +++ b/fs/ecryptfs/file.c @@ -3,7 +3,7 @@ * * Copyright (C) 1997-2004 Erez Zadok * Copyright (C) 2001-2004 Stony Brook University - * Copyright (C) 2004-2006 International Business Machines Corp. + * Copyright (C) 2004-2007 International Business Machines Corp. * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com> * Michael C. Thompson <mcthomps@us.ibm.com> * @@ -250,8 +250,19 @@ static int ecryptfs_open(struct inode *inode, struct file *file) struct ecryptfs_file_info *file_info; int lower_flags; + mount_crypt_stat = &ecryptfs_superblock_to_private( + ecryptfs_dentry->d_sb)->mount_crypt_stat; + if ((mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) + && ((file->f_flags & O_WRONLY) || (file->f_flags & O_RDWR) + || (file->f_flags & O_CREAT) || (file->f_flags & O_TRUNC) + || (file->f_flags & O_APPEND))) { + printk(KERN_WARNING "Mount has encrypted view enabled; " + "files may only be read\n"); + rc = -EPERM; + goto out; + } /* Released in ecryptfs_release or end of function if failure */ - file_info = kmem_cache_alloc(ecryptfs_file_info_cache, GFP_KERNEL); + file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL); ecryptfs_set_file_private(file, file_info); if (!file_info) { ecryptfs_printk(KERN_ERR, @@ -259,17 +270,14 @@ static int ecryptfs_open(struct inode *inode, struct file *file) rc = -ENOMEM; goto out; } - memset(file_info, 0, sizeof(*file_info)); lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; - mount_crypt_stat = &ecryptfs_superblock_to_private( - ecryptfs_dentry->d_sb)->mount_crypt_stat; mutex_lock(&crypt_stat->cs_mutex); - if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED)) { + if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) { ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n"); /* Policy code enabled in future release */ - ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED); - ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); + crypt_stat->flags |= ECRYPTFS_POLICY_APPLIED; + crypt_stat->flags |= ECRYPTFS_ENCRYPTED; } mutex_unlock(&crypt_stat->cs_mutex); lower_flags = file->f_flags; @@ -289,31 +297,14 @@ static int ecryptfs_open(struct inode *inode, struct file *file) lower_inode = lower_dentry->d_inode; if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); - ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); + crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); rc = 0; goto out; } mutex_lock(&crypt_stat->cs_mutex); - if (i_size_read(lower_inode) < ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE) { - if (!(mount_crypt_stat->flags - & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) { - rc = -EIO; - printk(KERN_WARNING "Attempt to read file that is " - "not in a valid eCryptfs format, and plaintext " - "passthrough mode is not enabled; returning " - "-EIO\n"); - mutex_unlock(&crypt_stat->cs_mutex); - goto out_puts; - } - crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); - rc = 0; - mutex_unlock(&crypt_stat->cs_mutex); - goto out; - } else if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, - ECRYPTFS_POLICY_APPLIED) - || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags, - ECRYPTFS_KEY_VALID)) { - rc = ecryptfs_read_headers(ecryptfs_dentry, lower_file); + if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED) + || !(crypt_stat->flags & ECRYPTFS_KEY_VALID)) { + rc = ecryptfs_read_metadata(ecryptfs_dentry, lower_file); if (rc) { ecryptfs_printk(KERN_DEBUG, "Valid headers not found\n"); @@ -327,9 +318,8 @@ static int ecryptfs_open(struct inode *inode, struct file *file) mutex_unlock(&crypt_stat->cs_mutex); goto out_puts; } - ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, - ECRYPTFS_ENCRYPTED); rc = 0; + crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); mutex_unlock(&crypt_stat->cs_mutex); goto out; } diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c index 11f5e5076ae..9fa7e0b27a9 100644 --- a/fs/ecryptfs/inode.c +++ b/fs/ecryptfs/inode.c @@ -3,7 +3,7 @@ * * Copyright (C) 1997-2004 Erez Zadok * Copyright (C) 2001-2004 Stony Brook University - * Copyright (C) 2004-2006 International Business Machines Corp. + * Copyright (C) 2004-2007 International Business Machines Corp. * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> * Michael C. Thompsion <mcthomps@us.ibm.com> * @@ -161,17 +161,17 @@ static int grow_file(struct dentry *ecryptfs_dentry, struct file *lower_file, ecryptfs_set_file_lower(&fake_file, lower_file); rc = ecryptfs_fill_zeros(&fake_file, 1); if (rc) { - ECRYPTFS_SET_FLAG( - ecryptfs_inode_to_private(inode)->crypt_stat.flags, - ECRYPTFS_SECURITY_WARNING); + ecryptfs_inode_to_private(inode)->crypt_stat.flags |= + ECRYPTFS_SECURITY_WARNING; ecryptfs_printk(KERN_WARNING, "Error attempting to fill zeros " "in file; rc = [%d]\n", rc); goto out; } i_size_write(inode, 0); - ecryptfs_write_inode_size_to_header(lower_file, lower_inode, inode); - ECRYPTFS_SET_FLAG(ecryptfs_inode_to_private(inode)->crypt_stat.flags, - ECRYPTFS_NEW_FILE); + ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode, inode, + ecryptfs_dentry, + ECRYPTFS_LOWER_I_MUTEX_NOT_HELD); + ecryptfs_inode_to_private(inode)->crypt_stat.flags |= ECRYPTFS_NEW_FILE; out: return rc; } @@ -199,7 +199,7 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) lower_dentry->d_name.name); inode = ecryptfs_dentry->d_inode; crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; - lower_flags = ((O_CREAT | O_WRONLY | O_TRUNC) & O_ACCMODE) | O_RDWR; + lower_flags = ((O_CREAT | O_TRUNC) & O_ACCMODE) | O_RDWR; #if BITS_PER_LONG != 32 lower_flags |= O_LARGEFILE; #endif @@ -214,10 +214,10 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) lower_inode = lower_dentry->d_inode; if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) { ecryptfs_printk(KERN_DEBUG, "This is a directory\n"); - ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED); + crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED); goto out_fput; } - ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE); + crypt_stat->flags |= ECRYPTFS_NEW_FILE; ecryptfs_printk(KERN_DEBUG, "Initializing crypto context\n"); rc = ecryptfs_new_file_context(ecryptfs_dentry); if (rc) { @@ -225,7 +225,7 @@ static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry) "context\n"); goto out_fput; } - rc = ecryptfs_write_headers(ecryptfs_dentry, lower_file); + rc = ecryptfs_write_metadata(ecryptfs_dentry, lower_file); if (rc) { ecryptfs_printk(KERN_DEBUG, "Error writing headers\n"); goto out_fput; @@ -287,6 +287,7 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, char *encoded_name; unsigned int encoded_namelen; struct ecryptfs_crypt_stat *crypt_stat = NULL; + struct ecryptfs_mount_crypt_stat *mount_crypt_stat; char *page_virt = NULL; struct inode *lower_inode; u64 file_size; @@ -361,34 +362,44 @@ static struct dentry *ecryptfs_lookup(struct inode *dir, struct dentry *dentry, goto out; } /* Released in this function */ - page_virt = - (char *)kmem_cache_alloc(ecryptfs_header_cache_2, - GFP_USER); + page_virt = kmem_cache_zalloc(ecryptfs_header_cache_2, + GFP_USER); if (!page_virt) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, "Cannot ecryptfs_kmalloc a page\n"); goto out_dput; } - memset(page_virt, 0, PAGE_CACHE_SIZE); - rc = ecryptfs_read_header_region(page_virt, lower_dentry, nd->mnt); crypt_stat = &ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat; - if (!ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_POLICY_APPLIED)) + if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) ecryptfs_set_default_sizes(crypt_stat); + rc = ecryptfs_read_and_validate_header_region(page_virt, lower_dentry, + nd->mnt); if (rc) { - rc = 0; - ecryptfs_printk(KERN_WARNING, "Error reading header region;" - " assuming unencrypted\n"); - } else { - if (!contains_ecryptfs_marker(page_virt - + ECRYPTFS_FILE_SIZE_BYTES)) { + rc = ecryptfs_read_and_validate_xattr_region(page_virt, dentry); + if (rc) { + printk(KERN_DEBUG "Valid metadata not found in header " + "region or xattr region; treating file as " + "unencrypted\n"); + rc = 0; kmem_cache_free(ecryptfs_header_cache_2, page_virt); goto out; } + crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR; + } + mount_crypt_stat = &ecryptfs_superblock_to_private( + dentry->d_sb)->mount_crypt_stat; + if (mount_crypt_stat->flags & ECRYPTFS_ENCRYPTED_VIEW_ENABLED) { + if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) + file_size = (crypt_stat->header_extent_size + + i_size_read(lower_dentry->d_inode)); + else + file_size = i_size_read(lower_dentry->d_inode); + } else { memcpy(&file_size, page_virt, sizeof(file_size)); file_size = be64_to_cpu(file_size); - i_size_write(dentry->d_inode, (loff_t)file_size); } + i_size_write(dentry->d_inode, (loff_t)file_size); kmem_cache_free(ecryptfs_header_cache_2, page_virt); goto out; @@ -782,20 +793,26 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length) goto out_fput; } i_size_write(inode, new_length); - rc = ecryptfs_write_inode_size_to_header(lower_file, - lower_dentry->d_inode, - inode); + rc = ecryptfs_write_inode_size_to_metadata( + lower_file, lower_dentry->d_inode, inode, dentry, + ECRYPTFS_LOWER_I_MUTEX_NOT_HELD); if (rc) { - ecryptfs_printk(KERN_ERR, - "Problem with ecryptfs_write" - "_inode_size\n"); + printk(KERN_ERR "Problem with " + "ecryptfs_write_inode_size_to_metadata; " + "rc = [%d]\n", rc); goto out_fput; } } else { /* new_length < i_size_read(inode) */ vmtruncate(inode, new_length); - ecryptfs_write_inode_size_to_header(lower_file, - lower_dentry->d_inode, - inode); + rc = ecryptfs_write_inode_size_to_metadata( + lower_file, lower_dentry->d_inode, inode, dentry, + ECRYPTFS_LOWER_I_MUTEX_NOT_HELD); + if (rc) { + printk(KERN_ERR "Problem with " + "ecryptfs_write_inode_size_to_metadata; " + "rc = [%d]\n", rc); + goto out_fput; + } /* We are reducing the size of the ecryptfs file, and need to * know if we need to reduce the size of the lower file. */ lower_size_before_truncate = @@ -882,7 +899,7 @@ out: return rc; } -static int +int ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value, size_t size, int flags) { @@ -902,7 +919,7 @@ out: return rc; } -static ssize_t +ssize_t ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size) { @@ -972,7 +989,7 @@ int ecryptfs_inode_set(struct inode *inode, void *lower_inode) return 0; } -struct inode_operations ecryptfs_symlink_iops = { +const struct inode_operations ecryptfs_symlink_iops = { .readlink = ecryptfs_readlink, .follow_link = ecryptfs_follow_link, .put_link = ecryptfs_put_link, @@ -984,7 +1001,7 @@ struct inode_operations ecryptfs_symlink_iops = { .removexattr = ecryptfs_removexattr }; -struct inode_operations ecryptfs_dir_iops = { +const struct inode_operations ecryptfs_dir_iops = { .create = ecryptfs_create, .lookup = ecryptfs_lookup, .link = ecryptfs_link, @@ -1002,7 +1019,7 @@ struct inode_operations ecryptfs_dir_iops = { .removexattr = ecryptfs_removexattr }; -struct inode_operations ecryptfs_main_iops = { +const struct inode_operations ecryptfs_main_iops = { .permission = ecryptfs_permission, .setattr = ecryptfs_setattr, .setxattr = ecryptfs_setxattr, diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c index 745c0f1bfbb..c209f67e7a2 100644 --- a/fs/ecryptfs/keystore.c +++ b/fs/ecryptfs/keystore.c @@ -7,6 +7,7 @@ * Copyright (C) 2004-2006 International Business Machines Corp. * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com> * Michael C. Thompson <mcthomps@us.ibm.com> + * Trevor S. Highland <trevor.highland@gmail.com> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -64,26 +65,6 @@ int process_request_key_err(long err_code) return rc; } -static void wipe_auth_tok_list(struct list_head *auth_tok_list_head) -{ - struct list_head *walker; - struct ecryptfs_auth_tok_list_item *auth_tok_list_item; - - walker = auth_tok_list_head->next; - while (walker != auth_tok_list_head) { - auth_tok_list_item = - list_entry(walker, struct ecryptfs_auth_tok_list_item, - list); - walker = auth_tok_list_item->list.next; - memset(auth_tok_list_item, 0, - sizeof(struct ecryptfs_auth_tok_list_item)); - kmem_cache_free(ecryptfs_auth_tok_list_item_cache, - auth_tok_list_item); - } -} - -struct kmem_cache *ecryptfs_auth_tok_list_item_cache; - /** * parse_packet_length * @data: Pointer to memory containing length at offset @@ -102,12 +83,12 @@ static int parse_packet_length(unsigned char *data, size_t *size, (*size) = 0; if (data[0] < 192) { /* One-byte length */ - (*size) = data[0]; + (*size) = (unsigned char)data[0]; (*length_size) = 1; } else if (data[0] < 224) { /* Two-byte length */ - (*size) = ((data[0] - 192) * 256); - (*size) += (data[1] + 192); + (*size) = (((unsigned char)(data[0]) - 192) * 256); + (*size) += ((unsigned char)(data[1]) + 192); (*length_size) = 2; } else if (data[0] == 255) { /* Five-byte length; we're not supposed to see this */ @@ -154,6 +135,499 @@ static int write_packet_length(char *dest, size_t size, return rc; } +static int +write_tag_64_packet(char *signature, struct ecryptfs_session_key *session_key, + char **packet, size_t *packet_len) +{ + size_t i = 0; + size_t data_len; + size_t packet_size_len; + char *message; + int rc; + + /* + * ***** TAG 64 Packet Format ***** + * | Content Type | 1 byte | + * | Key Identifier Size | 1 or 2 bytes | + * | Key Identifier | arbitrary | + * | Encrypted File Encryption Key Size | 1 or 2 bytes | + * | Encrypted File Encryption Key | arbitrary | + */ + data_len = (5 + ECRYPTFS_SIG_SIZE_HEX + + session_key->encrypted_key_size); + *packet = kmalloc(data_len, GFP_KERNEL); + message = *packet; + if (!message) { + ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n"); + rc = -ENOMEM; + goto out; + } + message[i++] = ECRYPTFS_TAG_64_PACKET_TYPE; + rc = write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX, + &packet_size_len); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet " + "header; cannot generate packet length\n"); + goto out; + } + i += packet_size_len; + memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX); + i += ECRYPTFS_SIG_SIZE_HEX; + rc = write_packet_length(&message[i], session_key->encrypted_key_size, + &packet_size_len); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet " + "header; cannot generate packet length\n"); + goto out; + } + i += packet_size_len; + memcpy(&message[i], session_key->encrypted_key, + session_key->encrypted_key_size); + i += session_key->encrypted_key_size; + *packet_len = i; +out: + return rc; +} + +static int +parse_tag_65_packet(struct ecryptfs_session_key *session_key, u16 *cipher_code, + struct ecryptfs_message *msg) +{ + size_t i = 0; + char *data; + size_t data_len; + size_t m_size; + size_t message_len; + u16 checksum = 0; + u16 expected_checksum = 0; + int rc; + + /* + * ***** TAG 65 Packet Format ***** + * | Content Type | 1 byte | + * | Status Indicator | 1 byte | + * | File Encryption Key Size | 1 or 2 bytes | + * | File Encryption Key | arbitrary | + */ + message_len = msg->data_len; + data = msg->data; + if (message_len < 4) { + rc = -EIO; + goto out; + } + if (data[i++] != ECRYPTFS_TAG_65_PACKET_TYPE) { + ecryptfs_printk(KERN_ERR, "Type should be ECRYPTFS_TAG_65\n"); + rc = -EIO; + goto out; + } + if (data[i++]) { + ecryptfs_printk(KERN_ERR, "Status indicator has non-zero value " + "[%d]\n", data[i-1]); + rc = -EIO; + goto out; + } + rc = parse_packet_length(&data[i], &m_size, &data_len); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error parsing packet length; " + "rc = [%d]\n", rc); + goto out; + } + i += data_len; + if (message_len < (i + m_size)) { + ecryptfs_printk(KERN_ERR, "The received netlink message is " + "shorter than expected\n"); + rc = -EIO; + goto out; + } + if (m_size < 3) { + ecryptfs_printk(KERN_ERR, + "The decrypted key is not long enough to " + "include a cipher code and checksum\n"); + rc = -EIO; + goto out; + } + *cipher_code = data[i++]; + /* The decrypted key includes 1 byte cipher code and 2 byte checksum */ + session_key->decrypted_key_size = m_size - 3; + if (session_key->decrypted_key_size > ECRYPTFS_MAX_KEY_BYTES) { + ecryptfs_printk(KERN_ERR, "key_size [%d] larger than " + "the maximum key size [%d]\n", + session_key->decrypted_key_size, + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES); + rc = -EIO; + goto out; + } + memcpy(session_key->decrypted_key, &data[i], + session_key->decrypted_key_size); + i += session_key->decrypted_key_size; + expected_checksum += (unsigned char)(data[i++]) << 8; + expected_checksum += (unsigned char)(data[i++]); + for (i = 0; i < session_key->decrypted_key_size; i++) + checksum += session_key->decrypted_key[i]; + if (expected_checksum != checksum) { + ecryptfs_printk(KERN_ERR, "Invalid checksum for file " + "encryption key; expected [%x]; calculated " + "[%x]\n", expected_checksum, checksum); + rc = -EIO; + } +out: + return rc; +} + + +static int +write_tag_66_packet(char *signature, size_t cipher_code, + struct ecryptfs_crypt_stat *crypt_stat, char **packet, + size_t *packet_len) +{ + size_t i = 0; + size_t j; + size_t data_len; + size_t checksum = 0; + size_t packet_size_len; + char *message; + int rc; + + /* + * ***** TAG 66 Packet Format ***** + * | Content Type | 1 byte | + * | Key Identifier Size | 1 or 2 bytes | + * | Key Identifier | arbitrary | + * | File Encryption Key Size | 1 or 2 bytes | + * | File Encryption Key | arbitrary | + */ + data_len = (5 + ECRYPTFS_SIG_SIZE_HEX + crypt_stat->key_size); + *packet = kmalloc(data_len, GFP_KERNEL); + message = *packet; + if (!message) { + ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n"); + rc = -ENOMEM; + goto out; + } + message[i++] = ECRYPTFS_TAG_66_PACKET_TYPE; + rc = write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX, + &packet_size_len); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet " + "header; cannot generate packet length\n"); + goto out; + } + i += packet_size_len; + memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX); + i += ECRYPTFS_SIG_SIZE_HEX; + /* The encrypted key includes 1 byte cipher code and 2 byte checksum */ + rc = write_packet_length(&message[i], crypt_stat->key_size + 3, + &packet_size_len); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet " + "header; cannot generate packet length\n"); + goto out; + } + i += packet_size_len; + message[i++] = cipher_code; + memcpy(&message[i], crypt_stat->key, crypt_stat->key_size); + i += crypt_stat->key_size; + for (j = 0; j < crypt_stat->key_size; j++) + checksum += crypt_stat->key[j]; + message[i++] = (checksum / 256) % 256; + message[i++] = (checksum % 256); + *packet_len = i; +out: + return rc; +} + +static int +parse_tag_67_packet(struct ecryptfs_key_record *key_rec, + struct ecryptfs_message *msg) +{ + size_t i = 0; + char *data; + size_t data_len; + size_t message_len; + int rc; + + /* + * ***** TAG 65 Packet Format ***** + * | Content Type | 1 byte | + * | Status Indicator | 1 byte | + * | Encrypted File Encryption Key Size | 1 or 2 bytes | + * | Encrypted File Encryption Key | arbitrary | + */ + message_len = msg->data_len; + data = msg->data; + /* verify that everything through the encrypted FEK size is present */ + if (message_len < 4) { + rc = -EIO; + goto out; + } + if (data[i++] != ECRYPTFS_TAG_67_PACKET_TYPE) { + ecryptfs_printk(KERN_ERR, "Type should be ECRYPTFS_TAG_67\n"); + rc = -EIO; + goto out; + } + if (data[i++]) { + ecryptfs_printk(KERN_ERR, "Status indicator has non zero value" + " [%d]\n", data[i-1]); + rc = -EIO; + goto out; + } + rc = parse_packet_length(&data[i], &key_rec->enc_key_size, &data_len); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error parsing packet length; " + "rc = [%d]\n", rc); + goto out; + } + i += data_len; + if (message_len < (i + key_rec->enc_key_size)) { + ecryptfs_printk(KERN_ERR, "message_len [%d]; max len is [%d]\n", + message_len, (i + key_rec->enc_key_size)); + rc = -EIO; + goto out; + } + if (key_rec->enc_key_size > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) { + ecryptfs_printk(KERN_ERR, "Encrypted key_size [%d] larger than " + "the maximum key size [%d]\n", + key_rec->enc_key_size, + ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES); + rc = -EIO; + goto out; + } + memcpy(key_rec->enc_key, &data[i], key_rec->enc_key_size); +out: + return rc; +} + +/** + * decrypt_pki_encrypted_session_key - Decrypt the session key with + * the given auth_tok. + * + * Returns Zero on success; non-zero error otherwise. + */ +static int decrypt_pki_encrypted_session_key( + struct ecryptfs_mount_crypt_stat *mount_crypt_stat, + struct ecryptfs_auth_tok *auth_tok, + struct ecryptfs_crypt_stat *crypt_stat) +{ + u16 cipher_code = 0; + struct ecryptfs_msg_ctx *msg_ctx; + struct ecryptfs_message *msg = NULL; + char *netlink_message; + size_t netlink_message_length; + int rc; + + rc = write_tag_64_packet(mount_crypt_stat->global_auth_tok_sig, + &(auth_tok->session_key), + &netlink_message, &netlink_message_length); + if (rc) { + ecryptfs_printk(KERN_ERR, "Failed to write tag 64 packet"); + goto out; + } + rc = ecryptfs_send_message(ecryptfs_transport, netlink_message, + netlink_message_length, &msg_ctx); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error sending netlink message\n"); + goto out; + } + rc = ecryptfs_wait_for_response(msg_ctx, &msg); + if (rc) { + ecryptfs_printk(KERN_ERR, "Failed to receive tag 65 packet " + "from the user space daemon\n"); + rc = -EIO; + goto out; + } + rc = parse_tag_65_packet(&(auth_tok->session_key), + &cipher_code, msg); + if (rc) { + printk(KERN_ERR "Failed to parse tag 65 packet; rc = [%d]\n", + rc); + goto out; + } + auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY; + memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key, + auth_tok->session_key.decrypted_key_size); + crypt_stat->key_size = auth_tok->session_key.decrypted_key_size; + rc = ecryptfs_cipher_code_to_string(crypt_stat->cipher, cipher_code); + if (rc) { + ecryptfs_printk(KERN_ERR, "Cipher code [%d] is invalid\n", + cipher_code) + goto out; + } + crypt_stat->flags |= ECRYPTFS_KEY_VALID; + if (ecryptfs_verbosity > 0) { + ecryptfs_printk(KERN_DEBUG, "Decrypted session key:\n"); + ecryptfs_dump_hex(crypt_stat->key, + crypt_stat->key_size); + } +out: + if (msg) + kfree(msg); + return rc; +} + +static void wipe_auth_tok_list(struct list_head *auth_tok_list_head) +{ + struct list_head *walker; + struct ecryptfs_auth_tok_list_item *auth_tok_list_item; + + walker = auth_tok_list_head->next; + while (walker != auth_tok_list_head) { + auth_tok_list_item = + list_entry(walker, struct ecryptfs_auth_tok_list_item, + list); + walker = auth_tok_list_item->list.next; + memset(auth_tok_list_item, 0, + sizeof(struct ecryptfs_auth_tok_list_item)); + kmem_cache_free(ecryptfs_auth_tok_list_item_cache, + auth_tok_list_item); + } + auth_tok_list_head->next = NULL; +} + +struct kmem_cache *ecryptfs_auth_tok_list_item_cache; + + +/** + * parse_tag_1_packet + * @crypt_stat: The cryptographic context to modify based on packet + * contents. + * @data: The raw bytes of the packet. + * @auth_tok_list: eCryptfs parses packets into authentication tokens; + * a new authentication token will be placed at the end + * of this list for this packet. + * @new_auth_tok: Pointer to a pointer to memory that this function + * allocates; sets the memory address of the pointer to + * NULL on error. This object is added to the + * auth_tok_list. + * @packet_size: This function writes the size of the parsed packet + * into this memory location; zero on error. + * + * Returns zero on success; non-zero on error. + */ +static int +parse_tag_1_packet(struct ecryptfs_crypt_stat *crypt_stat, + unsigned char *data, struct list_head *auth_tok_list, + struct ecryptfs_auth_tok **new_auth_tok, + size_t *packet_size, size_t max_packet_size) +{ + size_t body_size; + struct ecryptfs_auth_tok_list_item *auth_tok_list_item; + size_t length_size; + int rc = 0; + + (*packet_size) = 0; + (*new_auth_tok) = NULL; + + /* we check that: + * one byte for the Tag 1 ID flag + * two bytes for the body size + * do not exceed the maximum_packet_size + */ + if (unlikely((*packet_size) + 3 > max_packet_size)) { + ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n"); + rc = -EINVAL; + goto out; + } + /* check for Tag 1 identifier - one byte */ + if (data[(*packet_size)++] != ECRYPTFS_TAG_1_PACKET_TYPE) { + ecryptfs_printk(KERN_ERR, "Enter w/ first byte != 0x%.2x\n", + ECRYPTFS_TAG_1_PACKET_TYPE); + rc = -EINVAL; + goto out; + } + /* Released: wipe_auth_tok_list called in ecryptfs_parse_packet_set or + * at end of function upon failure */ + auth_tok_list_item = + kmem_cache_alloc(ecryptfs_auth_tok_list_item_cache, + GFP_KERNEL); + if (!auth_tok_list_item) { + ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n"); + rc = -ENOMEM; + goto out; + } + memset(auth_tok_list_item, 0, + sizeof(struct ecryptfs_auth_tok_list_item)); + (*new_auth_tok) = &auth_tok_list_item->auth_tok; + /* check for body size - one to two bytes + * + * ***** TAG 1 Packet Format ***** + * | version number | 1 byte | + * | key ID | 8 bytes | + * | public key algorithm | 1 byte | + * | encrypted session key | arbitrary | + */ + rc = parse_packet_length(&data[(*packet_size)], &body_size, + &length_size); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error parsing packet length; " + "rc = [%d]\n", rc); + goto out_free; + } + if (unlikely(body_size < (0x02 + ECRYPTFS_SIG_SIZE))) { + ecryptfs_printk(KERN_WARNING, "Invalid body size ([%d])\n", + body_size); + rc = -EINVAL; + goto out_free; + } + (*packet_size) += length_size; + if (unlikely((*packet_size) + body_size > max_packet_size)) { + ecryptfs_printk(KERN_ERR, "Packet size exceeds max\n"); + rc = -EINVAL; + goto out_free; + } + /* Version 3 (from RFC2440) - one byte */ + if (unlikely(data[(*packet_size)++] != 0x03)) { + ecryptfs_printk(KERN_DEBUG, "Unknown version number " + "[%d]\n", data[(*packet_size) - 1]); + rc = -EINVAL; + goto out_free; + } + /* Read Signature */ + ecryptfs_to_hex((*new_auth_tok)->token.private_key.signature, + &data[(*packet_size)], ECRYPTFS_SIG_SIZE); + *packet_size += ECRYPTFS_SIG_SIZE; + /* This byte is skipped because the kernel does not need to + * know which public key encryption algorithm was used */ + (*packet_size)++; + (*new_auth_tok)->session_key.encrypted_key_size = + body_size - (0x02 + ECRYPTFS_SIG_SIZE); + if ((*new_auth_tok)->session_key.encrypted_key_size + > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) { + ecryptfs_printk(KERN_ERR, "Tag 1 packet contains key larger " + "than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES"); + rc = -EINVAL; + goto out; + } + ecryptfs_printk(KERN_DEBUG, "Encrypted key size = [%d]\n", + (*new_auth_tok)->session_key.encrypted_key_size); + memcpy((*new_auth_tok)->session_key.encrypted_key, + &data[(*packet_size)], (body_size - 0x02 - ECRYPTFS_SIG_SIZE)); + (*packet_size) += (*new_auth_tok)->session_key.encrypted_key_size; + (*new_auth_tok)->session_key.flags &= + ~ECRYPTFS_CONTAINS_DECRYPTED_KEY; + (*new_auth_tok)->session_key.flags |= + ECRYPTFS_CONTAINS_ENCRYPTED_KEY; + (*new_auth_tok)->token_type = ECRYPTFS_PRIVATE_KEY; + (*new_auth_tok)->flags |= ECRYPTFS_PRIVATE_KEY; + /* TODO: Why are we setting this flag here? Don't we want the + * userspace to decrypt the session key? */ + (*new_auth_tok)->session_key.flags &= + ~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT); + (*new_auth_tok)->session_key.flags &= + ~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT); + list_add(&auth_tok_list_item->list, auth_tok_list); + goto out; +out_free: + (*new_auth_tok) = NULL; + memset(auth_tok_list_item, 0, + sizeof(struct ecryptfs_auth_tok_list_item)); + kmem_cache_free(ecryptfs_auth_tok_list_item_cache, + auth_tok_list_item); +out: + if (rc) + (*packet_size) = 0; + return rc; +} + /** * parse_tag_3_packet * @crypt_stat: The cryptographic context to modify based on packet @@ -178,10 +652,10 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat, struct ecryptfs_auth_tok **new_auth_tok, size_t *packet_size, size_t max_packet_size) { - int rc = 0; size_t body_size; struct ecryptfs_auth_tok_list_item *auth_tok_list_item; size_t length_size; + int rc = 0; (*packet_size) = 0; (*new_auth_tok) = NULL; @@ -207,14 +681,12 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat, /* Released: wipe_auth_tok_list called in ecryptfs_parse_packet_set or * at end of function upon failure */ auth_tok_list_item = - kmem_cache_alloc(ecryptfs_auth_tok_list_item_cache, GFP_KERNEL); + kmem_cache_zalloc(ecryptfs_auth_tok_list_item_cache, GFP_KERNEL); if (!auth_tok_list_item) { ecryptfs_printk(KERN_ERR, "Unable to allocate memory\n"); rc = -ENOMEM; goto out; } - memset(auth_tok_list_item, 0, - sizeof(struct ecryptfs_auth_tok_list_item)); (*new_auth_tok) = &auth_tok_list_item->auth_tok; /* check for body size - one to two bytes */ @@ -321,10 +793,10 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat, (*new_auth_tok)->token_type = ECRYPTFS_PASSWORD; /* TODO: Parametarize; we might actually want userspace to * decrypt the session key. */ - ECRYPTFS_CLEAR_FLAG((*new_auth_tok)->session_key.flags, - ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT); - ECRYPTFS_CLEAR_FLAG((*new_auth_tok)->session_key.flags, - ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT); + (*new_auth_tok)->session_key.flags &= + ~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT); + (*new_auth_tok)->session_key.flags &= + ~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT); list_add(&auth_tok_list_item->list, auth_tok_list); goto out; out_free: @@ -360,9 +832,9 @@ parse_tag_11_packet(unsigned char *data, unsigned char *contents, size_t max_contents_bytes, size_t *tag_11_contents_size, size_t *packet_size, size_t max_packet_size) { - int rc = 0; size_t body_size; size_t length_size; + int rc = 0; (*packet_size) = 0; (*tag_11_contents_size) = 0; @@ -461,7 +933,6 @@ static int decrypt_session_key(struct ecryptfs_auth_tok *auth_tok, struct ecryptfs_password *password_s_ptr; struct scatterlist src_sg[2], dst_sg[2]; struct mutex *tfm_mutex = NULL; - /* TODO: Use virt_to_scatterlist for these */ char *encrypted_session_key; char *session_key; struct blkcipher_desc desc = { @@ -470,8 +941,7 @@ static int decrypt_session_key(struct ecryptfs_auth_tok *auth_tok, int rc = 0; password_s_ptr = &auth_tok->token.password; - if (ECRYPTFS_CHECK_FLAG(password_s_ptr->flags, - ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET)) + if (password_s_ptr->flags & ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET) ecryptfs_printk(KERN_DEBUG, "Session key encryption key " "set; skipping key generation\n"); ecryptfs_printk(KERN_DEBUG, "Session key encryption key (size [%d])" @@ -553,7 +1023,7 @@ static int decrypt_session_key(struct ecryptfs_auth_tok *auth_tok, auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY; memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key, auth_tok->session_key.decrypted_key_size); - ECRYPTFS_SET_FLAG(crypt_stat->flags, ECRYPTFS_KEY_VALID); + crypt_stat->flags |= ECRYPTFS_KEY_VALID; ecryptfs_printk(KERN_DEBUG, "Decrypted session key:\n"); if (ecryptfs_verbosity > 0) ecryptfs_dump_hex(crypt_stat->key, @@ -589,7 +1059,6 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, struct dentry *ecryptfs_dentry) { size_t i = 0; - int rc = 0; size_t found_auth_tok = 0; size_t next_packet_is_auth_tok_packet; char sig[ECRYPTFS_SIG_SIZE_HEX]; @@ -605,6 +1074,7 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, unsigned char sig_tmp_space[ECRYPTFS_SIG_SIZE]; size_t tag_11_contents_size; size_t tag_11_packet_size; + int rc = 0; INIT_LIST_HEAD(&auth_tok_list); /* Parse the header to find as many packets as we can, these will be @@ -656,8 +1126,21 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, sig_tmp_space, tag_11_contents_size); new_auth_tok->token.password.signature[ ECRYPTFS_PASSWORD_SIG_SIZE] = '\0'; - ECRYPTFS_SET_FLAG(crypt_stat->flags, - ECRYPTFS_ENCRYPTED); + crypt_stat->flags |= ECRYPTFS_ENCRYPTED; + break; + case ECRYPTFS_TAG_1_PACKET_TYPE: + rc = parse_tag_1_packet(crypt_stat, + (unsigned char *)&src[i], + &auth_tok_list, &new_auth_tok, + &packet_size, max_packet_size); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error parsing " + "tag 1 packet\n"); + rc = -EIO; + goto out_wipe_list; + } + i += packet_size; + crypt_stat->flags |= ECRYPTFS_ENCRYPTED; break; case ECRYPTFS_TAG_11_PACKET_TYPE: ecryptfs_printk(KERN_WARNING, "Invalid packet set " @@ -706,31 +1189,46 @@ int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat, goto leave_list; /* TODO: Transfer the common salt into the * crypt_stat salt */ + } else if ((candidate_auth_tok->token_type + == ECRYPTFS_PRIVATE_KEY) + && !strncmp(candidate_auth_tok->token.private_key.signature, + sig, ECRYPTFS_SIG_SIZE_HEX)) { + found_auth_tok = 1; + goto leave_list; } } -leave_list: if (!found_auth_tok) { ecryptfs_printk(KERN_ERR, "Could not find authentication " "token on temporary list for sig [%.*s]\n", ECRYPTFS_SIG_SIZE_HEX, sig); rc = -EIO; goto out_wipe_list; - } else { + } +leave_list: + rc = -ENOTSUPP; + if (candidate_auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) { + memcpy(&(candidate_auth_tok->token.private_key), + &(chosen_auth_tok->token.private_key), + sizeof(struct ecryptfs_private_key)); + rc = decrypt_pki_encrypted_session_key(mount_crypt_stat, + candidate_auth_tok, + crypt_stat); + } else if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD) { memcpy(&(candidate_auth_tok->token.password), &(chosen_auth_tok->token.password), sizeof(struct ecryptfs_password)); rc = decrypt_session_key(candidate_auth_tok, crypt_stat); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error decrypting the " - "session key\n"); - goto out_wipe_list; - } - rc = ecryptfs_compute_root_iv(crypt_stat); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error computing " - "the root IV\n"); - goto out_wipe_list; - } + } + if (rc) { + ecryptfs_printk(KERN_ERR, "Error decrypting the " + "session key; rc = [%d]\n", rc); + goto out_wipe_list; + } + rc = ecryptfs_compute_root_iv(crypt_stat); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error computing " + "the root IV\n"); + goto out_wipe_list; } rc = ecryptfs_init_crypt_ctx(crypt_stat); if (rc) { @@ -743,6 +1241,145 @@ out_wipe_list: out: return rc; } +static int +pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok, + struct ecryptfs_crypt_stat *crypt_stat, + struct ecryptfs_key_record *key_rec) +{ + struct ecryptfs_msg_ctx *msg_ctx = NULL; + char *netlink_payload; + size_t netlink_payload_length; + struct ecryptfs_message *msg; + int rc; + + rc = write_tag_66_packet(auth_tok->token.private_key.signature, + ecryptfs_code_for_cipher_string(crypt_stat), + crypt_stat, &netlink_payload, + &netlink_payload_length); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet\n"); + goto out; + } + rc = ecryptfs_send_message(ecryptfs_transport, netlink_payload, + netlink_payload_length, &msg_ctx); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error sending netlink message\n"); + goto out; + } + rc = ecryptfs_wait_for_response(msg_ctx, &msg); + if (rc) { + ecryptfs_printk(KERN_ERR, "Failed to receive tag 67 packet " + "from the user space daemon\n"); + rc = -EIO; + goto out; + } + rc = parse_tag_67_packet(key_rec, msg); + if (rc) + ecryptfs_printk(KERN_ERR, "Error parsing tag 67 packet\n"); + kfree(msg); +out: + if (netlink_payload) + kfree(netlink_payload); + return rc; +} +/** + * write_tag_1_packet - Write an RFC2440-compatible tag 1 (public key) packet + * @dest: Buffer into which to write the packet + * @max: Maximum number of bytes that can be writtn + * @packet_size: This function will write the number of bytes that end + * up constituting the packet; set to zero on error + * + * Returns zero on success; non-zero on error. + */ +static int +write_tag_1_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok, + struct ecryptfs_crypt_stat *crypt_stat, + struct ecryptfs_mount_crypt_stat *mount_crypt_stat, + struct ecryptfs_key_record *key_rec, size_t *packet_size) +{ + size_t i; + size_t encrypted_session_key_valid = 0; + size_t key_rec_size; + size_t packet_size_length; + int rc = 0; + + (*packet_size) = 0; + ecryptfs_from_hex(key_rec->sig, auth_tok->token.private_key.signature, + ECRYPTFS_SIG_SIZE); + encrypted_session_key_valid = 0; + for (i = 0; i < crypt_stat->key_size; i++) + encrypted_session_key_valid |= + auth_tok->session_key.encrypted_key[i]; + if (encrypted_session_key_valid) { + memcpy(key_rec->enc_key, + auth_tok->session_key.encrypted_key, + auth_tok->session_key.encrypted_key_size); + goto encrypted_session_key_set; + } + if (auth_tok->session_key.encrypted_key_size == 0) + auth_tok->session_key.encrypted_key_size = + auth_tok->token.private_key.key_size; + rc = pki_encrypt_session_key(auth_tok, crypt_stat, key_rec); + if (rc) { + ecryptfs_printk(KERN_ERR, "Failed to encrypt session key " + "via a pki"); + goto out; + } + if (ecryptfs_verbosity > 0) { + ecryptfs_printk(KERN_DEBUG, "Encrypted key:\n"); + ecryptfs_dump_hex(key_rec->enc_key, key_rec->enc_key_size); + } +encrypted_session_key_set: + /* Now we have a valid key_rec. Append it to the + * key_rec set. */ + key_rec_size = (sizeof(struct ecryptfs_key_record) + - ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES + + (key_rec->enc_key_size)); + /* TODO: Include a packet size limit as a parameter to this + * function once we have multi-packet headers (for versions + * later than 0.1 */ + if (key_rec_size >= ECRYPTFS_MAX_KEYSET_SIZE) { + ecryptfs_printk(KERN_ERR, "Keyset too large\n"); + rc = -EINVAL; + goto out; + } + /* ***** TAG 1 Packet Format ***** + * | version number | 1 byte | + * | key ID | 8 bytes | + * | public key algorithm | 1 byte | + * | encrypted session key | arbitrary | + */ + if ((0x02 + ECRYPTFS_SIG_SIZE + key_rec->enc_key_size) >= max) { + ecryptfs_printk(KERN_ERR, + "Authentication token is too large\n"); + rc = -EINVAL; + goto out; + } + dest[(*packet_size)++] = ECRYPTFS_TAG_1_PACKET_TYPE; + /* This format is inspired by OpenPGP; see RFC 2440 + * packet tag 1 */ + rc = write_packet_length(&dest[(*packet_size)], + (0x02 + ECRYPTFS_SIG_SIZE + + key_rec->enc_key_size), + &packet_size_length); + if (rc) { + ecryptfs_printk(KERN_ERR, "Error generating tag 1 packet " + "header; cannot generate packet length\n"); + goto out; + } + (*packet_size) += packet_size_length; + dest[(*packet_size)++] = 0x03; /* version 3 */ + memcpy(&dest[(*packet_size)], key_rec->sig, ECRYPTFS_SIG_SIZE); + (*packet_size) += ECRYPTFS_SIG_SIZE; + dest[(*packet_size)++] = RFC2440_CIPHER_RSA; + memcpy(&dest[(*packet_size)], key_rec->enc_key, + key_rec->enc_key_size); + (*packet_size) += key_rec->enc_key_size; +out: + if (rc) + (*packet_size) = 0; + return rc; +} /** * write_tag_11_packet @@ -758,8 +1395,8 @@ static int write_tag_11_packet(char *dest, int max, char *contents, size_t contents_length, size_t *packet_length) { - int rc = 0; size_t packet_size_length; + int rc = 0; (*packet_length) = 0; if ((13 + contents_length) > max) { @@ -817,7 +1454,6 @@ write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok, struct ecryptfs_key_record *key_rec, size_t *packet_size) { size_t i; - size_t signature_is_valid = 0; size_t encrypted_session_key_valid = 0; char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES]; struct scatterlist dest_sg[2]; @@ -833,19 +1469,14 @@ write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok, int rc = 0; (*packet_size) = 0; - /* Check for a valid signature on the auth_tok */ - for (i = 0; i < ECRYPTFS_SIG_SIZE_HEX; i++) - signature_is_valid |= auth_tok->token.password.signature[i]; - if (!signature_is_valid) - BUG(); - ecryptfs_from_hex((*key_rec).sig, auth_tok->token.password.signature, + ecryptfs_from_hex(key_rec->sig, auth_tok->token.password.signature, ECRYPTFS_SIG_SIZE); encrypted_session_key_valid = 0; for (i = 0; i < crypt_stat->key_size; i++) encrypted_session_key_valid |= auth_tok->session_key.encrypted_key[i]; if (encrypted_session_key_valid) { - memcpy((*key_rec).enc_key, + memcpy(key_rec->enc_key, auth_tok->session_key.encrypted_key, auth_tok->session_key.encrypted_key_size); goto encrypted_session_key_set; @@ -858,10 +1489,10 @@ write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok, memset((crypt_stat->key + 24), 0, 8); auth_tok->session_key.encrypted_key_size = 32; } - (*key_rec).enc_key_size = + key_rec->enc_key_size = auth_tok->session_key.encrypted_key_size; - if (ECRYPTFS_CHECK_FLAG(auth_tok->token.password.flags, - ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET)) { + if (auth_tok->token.password.flags & + ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET) { ecryptfs_printk(KERN_DEBUG, "Using previously generated " "session key encryption key of size [%d]\n", auth_tok->token.password. @@ -879,15 +1510,15 @@ write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok, ecryptfs_dump_hex(session_key_encryption_key, 16); } rc = virt_to_scatterlist(crypt_stat->key, - (*key_rec).enc_key_size, src_sg, 2); + key_rec->enc_key_size, src_sg, 2); if (!rc) { ecryptfs_printk(KERN_ERR, "Error generating scatterlist " "for crypt_stat session key\n"); rc = -ENOMEM; goto out; } - rc = virt_to_scatterlist((*key_rec).enc_key, - (*key_rec).enc_key_size, dest_sg, 2); + rc = virt_to_scatterlist(key_rec->enc_key, + key_rec->enc_key_size, dest_sg, 2); if (!rc) { ecryptfs_printk(KERN_ERR, "Error generating scatterlist " "for crypt_stat encrypted session key\n"); @@ -943,14 +1574,14 @@ write_tag_3_packet(char *dest, size_t max, struct ecryptfs_auth_tok *auth_tok, mutex_unlock(tfm_mutex); ecryptfs_printk(KERN_DEBUG, "This should be the encrypted key:\n"); if (ecryptfs_verbosity > 0) - ecryptfs_dump_hex((*key_rec).enc_key, - (*key_rec).enc_key_size); + ecryptfs_dump_hex(key_rec->enc_key, + key_rec->enc_key_size); encrypted_session_key_set: /* Now we have a valid key_rec. Append it to the * key_rec set. */ key_rec_size = (sizeof(struct ecryptfs_key_record) - ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES - + ((*key_rec).enc_key_size)); + + (key_rec->enc_key_size)); /* TODO: Include a packet size limit as a parameter to this * function once we have multi-packet headers (for versions * later than 0.1 */ @@ -962,7 +1593,7 @@ encrypted_session_key_set: /* TODO: Packet size limit */ /* We have 5 bytes of surrounding packet data */ if ((0x05 + ECRYPTFS_SALT_SIZE - + (*key_rec).enc_key_size) >= max) { + + key_rec->enc_key_size) >= max) { ecryptfs_printk(KERN_ERR, "Authentication token is too " "large\n"); rc = -EINVAL; @@ -974,7 +1605,7 @@ encrypted_session_key_set: /* ver+cipher+s2k+hash+salt+iter+enc_key */ rc = write_packet_length(&dest[(*packet_size)], (0x05 + ECRYPTFS_SALT_SIZE - + (*key_rec).enc_key_size), + + key_rec->enc_key_size), &packet_size_length); if (rc) { ecryptfs_printk(KERN_ERR, "Error generating tag 3 packet " @@ -997,9 +1628,9 @@ encrypted_session_key_set: ECRYPTFS_SALT_SIZE); (*packet_size) += ECRYPTFS_SALT_SIZE; /* salt */ dest[(*packet_size)++] = 0x60; /* hash iterations (65536) */ - memcpy(&dest[(*packet_size)], (*key_rec).enc_key, - (*key_rec).enc_key_size); - (*packet_size) += (*key_rec).enc_key_size; + memcpy(&dest[(*packet_size)], key_rec->enc_key, + key_rec->enc_key_size); + (*packet_size) += key_rec->enc_key_size; out: if (desc.tfm && !tfm_mutex) crypto_free_blkcipher(desc.tfm); @@ -1029,13 +1660,13 @@ ecryptfs_generate_key_packet_set(char *dest_base, struct dentry *ecryptfs_dentry, size_t *len, size_t max) { - int rc = 0; struct ecryptfs_auth_tok *auth_tok; struct ecryptfs_mount_crypt_stat *mount_crypt_stat = &ecryptfs_superblock_to_private( ecryptfs_dentry->d_sb)->mount_crypt_stat; size_t written; struct ecryptfs_key_record key_rec; + int rc = 0; (*len) = 0; if (mount_crypt_stat->global_auth_tok) { @@ -1062,20 +1693,23 @@ ecryptfs_generate_key_packet_set(char *dest_base, goto out; } (*len) += written; + } else if (auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) { + rc = write_tag_1_packet(dest_base + (*len), + max, auth_tok, + crypt_stat,mount_crypt_stat, + &key_rec, &written); + if (rc) { + ecryptfs_printk(KERN_WARNING, "Error " + "writing tag 1 packet\n"); + goto out; + } + (*len) += written; } else { ecryptfs_printk(KERN_WARNING, "Unsupported " "authentication token type\n"); rc = -EINVAL; goto out; } - if (rc) { - ecryptfs_printk(KERN_WARNING, "Error writing " - "authentication token packet with sig " - "= [%s]\n", - mount_crypt_stat->global_auth_tok_sig); - rc = -EIO; - goto out; - } } else BUG(); if (likely((max - (*len)) > 0)) { diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c index d0541ae8fab..26fe405a576 100644 --- a/fs/ecryptfs/main.c +++ b/fs/ecryptfs/main.c @@ -3,9 +3,10 @@ * * Copyright (C) 1997-2003 Erez Zadok * Copyright (C) 2001-2003 Stony Brook University - * Copyright (C) 2004-2006 International Business Machines Corp. + * Copyright (C) 2004-2007 International Business Machines Corp. * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> * Michael C. Thompson <mcthomps@us.ibm.com> + * Tyler Hicks <tyhicks@ou.edu> * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -48,6 +49,43 @@ MODULE_PARM_DESC(ecryptfs_verbosity, "Initial verbosity level (0 or 1; defaults to " "0, which is Quiet)"); +/** + * Module parameter that defines the number of netlink message buffer + * elements + */ +unsigned int ecryptfs_message_buf_len = ECRYPTFS_DEFAULT_MSG_CTX_ELEMS; + +module_param(ecryptfs_message_buf_len, uint, 0); +MODULE_PARM_DESC(ecryptfs_message_buf_len, + "Number of message buffer elements"); + +/** + * Module parameter that defines the maximum guaranteed amount of time to wait + * for a response through netlink. The actual sleep time will be, more than + * likely, a small amount greater than this specified value, but only less if + * the netlink message successfully arrives. + */ +signed long ecryptfs_message_wait_timeout = ECRYPTFS_MAX_MSG_CTX_TTL / HZ; + +module_param(ecryptfs_message_wait_timeout, long, 0); +MODULE_PARM_DESC(ecryptfs_message_wait_timeout, + "Maximum number of seconds that an operation will " + "sleep while waiting for a message response from " + "userspace"); + +/** + * Module parameter that is an estimate of the maximum number of users + * that will be concurrently using eCryptfs. Set this to the right + * value to balance performance and memory use. + */ +unsigned int ecryptfs_number_of_users = ECRYPTFS_DEFAULT_NUM_USERS; + +module_param(ecryptfs_number_of_users, uint, 0); +MODULE_PARM_DESC(ecryptfs_number_of_users, "An estimate of the number of " + "concurrent users of eCryptfs"); + +unsigned int ecryptfs_transport = ECRYPTFS_DEFAULT_TRANSPORT; + void __ecryptfs_printk(const char *fmt, ...) { va_list args; @@ -124,7 +162,8 @@ out: enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig, ecryptfs_opt_debug, ecryptfs_opt_ecryptfs_debug, ecryptfs_opt_cipher, ecryptfs_opt_ecryptfs_cipher, ecryptfs_opt_ecryptfs_key_bytes, - ecryptfs_opt_passthrough, ecryptfs_opt_err }; + ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata, + ecryptfs_opt_encrypted_view, ecryptfs_opt_err }; static match_table_t tokens = { {ecryptfs_opt_sig, "sig=%s"}, @@ -135,6 +174,8 @@ static match_table_t tokens = { {ecryptfs_opt_ecryptfs_cipher, "ecryptfs_cipher=%s"}, {ecryptfs_opt_ecryptfs_key_bytes, "ecryptfs_key_bytes=%u"}, {ecryptfs_opt_passthrough, "ecryptfs_passthrough"}, + {ecryptfs_opt_xattr_metadata, "ecryptfs_xattr_metadata"}, + {ecryptfs_opt_encrypted_view, "ecryptfs_encrypted_view"}, {ecryptfs_opt_err, NULL} }; @@ -275,6 +316,16 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) mount_crypt_stat->flags |= ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED; break; + case ecryptfs_opt_xattr_metadata: + mount_crypt_stat->flags |= + ECRYPTFS_XATTR_METADATA_ENABLED; + break; + case ecryptfs_opt_encrypted_view: + mount_crypt_stat->flags |= + ECRYPTFS_XATTR_METADATA_ENABLED; + mount_crypt_stat->flags |= + ECRYPTFS_ENCRYPTED_VIEW_ENABLED; + break; case ecryptfs_opt_err: default: ecryptfs_printk(KERN_WARNING, @@ -347,9 +398,10 @@ static int ecryptfs_parse_options(struct super_block *sb, char *options) rc = -EINVAL; goto out; } - if (auth_tok->token_type != ECRYPTFS_PASSWORD) { + if (auth_tok->token_type != ECRYPTFS_PASSWORD + && auth_tok->token_type != ECRYPTFS_PRIVATE_KEY) { ecryptfs_printk(KERN_ERR, "Invalid auth_tok structure " - "returned from key\n"); + "returned from key query\n"); rc = -EINVAL; goto out; } @@ -378,15 +430,13 @@ ecryptfs_fill_super(struct super_block *sb, void *raw_data, int silent) /* Released in ecryptfs_put_super() */ ecryptfs_set_superblock_private(sb, - kmem_cache_alloc(ecryptfs_sb_info_cache, + kmem_cache_zalloc(ecryptfs_sb_info_cache, GFP_KERNEL)); if (!ecryptfs_superblock_to_private(sb)) { ecryptfs_printk(KERN_WARNING, "Out of memory\n"); rc = -ENOMEM; goto out; } - memset(ecryptfs_superblock_to_private(sb), 0, - sizeof(struct ecryptfs_sb_info)); sb->s_op = &ecryptfs_sops; /* Released through deactivate_super(sb) from get_sb_nodev */ sb->s_root = d_alloc(NULL, &(const struct qstr) { @@ -402,7 +452,7 @@ ecryptfs_fill_super(struct super_block *sb, void *raw_data, int silent) /* Released in d_release when dput(sb->s_root) is called */ /* through deactivate_super(sb) from get_sb_nodev() */ ecryptfs_set_dentry_private(sb->s_root, - kmem_cache_alloc(ecryptfs_dentry_info_cache, + kmem_cache_zalloc(ecryptfs_dentry_info_cache, GFP_KERNEL)); if (!ecryptfs_dentry_to_private(sb->s_root)) { ecryptfs_printk(KERN_ERR, @@ -410,8 +460,6 @@ ecryptfs_fill_super(struct super_block *sb, void *raw_data, int silent) rc = -ENOMEM; goto out; } - memset(ecryptfs_dentry_to_private(sb->s_root), 0, - sizeof(struct ecryptfs_dentry_info)); rc = 0; out: /* Should be able to rely on deactivate_super called from @@ -594,6 +642,11 @@ static struct ecryptfs_cache_info { .size = PAGE_CACHE_SIZE, }, { + .cache = &ecryptfs_xattr_cache, + .name = "ecryptfs_xattr_cache", + .size = PAGE_CACHE_SIZE, + }, + { .cache = &ecryptfs_lower_page_cache, .name = "ecryptfs_lower_page_cache", .size = PAGE_CACHE_SIZE, @@ -699,7 +752,8 @@ static struct ecryptfs_version_str_map_elem { {ECRYPTFS_VERSIONING_PASSPHRASE, "passphrase"}, {ECRYPTFS_VERSIONING_PUBKEY, "pubkey"}, {ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH, "plaintext passthrough"}, - {ECRYPTFS_VERSIONING_POLICY, "policy"} + {ECRYPTFS_VERSIONING_POLICY, "policy"}, + {ECRYPTFS_VERSIONING_XATTR, "metadata in extended attribute"} }; static ssize_t version_str_show(struct ecryptfs_obj *obj, char *buff) @@ -798,6 +852,11 @@ static int __init ecryptfs_init(void) ecryptfs_free_kmem_caches(); goto out; } + rc = ecryptfs_init_messaging(ecryptfs_transport); + if (rc) { + ecryptfs_printk(KERN_ERR, "Failure occured while attempting to " + "initialize the eCryptfs netlink socket\n"); + } out: return rc; } @@ -809,6 +868,7 @@ static void __exit ecryptfs_exit(void) sysfs_remove_file(&ecryptfs_subsys.kset.kobj, &sysfs_attr_version_str.attr); subsystem_unregister(&ecryptfs_subsys); + ecryptfs_release_messaging(ecryptfs_transport); unregister_filesystem(&ecryptfs_fs_type); ecryptfs_free_kmem_caches(); } diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c new file mode 100644 index 00000000000..47d7e7b611f --- /dev/null +++ b/fs/ecryptfs/messaging.c @@ -0,0 +1,515 @@ +/** + * eCryptfs: Linux filesystem encryption layer + * + * Copyright (C) 2004-2006 International Business Machines Corp. + * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com> + * Tyler Hicks <tyhicks@ou.edu> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include "ecryptfs_kernel.h" + +static LIST_HEAD(ecryptfs_msg_ctx_free_list); +static LIST_HEAD(ecryptfs_msg_ctx_alloc_list); +static struct mutex ecryptfs_msg_ctx_lists_mux; + +static struct hlist_head *ecryptfs_daemon_id_hash; +static struct mutex ecryptfs_daemon_id_hash_mux; +static int ecryptfs_hash_buckets; +#define ecryptfs_uid_hash(uid) \ + hash_long((unsigned long)uid, ecryptfs_hash_buckets) + +static unsigned int ecryptfs_msg_counter; +static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr; + +/** + * ecryptfs_acquire_free_msg_ctx + * @msg_ctx: The context that was acquired from the free list + * + * Acquires a context element from the free list and locks the mutex + * on the context. Returns zero on success; non-zero on error or upon + * failure to acquire a free context element. Be sure to lock the + * list mutex before calling. + */ +static int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx) +{ + struct list_head *p; + int rc; + + if (list_empty(&ecryptfs_msg_ctx_free_list)) { + ecryptfs_printk(KERN_WARNING, "The eCryptfs free " + "context list is empty. It may be helpful to " + "specify the ecryptfs_message_buf_len " + "parameter to be greater than the current " + "value of [%d]\n", ecryptfs_message_buf_len); + rc = -ENOMEM; + goto out; + } + list_for_each(p, &ecryptfs_msg_ctx_free_list) { + *msg_ctx = list_entry(p, struct ecryptfs_msg_ctx, node); + if (mutex_trylock(&(*msg_ctx)->mux)) { + (*msg_ctx)->task = current; + rc = 0; + goto out; + } + } + rc = -ENOMEM; +out: + return rc; +} + +/** + * ecryptfs_msg_ctx_free_to_alloc + * @msg_ctx: The context to move from the free list to the alloc list + * + * Be sure to lock the list mutex and the context mutex before + * calling. + */ +static void ecryptfs_msg_ctx_free_to_alloc(struct ecryptfs_msg_ctx *msg_ctx) +{ + list_move(&msg_ctx->node, &ecryptfs_msg_ctx_alloc_list); + msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_PENDING; + msg_ctx->counter = ++ecryptfs_msg_counter; +} + +/** + * ecryptfs_msg_ctx_alloc_to_free + * @msg_ctx: The context to move from the alloc list to the free list + * + * Be sure to lock the list mutex and the context mutex before + * calling. + */ +static void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx) +{ + list_move(&(msg_ctx->node), &ecryptfs_msg_ctx_free_list); + if (msg_ctx->msg) + kfree(msg_ctx->msg); + msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_FREE; +} + +/** + * ecryptfs_find_daemon_id + * @uid: The user id which maps to the desired daemon id + * @id: If return value is zero, points to the desired daemon id + * pointer + * + * Search the hash list for the given user id. Returns zero if the + * user id exists in the list; non-zero otherwise. The daemon id hash + * mutex should be held before calling this function. + */ +static int ecryptfs_find_daemon_id(uid_t uid, struct ecryptfs_daemon_id **id) +{ + struct hlist_node *elem; + int rc; + + hlist_for_each_entry(*id, elem, + &ecryptfs_daemon_id_hash[ecryptfs_uid_hash(uid)], + id_chain) { + if ((*id)->uid == uid) { + rc = 0; + goto out; + } + } + rc = -EINVAL; +out: + return rc; +} + +static int ecryptfs_send_raw_message(unsigned int transport, u16 msg_type, + pid_t pid) +{ + int rc; + + switch(transport) { + case ECRYPTFS_TRANSPORT_NETLINK: + rc = ecryptfs_send_netlink(NULL, 0, NULL, msg_type, 0, pid); + break; + case ECRYPTFS_TRANSPORT_CONNECTOR: + case ECRYPTFS_TRANSPORT_RELAYFS: + default: + rc = -ENOSYS; + } + return rc; +} + +/** + * ecryptfs_process_helo + * @transport: The underlying transport (netlink, etc.) + * @uid: The user ID owner of the message + * @pid: The process ID for the userspace program that sent the + * message + * + * Adds the uid and pid values to the daemon id hash. If a uid + * already has a daemon pid registered, the daemon will be + * unregistered before the new daemon id is put into the hash list. + * Returns zero after adding a new daemon id to the hash list; + * non-zero otherwise. + */ +int ecryptfs_process_helo(unsigned int transport, uid_t uid, pid_t pid) +{ + struct ecryptfs_daemon_id *new_id; + struct ecryptfs_daemon_id *old_id; + int rc; + + mutex_lock(&ecryptfs_daemon_id_hash_mux); + new_id = kmalloc(sizeof(*new_id), GFP_KERNEL); + if (!new_id) { + rc = -ENOMEM; + ecryptfs_printk(KERN_ERR, "Failed to allocate memory; unable " + "to register daemon [%d] for user\n", pid, uid); + goto unlock; + } + if (!ecryptfs_find_daemon_id(uid, &old_id)) { + printk(KERN_WARNING "Received request from user [%d] " + "to register daemon [%d]; unregistering daemon " + "[%d]\n", uid, pid, old_id->pid); + hlist_del(&old_id->id_chain); + rc = ecryptfs_send_raw_message(transport, ECRYPTFS_NLMSG_QUIT, + old_id->pid); + if (rc) + printk(KERN_WARNING "Failed to send QUIT " + "message to daemon [%d]; rc = [%d]\n", + old_id->pid, rc); + kfree(old_id); + } + new_id->uid = uid; + new_id->pid = pid; + hlist_add_head(&new_id->id_chain, + &ecryptfs_daemon_id_hash[ecryptfs_uid_hash(uid)]); + rc = 0; +unlock: + mutex_unlock(&ecryptfs_daemon_id_hash_mux); + return rc; +} + +/** + * ecryptfs_process_quit + * @uid: The user ID owner of the message + * @pid: The process ID for the userspace program that sent the + * message + * + * Deletes the corresponding daemon id for the given uid and pid, if + * it is the registered that is requesting the deletion. Returns zero + * after deleting the desired daemon id; non-zero otherwise. + */ +int ecryptfs_process_quit(uid_t uid, pid_t pid) +{ + struct ecryptfs_daemon_id *id; + int rc; + + mutex_lock(&ecryptfs_daemon_id_hash_mux); + if (ecryptfs_find_daemon_id(uid, &id)) { + rc = -EINVAL; + ecryptfs_printk(KERN_ERR, "Received request from user [%d] to " + "unregister unrecognized daemon [%d]\n", uid, + pid); + goto unlock; + } + if (id->pid != pid) { + rc = -EINVAL; + ecryptfs_printk(KERN_WARNING, "Received request from user [%d] " + "with pid [%d] to unregister daemon [%d]\n", + uid, pid, id->pid); + goto unlock; + } + hlist_del(&id->id_chain); + kfree(id); + rc = 0; +unlock: + mutex_unlock(&ecryptfs_daemon_id_hash_mux); + return rc; +} + +/** + * ecryptfs_process_reponse + * @msg: The ecryptfs message received; the caller should sanity check + * msg->data_len + * @pid: The process ID of the userspace application that sent the + * message + * @seq: The sequence number of the message + * + * Processes a response message after sending a operation request to + * userspace. Returns zero upon delivery to desired context element; + * non-zero upon delivery failure or error. + */ +int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t uid, + pid_t pid, u32 seq) +{ + struct ecryptfs_daemon_id *id; + struct ecryptfs_msg_ctx *msg_ctx; + int msg_size; + int rc; + + if (msg->index >= ecryptfs_message_buf_len) { + rc = -EINVAL; + ecryptfs_printk(KERN_ERR, "Attempt to reference " + "context buffer at index [%d]; maximum " + "allowable is [%d]\n", msg->index, + (ecryptfs_message_buf_len - 1)); + goto out; + } + msg_ctx = &ecryptfs_msg_ctx_arr[msg->index]; + mutex_lock(&msg_ctx->mux); + if (ecryptfs_find_daemon_id(msg_ctx->task->euid, &id)) { + rc = -EBADMSG; + ecryptfs_printk(KERN_WARNING, "User [%d] received a " + "message response from process [%d] but does " + "not have a registered daemon\n", + msg_ctx->task->euid, pid); + goto wake_up; + } + if (msg_ctx->task->euid != uid) { + rc = -EBADMSG; + ecryptfs_printk(KERN_WARNING, "Received message from user " + "[%d]; expected message from user [%d]\n", + uid, msg_ctx->task->euid); + goto unlock; + } + if (id->pid != pid) { + rc = -EBADMSG; + ecryptfs_printk(KERN_ERR, "User [%d] received a " + "message response from an unrecognized " + "process [%d]\n", msg_ctx->task->euid, pid); + goto unlock; + } + if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) { + rc = -EINVAL; + ecryptfs_printk(KERN_WARNING, "Desired context element is not " + "pending a response\n"); + goto unlock; + } else if (msg_ctx->counter != seq) { + rc = -EINVAL; + ecryptfs_printk(KERN_WARNING, "Invalid message sequence; " + "expected [%d]; received [%d]\n", + msg_ctx->counter, seq); + goto unlock; + } + msg_size = sizeof(*msg) + msg->data_len; + msg_ctx->msg = kmalloc(msg_size, GFP_KERNEL); + if (!msg_ctx->msg) { + rc = -ENOMEM; + ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n"); + goto unlock; + } + memcpy(msg_ctx->msg, msg, msg_size); + msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_DONE; + rc = 0; +wake_up: + wake_up_process(msg_ctx->task); +unlock: + mutex_unlock(&msg_ctx->mux); +out: + return rc; +} + +/** + * ecryptfs_send_message + * @transport: The transport over which to send the message (i.e., + * netlink) + * @data: The data to send + * @data_len: The length of data + * @msg_ctx: The message context allocated for the send + */ +int ecryptfs_send_message(unsigned int transport, char *data, int data_len, + struct ecryptfs_msg_ctx **msg_ctx) +{ + struct ecryptfs_daemon_id *id; + int rc; + + mutex_lock(&ecryptfs_daemon_id_hash_mux); + if (ecryptfs_find_daemon_id(current->euid, &id)) { + mutex_unlock(&ecryptfs_daemon_id_hash_mux); + rc = -ENOTCONN; + ecryptfs_printk(KERN_ERR, "User [%d] does not have a daemon " + "registered\n", current->euid); + goto out; + } + mutex_unlock(&ecryptfs_daemon_id_hash_mux); + mutex_lock(&ecryptfs_msg_ctx_lists_mux); + rc = ecryptfs_acquire_free_msg_ctx(msg_ctx); + if (rc) { + mutex_unlock(&ecryptfs_msg_ctx_lists_mux); + ecryptfs_printk(KERN_WARNING, "Could not claim a free " + "context element\n"); + goto out; + } + ecryptfs_msg_ctx_free_to_alloc(*msg_ctx); + mutex_unlock(&(*msg_ctx)->mux); + mutex_unlock(&ecryptfs_msg_ctx_lists_mux); + switch (transport) { + case ECRYPTFS_TRANSPORT_NETLINK: + rc = ecryptfs_send_netlink(data, data_len, *msg_ctx, + ECRYPTFS_NLMSG_REQUEST, 0, id->pid); + break; + case ECRYPTFS_TRANSPORT_CONNECTOR: + case ECRYPTFS_TRANSPORT_RELAYFS: + default: + rc = -ENOSYS; + } + if (rc) { + printk(KERN_ERR "Error attempting to send message to userspace " + "daemon; rc = [%d]\n", rc); + } +out: + return rc; +} + +/** + * ecryptfs_wait_for_response + * @msg_ctx: The context that was assigned when sending a message + * @msg: The incoming message from userspace; not set if rc != 0 + * + * Sleeps until awaken by ecryptfs_receive_message or until the amount + * of time exceeds ecryptfs_message_wait_timeout. If zero is + * returned, msg will point to a valid message from userspace; a + * non-zero value is returned upon failure to receive a message or an + * error occurs. + */ +int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx, + struct ecryptfs_message **msg) +{ + signed long timeout = ecryptfs_message_wait_timeout * HZ; + int rc = 0; + +sleep: + timeout = schedule_timeout_interruptible(timeout); + mutex_lock(&ecryptfs_msg_ctx_lists_mux); + mutex_lock(&msg_ctx->mux); + if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_DONE) { + if (timeout) { + mutex_unlock(&msg_ctx->mux); + mutex_unlock(&ecryptfs_msg_ctx_lists_mux); + goto sleep; + } + rc = -ENOMSG; + } else { + *msg = msg_ctx->msg; + msg_ctx->msg = NULL; + } + ecryptfs_msg_ctx_alloc_to_free(msg_ctx); + mutex_unlock(&msg_ctx->mux); + mutex_unlock(&ecryptfs_msg_ctx_lists_mux); + return rc; +} + +int ecryptfs_init_messaging(unsigned int transport) +{ + int i; + int rc = 0; + + if (ecryptfs_number_of_users > ECRYPTFS_MAX_NUM_USERS) { + ecryptfs_number_of_users = ECRYPTFS_MAX_NUM_USERS; + ecryptfs_printk(KERN_WARNING, "Specified number of users is " + "too large, defaulting to [%d] users\n", + ecryptfs_number_of_users); + } + mutex_init(&ecryptfs_daemon_id_hash_mux); + mutex_lock(&ecryptfs_daemon_id_hash_mux); + ecryptfs_hash_buckets = 0; + while (ecryptfs_number_of_users >> ++ecryptfs_hash_buckets); + ecryptfs_daemon_id_hash = kmalloc(sizeof(struct hlist_head) + * ecryptfs_hash_buckets, GFP_KERNEL); + if (!ecryptfs_daemon_id_hash) { + rc = -ENOMEM; + ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n"); + goto out; + } + for (i = 0; i < ecryptfs_hash_buckets; i++) + INIT_HLIST_HEAD(&ecryptfs_daemon_id_hash[i]); + mutex_unlock(&ecryptfs_daemon_id_hash_mux); + + ecryptfs_msg_ctx_arr = kmalloc((sizeof(struct ecryptfs_msg_ctx) + * ecryptfs_message_buf_len), GFP_KERNEL); + if (!ecryptfs_msg_ctx_arr) { + rc = -ENOMEM; + ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n"); + goto out; + } + mutex_init(&ecryptfs_msg_ctx_lists_mux); + mutex_lock(&ecryptfs_msg_ctx_lists_mux); + ecryptfs_msg_counter = 0; + for (i = 0; i < ecryptfs_message_buf_len; i++) { + INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].node); + mutex_init(&ecryptfs_msg_ctx_arr[i].mux); + mutex_lock(&ecryptfs_msg_ctx_arr[i].mux); + ecryptfs_msg_ctx_arr[i].index = i; + ecryptfs_msg_ctx_arr[i].state = ECRYPTFS_MSG_CTX_STATE_FREE; + ecryptfs_msg_ctx_arr[i].counter = 0; + ecryptfs_msg_ctx_arr[i].task = NULL; + ecryptfs_msg_ctx_arr[i].msg = NULL; + list_add_tail(&ecryptfs_msg_ctx_arr[i].node, + &ecryptfs_msg_ctx_free_list); + mutex_unlock(&ecryptfs_msg_ctx_arr[i].mux); + } + mutex_unlock(&ecryptfs_msg_ctx_lists_mux); + switch(transport) { + case ECRYPTFS_TRANSPORT_NETLINK: + rc = ecryptfs_init_netlink(); + if (rc) + ecryptfs_release_messaging(transport); + break; + case ECRYPTFS_TRANSPORT_CONNECTOR: + case ECRYPTFS_TRANSPORT_RELAYFS: + default: + rc = -ENOSYS; + } +out: + return rc; +} + +void ecryptfs_release_messaging(unsigned int transport) +{ + if (ecryptfs_msg_ctx_arr) { + int i; + + mutex_lock(&ecryptfs_msg_ctx_lists_mux); + for (i = 0; i < ecryptfs_message_buf_len; i++) { + mutex_lock(&ecryptfs_msg_ctx_arr[i].mux); + if (ecryptfs_msg_ctx_arr[i].msg) + kfree(ecryptfs_msg_ctx_arr[i].msg); + mutex_unlock(&ecryptfs_msg_ctx_arr[i].mux); + } + kfree(ecryptfs_msg_ctx_arr); + mutex_unlock(&ecryptfs_msg_ctx_lists_mux); + } + if (ecryptfs_daemon_id_hash) { + struct hlist_node *elem; + struct ecryptfs_daemon_id *id; + int i; + + mutex_lock(&ecryptfs_daemon_id_hash_mux); + for (i = 0; i < ecryptfs_hash_buckets; i++) { + hlist_for_each_entry(id, elem, + &ecryptfs_daemon_id_hash[i], + id_chain) { + hlist_del(elem); + kfree(id); + } + } + kfree(ecryptfs_daemon_id_hash); + mutex_unlock(&ecryptfs_daemon_id_hash_mux); + } + switch(transport) { + case ECRYPTFS_TRANSPORT_NETLINK: + ecryptfs_release_netlink(); + break; + case ECRYPTFS_TRANSPORT_CONNECTOR: + case ECRYPTFS_TRANSPORT_RELAYFS: + default: + break; + } + return; +} diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c index 06843d24f23..3a6f65c3f14 100644 --- a/fs/ecryptfs/mmap.c +++ b/fs/ecryptfs/mmap.c @@ -6,7 +6,7 @@ * * Copyright (C) 1997-2003 Erez Zadok * Copyright (C) 2001-2003 Stony Brook University - * Copyright (C) 2004-2006 International Business Machines Corp. + * Copyright (C) 2004-2007 International Business Machines Corp. * Author(s): Michael A. Halcrow <mahalcro@us.ibm.com> * * This program is free software; you can redistribute it and/or @@ -234,22 +234,13 @@ int ecryptfs_do_readpage(struct file *file, struct page *page, goto out; } wait_on_page_locked(lower_page); - page_data = (char *)kmap(page); - if (!page_data) { - rc = -ENOMEM; - ecryptfs_printk(KERN_ERR, "Error mapping page\n"); - goto out; - } - lower_page_data = (char *)kmap(lower_page); - if (!lower_page_data) { - rc = -ENOMEM; - ecryptfs_printk(KERN_ERR, "Error mapping page\n"); - kunmap(page); - goto out; - } + page_data = kmap_atomic(page, KM_USER0); + lower_page_data = kmap_atomic(lower_page, KM_USER1); memcpy(page_data, lower_page_data, PAGE_CACHE_SIZE); - kunmap(lower_page); - kunmap(page); + kunmap_atomic(lower_page_data, KM_USER1); + flush_dcache_page(lower_page); + kunmap_atomic(page_data, KM_USER0); + flush_dcache_page(page); rc = 0; out: if (likely(lower_page)) @@ -260,6 +251,33 @@ out: ClearPageUptodate(page); return rc; } +/** + * Header Extent: + * Octets 0-7: Unencrypted file size (big-endian) + * Octets 8-15: eCryptfs special marker + * Octets 16-19: Flags + * Octet 16: File format version number (between 0 and 255) + * Octets 17-18: Reserved + * Octet 19: Bit 1 (lsb): Reserved + * Bit 2: Encrypted? + * Bits 3-8: Reserved + * Octets 20-23: Header extent size (big-endian) + * Octets 24-25: Number of header extents at front of file + * (big-endian) + * Octet 26: Begin RFC 2440 authentication token packet set + */ +static void set_header_info(char *page_virt, + struct ecryptfs_crypt_stat *crypt_stat) +{ + size_t written; + int save_num_header_extents_at_front = + crypt_stat->num_header_extents_at_front; + + crypt_stat->num_header_extents_at_front = 1; + ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &written); + crypt_stat->num_header_extents_at_front = + save_num_header_extents_at_front; +} /** * ecryptfs_readpage @@ -279,8 +297,8 @@ static int ecryptfs_readpage(struct file *file, struct page *page) crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode) ->crypt_stat; if (!crypt_stat - || !ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_ENCRYPTED) - || ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE)) { + || !(crypt_stat->flags & ECRYPTFS_ENCRYPTED) + || (crypt_stat->flags & ECRYPTFS_NEW_FILE)) { ecryptfs_printk(KERN_DEBUG, "Passing through unencrypted page\n"); rc = ecryptfs_do_readpage(file, page, page->index); @@ -289,10 +307,51 @@ static int ecryptfs_readpage(struct file *file, struct page *page) "[%d]\n", rc); goto out; } + } else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) { + if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) { + int num_pages_in_header_region = + (crypt_stat->header_extent_size + / PAGE_CACHE_SIZE); + + if (page->index < num_pages_in_header_region) { + char *page_virt; + + page_virt = kmap_atomic(page, KM_USER0); + memset(page_virt, 0, PAGE_CACHE_SIZE); + if (page->index == 0) { + rc = ecryptfs_read_xattr_region( + page_virt, file->f_path.dentry); + set_header_info(page_virt, crypt_stat); + } + kunmap_atomic(page_virt, KM_USER0); + flush_dcache_page(page); + if (rc) { + printk(KERN_ERR "Error reading xattr " + "region\n"); + goto out; + } + } else { + rc = ecryptfs_do_readpage( + file, page, + (page->index + - num_pages_in_header_region)); + if (rc) { + printk(KERN_ERR "Error reading page; " + "rc = [%d]\n", rc); + goto out; + } + } + } else { + rc = ecryptfs_do_readpage(file, page, page->index); + if (rc) { + printk(KERN_ERR "Error reading page; rc = " + "[%d]\n", rc); + goto out; + } + } } else { rc = ecryptfs_decrypt_page(file, page); if (rc) { - ecryptfs_printk(KERN_ERR, "Error decrypting page; " "rc = [%d]\n", rc); goto out; @@ -308,30 +367,27 @@ out: return rc; } +/** + * Called with lower inode mutex held. + */ static int fill_zeros_to_end_of_page(struct page *page, unsigned int to) { struct inode *inode = page->mapping->host; int end_byte_in_page; - int rc = 0; char *page_virt; - if ((i_size_read(inode) / PAGE_CACHE_SIZE) == page->index) { - end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE; - if (to > end_byte_in_page) - end_byte_in_page = to; - page_virt = kmap(page); - if (!page_virt) { - rc = -ENOMEM; - ecryptfs_printk(KERN_WARNING, - "Could not map page\n"); - goto out; - } - memset((page_virt + end_byte_in_page), 0, - (PAGE_CACHE_SIZE - end_byte_in_page)); - kunmap(page); - } + if ((i_size_read(inode) / PAGE_CACHE_SIZE) != page->index) + goto out; + end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE; + if (to > end_byte_in_page) + end_byte_in_page = to; + page_virt = kmap_atomic(page, KM_USER0); + memset((page_virt + end_byte_in_page), 0, + (PAGE_CACHE_SIZE - end_byte_in_page)); + kunmap_atomic(page_virt, KM_USER0); + flush_dcache_page(page); out: - return rc; + return 0; } static int ecryptfs_prepare_write(struct file *file, struct page *page, @@ -339,7 +395,6 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page, { int rc = 0; - kmap(page); if (from == 0 && to == PAGE_CACHE_SIZE) goto out; /* If we are writing a full page, it will be up to date. */ @@ -349,30 +404,6 @@ out: return rc; } -int ecryptfs_grab_and_map_lower_page(struct page **lower_page, - char **lower_virt, - struct inode *lower_inode, - unsigned long lower_page_index) -{ - int rc = 0; - - (*lower_page) = grab_cache_page(lower_inode->i_mapping, - lower_page_index); - if (!(*lower_page)) { - ecryptfs_printk(KERN_ERR, "grab_cache_page for " - "lower_page_index = [0x%.16x] failed\n", - lower_page_index); - rc = -EINVAL; - goto out; - } - if (lower_virt) - (*lower_virt) = kmap((*lower_page)); - else - kmap((*lower_page)); -out: - return rc; -} - int ecryptfs_writepage_and_release_lower_page(struct page *lower_page, struct inode *lower_inode, struct writeback_control *wbc) @@ -391,11 +422,8 @@ out: return rc; } -static void ecryptfs_unmap_and_release_lower_page(struct page *lower_page) +static void ecryptfs_release_lower_page(struct page *lower_page) { - kunmap(lower_page); - ecryptfs_printk(KERN_DEBUG, "Unlocking lower page with index = " - "[0x%.16x]\n", lower_page->index); unlock_page(lower_page); page_cache_release(lower_page); } @@ -407,10 +435,9 @@ static void ecryptfs_unmap_and_release_lower_page(struct page *lower_page) * * Returns zero on success; non-zero on error. */ -int -ecryptfs_write_inode_size_to_header(struct file *lower_file, - struct inode *lower_inode, - struct inode *inode) +static int ecryptfs_write_inode_size_to_header(struct file *lower_file, + struct inode *lower_inode, + struct inode *inode) { int rc = 0; struct page *header_page; @@ -418,11 +445,11 @@ ecryptfs_write_inode_size_to_header(struct file *lower_file, const struct address_space_operations *lower_a_ops; u64 file_size; - rc = ecryptfs_grab_and_map_lower_page(&header_page, &header_virt, - lower_inode, 0); - if (rc) { - ecryptfs_printk(KERN_ERR, "grab_cache_page for header page " - "failed\n"); + header_page = grab_cache_page(lower_inode->i_mapping, 0); + if (!header_page) { + ecryptfs_printk(KERN_ERR, "grab_cache_page for " + "lower_page_index 0 failed\n"); + rc = -EINVAL; goto out; } lower_a_ops = lower_inode->i_mapping->a_ops; @@ -430,18 +457,95 @@ ecryptfs_write_inode_size_to_header(struct file *lower_file, file_size = (u64)i_size_read(inode); ecryptfs_printk(KERN_DEBUG, "Writing size: [0x%.16x]\n", file_size); file_size = cpu_to_be64(file_size); + header_virt = kmap_atomic(header_page, KM_USER0); memcpy(header_virt, &file_size, sizeof(u64)); + kunmap_atomic(header_virt, KM_USER0); + flush_dcache_page(header_page); rc = lower_a_ops->commit_write(lower_file, header_page, 0, 8); if (rc < 0) ecryptfs_printk(KERN_ERR, "Error commiting header page " "write\n"); - ecryptfs_unmap_and_release_lower_page(header_page); + ecryptfs_release_lower_page(header_page); lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; mark_inode_dirty_sync(inode); out: return rc; } +static int ecryptfs_write_inode_size_to_xattr(struct inode *lower_inode, + struct inode *inode, + struct dentry *ecryptfs_dentry, + int lower_i_mutex_held) +{ + ssize_t size; + void *xattr_virt; + struct dentry *lower_dentry; + u64 file_size; + int rc; + + xattr_virt = kmem_cache_alloc(ecryptfs_xattr_cache, GFP_KERNEL); + if (!xattr_virt) { + printk(KERN_ERR "Out of memory whilst attempting to write " + "inode size to xattr\n"); + rc = -ENOMEM; + goto out; + } + lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry); + if (!lower_dentry->d_inode->i_op->getxattr) { + printk(KERN_WARNING + "No support for setting xattr in lower filesystem\n"); + rc = -ENOSYS; + kmem_cache_free(ecryptfs_xattr_cache, xattr_virt); + goto out; + } + if (!lower_i_mutex_held) + mutex_lock(&lower_dentry->d_inode->i_mutex); + size = lower_dentry->d_inode->i_op->getxattr(lower_dentry, + ECRYPTFS_XATTR_NAME, + xattr_virt, + PAGE_CACHE_SIZE); + if (!lower_i_mutex_held) + mutex_unlock(&lower_dentry->d_inode->i_mutex); + if (size < 0) + size = 8; + file_size = (u64)i_size_read(inode); + file_size = cpu_to_be64(file_size); + memcpy(xattr_virt, &file_size, sizeof(u64)); + if (!lower_i_mutex_held) + mutex_lock(&lower_dentry->d_inode->i_mutex); + rc = lower_dentry->d_inode->i_op->setxattr(lower_dentry, + ECRYPTFS_XATTR_NAME, + xattr_virt, size, 0); + if (!lower_i_mutex_held) + mutex_unlock(&lower_dentry->d_inode->i_mutex); + if (rc) + printk(KERN_ERR "Error whilst attempting to write inode size " + "to lower file xattr; rc = [%d]\n", rc); + kmem_cache_free(ecryptfs_xattr_cache, xattr_virt); +out: + return rc; +} + +int +ecryptfs_write_inode_size_to_metadata(struct file *lower_file, + struct inode *lower_inode, + struct inode *inode, + struct dentry *ecryptfs_dentry, + int lower_i_mutex_held) +{ + struct ecryptfs_crypt_stat *crypt_stat; + + crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat; + if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) + return ecryptfs_write_inode_size_to_xattr(lower_inode, inode, + ecryptfs_dentry, + lower_i_mutex_held); + else + return ecryptfs_write_inode_size_to_header(lower_file, + lower_inode, + inode); +} + int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, struct file *lower_file, unsigned long lower_page_index, int byte_offset, @@ -449,10 +553,10 @@ int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, { int rc = 0; - rc = ecryptfs_grab_and_map_lower_page(lower_page, NULL, lower_inode, - lower_page_index); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error attempting to grab and map " + *lower_page = grab_cache_page(lower_inode->i_mapping, lower_page_index); + if (!(*lower_page)) { + rc = -EINVAL; + ecryptfs_printk(KERN_ERR, "Error attempting to grab " "lower page with index [0x%.16x]\n", lower_page_index); goto out; @@ -468,7 +572,7 @@ int ecryptfs_get_lower_page(struct page **lower_page, struct inode *lower_inode, } out: if (rc && (*lower_page)) { - ecryptfs_unmap_and_release_lower_page(*lower_page); + ecryptfs_release_lower_page(*lower_page); (*lower_page) = NULL; } return rc; @@ -493,7 +597,7 @@ ecryptfs_commit_lower_page(struct page *lower_page, struct inode *lower_inode, "Error committing write; rc = [%d]\n", rc); } else rc = 0; - ecryptfs_unmap_and_release_lower_page(lower_page); + ecryptfs_release_lower_page(lower_page); return rc; } @@ -528,89 +632,7 @@ out: return rc; } -static int -process_new_file(struct ecryptfs_crypt_stat *crypt_stat, - struct file *file, struct inode *inode) -{ - struct page *header_page; - const struct address_space_operations *lower_a_ops; - struct inode *lower_inode; - struct file *lower_file; - char *header_virt; - int rc = 0; - int current_header_page = 0; - int header_pages; - int more_header_data_to_be_written = 1; - - lower_inode = ecryptfs_inode_to_lower(inode); - lower_file = ecryptfs_file_to_lower(file); - lower_a_ops = lower_inode->i_mapping->a_ops; - header_pages = ((crypt_stat->header_extent_size - * crypt_stat->num_header_extents_at_front) - / PAGE_CACHE_SIZE); - BUG_ON(header_pages < 1); - while (current_header_page < header_pages) { - rc = ecryptfs_grab_and_map_lower_page(&header_page, - &header_virt, - lower_inode, - current_header_page); - if (rc) { - ecryptfs_printk(KERN_ERR, "grab_cache_page for " - "header page [%d] failed; rc = [%d]\n", - current_header_page, rc); - goto out; - } - rc = lower_a_ops->prepare_write(lower_file, header_page, 0, - PAGE_CACHE_SIZE); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error preparing to write " - "header page out; rc = [%d]\n", rc); - goto out; - } - memset(header_virt, 0, PAGE_CACHE_SIZE); - if (more_header_data_to_be_written) { - rc = ecryptfs_write_headers_virt(header_virt, - crypt_stat, - file->f_dentry); - if (rc) { - ecryptfs_printk(KERN_WARNING, "Error " - "generating header; rc = " - "[%d]\n", rc); - rc = -EIO; - memset(header_virt, 0, PAGE_CACHE_SIZE); - ecryptfs_unmap_and_release_lower_page( - header_page); - goto out; - } - if (current_header_page == 0) - memset(header_virt, 0, 8); - more_header_data_to_be_written = 0; - } - rc = lower_a_ops->commit_write(lower_file, header_page, 0, - PAGE_CACHE_SIZE); - ecryptfs_unmap_and_release_lower_page(header_page); - if (rc < 0) { - ecryptfs_printk(KERN_ERR, - "Error commiting header page write; " - "rc = [%d]\n", rc); - break; - } - current_header_page++; - } - if (rc >= 0) { - rc = 0; - ecryptfs_printk(KERN_DEBUG, "lower_inode->i_blocks = " - "[0x%.16x]\n", lower_inode->i_blocks); - i_size_write(inode, 0); - lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; - mark_inode_dirty_sync(inode); - } - ecryptfs_printk(KERN_DEBUG, "Clearing ECRYPTFS_NEW_FILE flag in " - "crypt_stat at memory location [%p]\n", crypt_stat); - ECRYPTFS_CLEAR_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE); -out: - return rc; -} +struct kmem_cache *ecryptfs_xattr_cache; /** * ecryptfs_commit_write @@ -640,15 +662,10 @@ static int ecryptfs_commit_write(struct file *file, struct page *page, mutex_lock(&lower_inode->i_mutex); crypt_stat = &ecryptfs_inode_to_private(file->f_path.dentry->d_inode) ->crypt_stat; - if (ECRYPTFS_CHECK_FLAG(crypt_stat->flags, ECRYPTFS_NEW_FILE)) { + if (crypt_stat->flags & ECRYPTFS_NEW_FILE) { ecryptfs_printk(KERN_DEBUG, "ECRYPTFS_NEW_FILE flag set in " "crypt_stat at memory location [%p]\n", crypt_stat); - rc = process_new_file(crypt_stat, file, inode); - if (rc) { - ecryptfs_printk(KERN_ERR, "Error processing new " - "file; rc = [%d]\n", rc); - goto out; - } + crypt_stat->flags &= ~(ECRYPTFS_NEW_FILE); } else ecryptfs_printk(KERN_DEBUG, "Not a new file\n"); ecryptfs_printk(KERN_DEBUG, "Calling fill_zeros_to_end_of_page" @@ -670,7 +687,6 @@ static int ecryptfs_commit_write(struct file *file, struct page *page, "index [0x%.16x])\n", page->index); goto out; } - rc = 0; inode->i_blocks = lower_inode->i_blocks; pos = (page->index << PAGE_CACHE_SHIFT) + to; if (pos > i_size_read(inode)) { @@ -678,11 +694,15 @@ static int ecryptfs_commit_write(struct file *file, struct page *page, ecryptfs_printk(KERN_DEBUG, "Expanded file size to " "[0x%.16x]\n", i_size_read(inode)); } - ecryptfs_write_inode_size_to_header(lower_file, lower_inode, inode); + rc = ecryptfs_write_inode_size_to_metadata(lower_file, lower_inode, + inode, file->f_dentry, + ECRYPTFS_LOWER_I_MUTEX_HELD); + if (rc) + printk(KERN_ERR "Error writing inode size to metadata; " + "rc = [%d]\n", rc); lower_inode->i_mtime = lower_inode->i_ctime = CURRENT_TIME; mark_inode_dirty_sync(inode); out: - kunmap(page); /* mapped in prior call (prepare_write) */ if (rc < 0) ClearPageUptodate(page); else @@ -707,6 +727,7 @@ int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros) { int rc = 0; struct page *tmp_page; + char *tmp_page_virt; tmp_page = ecryptfs_get1page(file, index); if (IS_ERR(tmp_page)) { @@ -715,28 +736,27 @@ int write_zeros(struct file *file, pgoff_t index, int start, int num_zeros) rc = PTR_ERR(tmp_page); goto out; } - kmap(tmp_page); rc = ecryptfs_prepare_write(file, tmp_page, start, start + num_zeros); if (rc) { ecryptfs_printk(KERN_ERR, "Error preparing to write zero's " "to remainder of page at index [0x%.16x]\n", index); - kunmap(tmp_page); page_cache_release(tmp_page); goto out; } - memset(((char *)page_address(tmp_page) + start), 0, num_zeros); + tmp_page_virt = kmap_atomic(tmp_page, KM_USER0); + memset(((char *)tmp_page_virt + start), 0, num_zeros); + kunmap_atomic(tmp_page_virt, KM_USER0); + flush_dcache_page(tmp_page); rc = ecryptfs_commit_write(file, tmp_page, start, start + num_zeros); if (rc < 0) { ecryptfs_printk(KERN_ERR, "Error attempting to write zero's " "to remainder of page at index [0x%.16x]\n", index); - kunmap(tmp_page); page_cache_release(tmp_page); goto out; } rc = 0; - kunmap(tmp_page); page_cache_release(tmp_page); out: return rc; diff --git a/fs/ecryptfs/netlink.c b/fs/ecryptfs/netlink.c new file mode 100644 index 00000000000..e3aa2253c85 --- /dev/null +++ b/fs/ecryptfs/netlink.c @@ -0,0 +1,255 @@ +/** + * eCryptfs: Linux filesystem encryption layer + * + * Copyright (C) 2004-2006 International Business Machines Corp. + * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com> + * Tyler Hicks <tyhicks@ou.edu> + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version + * 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + */ + +#include <net/sock.h> +#include <linux/hash.h> +#include <linux/random.h> +#include "ecryptfs_kernel.h" + +static struct sock *ecryptfs_nl_sock; + +/** + * ecryptfs_send_netlink + * @data: The data to include as the payload + * @data_len: The byte count of the data + * @msg_ctx: The netlink context that will be used to handle the + * response message + * @msg_type: The type of netlink message to send + * @msg_flags: The flags to include in the netlink header + * @daemon_pid: The process id of the daemon to send the message to + * + * Sends the data to the specified daemon pid and uses the netlink + * context element to store the data needed for validation upon + * receiving the response. The data and the netlink context can be + * null if just sending a netlink header is sufficient. Returns zero + * upon sending the message; non-zero upon error. + */ +int ecryptfs_send_netlink(char *data, int data_len, + struct ecryptfs_msg_ctx *msg_ctx, u16 msg_type, + u16 msg_flags, pid_t daemon_pid) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + struct ecryptfs_message *msg; + size_t payload_len; + int rc; + + payload_len = ((data && data_len) ? (sizeof(*msg) + data_len) : 0); + skb = alloc_skb(NLMSG_SPACE(payload_len), GFP_KERNEL); + if (!skb) { + rc = -ENOMEM; + ecryptfs_printk(KERN_ERR, "Failed to allocate socket buffer\n"); + goto out; + } + nlh = NLMSG_PUT(skb, daemon_pid, msg_ctx ? msg_ctx->counter : 0, + msg_type, payload_len); + nlh->nlmsg_flags = msg_flags; + if (msg_ctx && payload_len) { + msg = (struct ecryptfs_message *)NLMSG_DATA(nlh); + msg->index = msg_ctx->index; + msg->data_len = data_len; + memcpy(msg->data, data, data_len); + } + rc = netlink_unicast(ecryptfs_nl_sock, skb, daemon_pid, 0); + if (rc < 0) { + ecryptfs_printk(KERN_ERR, "Failed to send eCryptfs netlink " + "message; rc = [%d]\n", rc); + goto out; + } + rc = 0; + goto out; +nlmsg_failure: + rc = -EMSGSIZE; + kfree_skb(skb); +out: + return rc; +} + +/** + * ecryptfs_process_nl_reponse + * @skb: The socket buffer containing the netlink message of state + * RESPONSE + * + * Processes a response message after sending a operation request to + * userspace. Attempts to assign the msg to a netlink context element + * at the index specified in the msg. The sk_buff and nlmsghdr must + * be validated before this function. Returns zero upon delivery to + * desired context element; non-zero upon delivery failure or error. + */ +static int ecryptfs_process_nl_response(struct sk_buff *skb) +{ + struct nlmsghdr *nlh = (struct nlmsghdr*)skb->data; + struct ecryptfs_message *msg = NLMSG_DATA(nlh); + int rc; + + if (skb->len - NLMSG_HDRLEN - sizeof(*msg) != msg->data_len) { + rc = -EINVAL; + ecryptfs_printk(KERN_ERR, "Received netlink message with " + "incorrectly specified data length\n"); + goto out; + } + rc = ecryptfs_process_response(msg, NETLINK_CREDS(skb)->uid, + NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq); + if (rc) + printk(KERN_ERR + "Error processing response message; rc = [%d]\n", rc); +out: + return rc; +} + +/** + * ecryptfs_process_nl_helo + * @skb: The socket buffer containing the nlmsghdr in HELO state + * + * Gets uid and pid of the skb and adds the values to the daemon id + * hash. Returns zero after adding a new daemon id to the hash list; + * non-zero otherwise. + */ +static int ecryptfs_process_nl_helo(struct sk_buff *skb) +{ + int rc; + + rc = ecryptfs_process_helo(ECRYPTFS_TRANSPORT_NETLINK, + NETLINK_CREDS(skb)->uid, + NETLINK_CREDS(skb)->pid); + if (rc) + printk(KERN_WARNING "Error processing HELO; rc = [%d]\n", rc); + return rc; +} + +/** + * ecryptfs_process_nl_quit + * @skb: The socket buffer containing the nlmsghdr in QUIT state + * + * Gets uid and pid of the skb and deletes the corresponding daemon + * id, if it is the registered that is requesting the + * deletion. Returns zero after deleting the desired daemon id; + * non-zero otherwise. + */ +static int ecryptfs_process_nl_quit(struct sk_buff *skb) +{ + int rc; + + rc = ecryptfs_process_quit(NETLINK_CREDS(skb)->uid, + NETLINK_CREDS(skb)->pid); + if (rc) + printk(KERN_WARNING + "Error processing QUIT message; rc = [%d]\n", rc); + return rc; +} + +/** + * ecryptfs_receive_nl_message + * + * Callback function called by netlink system when a message arrives. + * If the message looks to be valid, then an attempt is made to assign + * it to its desired netlink context element and wake up the process + * that is waiting for a response. + */ +static void ecryptfs_receive_nl_message(struct sock *sk, int len) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + int rc = 0; /* skb_recv_datagram requires this */ + +receive: + skb = skb_recv_datagram(sk, 0, 0, &rc); + if (rc == -EINTR) + goto receive; + else if (rc < 0) { + ecryptfs_printk(KERN_ERR, "Error occurred while " + "receiving eCryptfs netlink message; " + "rc = [%d]\n", rc); + return; + } + nlh = (struct nlmsghdr *)skb->data; + if (!NLMSG_OK(nlh, skb->len)) { + ecryptfs_printk(KERN_ERR, "Received corrupt netlink " + "message\n"); + goto free; + } + switch (nlh->nlmsg_type) { + case ECRYPTFS_NLMSG_RESPONSE: + if (ecryptfs_process_nl_response(skb)) { + ecryptfs_printk(KERN_WARNING, "Failed to " + "deliver netlink response to " + "requesting operation\n"); + } + break; + case ECRYPTFS_NLMSG_HELO: + if (ecryptfs_process_nl_helo(skb)) { + ecryptfs_printk(KERN_WARNING, "Failed to " + "fulfill HELO request\n"); + } + break; + case ECRYPTFS_NLMSG_QUIT: + if (ecryptfs_process_nl_quit(skb)) { + ecryptfs_printk(KERN_WARNING, "Failed to " + "fulfill QUIT request\n"); + } + break; + default: + ecryptfs_printk(KERN_WARNING, "Dropping netlink " + "message of unrecognized type [%d]\n", + nlh->nlmsg_type); + break; + } +free: + kfree_skb(skb); +} + +/** + * ecryptfs_init_netlink + * + * Initializes the daemon id hash list, netlink context array, and + * necessary locks. Returns zero upon success; non-zero upon error. + */ +int ecryptfs_init_netlink(void) +{ + int rc; + + ecryptfs_nl_sock = netlink_kernel_create(NETLINK_ECRYPTFS, 0, + ecryptfs_receive_nl_message, + THIS_MODULE); + if (!ecryptfs_nl_sock) { + rc = -EIO; + ecryptfs_printk(KERN_ERR, "Failed to create netlink socket\n"); + goto out; + } + ecryptfs_nl_sock->sk_sndtimeo = ECRYPTFS_DEFAULT_SEND_TIMEOUT; + rc = 0; +out: + return rc; +} + +/** + * ecryptfs_release_netlink + * + * Frees all memory used by the netlink context array and releases the + * netlink socket. + */ +void ecryptfs_release_netlink(void) +{ + if (ecryptfs_nl_sock && ecryptfs_nl_sock->sk_socket) + sock_release(ecryptfs_nl_sock->sk_socket); + ecryptfs_nl_sock = NULL; +} diff --git a/fs/ecryptfs/super.c b/fs/ecryptfs/super.c index eaa5daaf106..7b3f0cc09a6 100644 --- a/fs/ecryptfs/super.c +++ b/fs/ecryptfs/super.c @@ -168,7 +168,7 @@ out: return rc; } -struct super_operations ecryptfs_sops = { +const struct super_operations ecryptfs_sops = { .alloc_inode = ecryptfs_alloc_inode, .destroy_inode = ecryptfs_destroy_inode, .drop_inode = generic_delete_inode, diff --git a/fs/efs/dir.c b/fs/efs/dir.c index b46c488eefc..dfb5cb40021 100644 --- a/fs/efs/dir.c +++ b/fs/efs/dir.c @@ -15,7 +15,7 @@ const struct file_operations efs_dir_operations = { .readdir = efs_readdir, }; -struct inode_operations efs_dir_inode_operations = { +const struct inode_operations efs_dir_inode_operations = { .lookup = efs_lookup, }; diff --git a/fs/efs/super.c b/fs/efs/super.c index dfebf21289f..c2235e46edc 100644 --- a/fs/efs/super.c +++ b/fs/efs/super.c @@ -105,7 +105,7 @@ static int efs_remount(struct super_block *sb, int *flags, char *data) return 0; } -static struct super_operations efs_superblock_operations = { +static const struct super_operations efs_superblock_operations = { .alloc_inode = efs_alloc_inode, .destroy_inode = efs_destroy_inode, .read_inode = efs_read_inode, diff --git a/fs/exec.c b/fs/exec.c index 11fe93f7363..7e36c6f6f53 100644 --- a/fs/exec.c +++ b/fs/exec.c @@ -405,12 +405,10 @@ int setup_arg_pages(struct linux_binprm *bprm, bprm->loader += stack_base; bprm->exec += stack_base; - mpnt = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); + mpnt = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); if (!mpnt) return -ENOMEM; - memset(mpnt, 0, sizeof(*mpnt)); - down_write(&mm->mmap_sem); { mpnt->vm_mm = mm; diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c index 0b02ba9642d..e89bfc8cf95 100644 --- a/fs/ext2/dir.c +++ b/fs/ext2/dir.c @@ -368,6 +368,14 @@ struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir, } if (++n >= npages) n = 0; + /* next page is past the blocks we've got */ + if (unlikely(n > (dir->i_blocks >> (PAGE_CACHE_SHIFT - 9)))) { + ext2_error(dir->i_sb, __FUNCTION__, + "dir %lu size %lld exceeds block count %llu", + dir->i_ino, dir->i_size, + (unsigned long long)dir->i_blocks); + goto out; + } } while (n != start); out: return NULL; diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h index c19ac153f56..e2a0ea50af1 100644 --- a/fs/ext2/ext2.h +++ b/fs/ext2/ext2.h @@ -158,7 +158,7 @@ extern void ext2_write_super (struct super_block *); extern const struct file_operations ext2_dir_operations; /* file.c */ -extern struct inode_operations ext2_file_inode_operations; +extern const struct inode_operations ext2_file_inode_operations; extern const struct file_operations ext2_file_operations; extern const struct file_operations ext2_xip_file_operations; @@ -168,9 +168,9 @@ extern const struct address_space_operations ext2_aops_xip; extern const struct address_space_operations ext2_nobh_aops; /* namei.c */ -extern struct inode_operations ext2_dir_inode_operations; -extern struct inode_operations ext2_special_inode_operations; +extern const struct inode_operations ext2_dir_inode_operations; +extern const struct inode_operations ext2_special_inode_operations; /* symlink.c */ -extern struct inode_operations ext2_fast_symlink_inode_operations; -extern struct inode_operations ext2_symlink_inode_operations; +extern const struct inode_operations ext2_fast_symlink_inode_operations; +extern const struct inode_operations ext2_symlink_inode_operations; diff --git a/fs/ext2/file.c b/fs/ext2/file.c index 2dba473c524..566d4e2d385 100644 --- a/fs/ext2/file.c +++ b/fs/ext2/file.c @@ -75,7 +75,7 @@ const struct file_operations ext2_xip_file_operations = { }; #endif -struct inode_operations ext2_file_inode_operations = { +const struct inode_operations ext2_file_inode_operations = { .truncate = ext2_truncate, #ifdef CONFIG_EXT2_FS_XATTR .setxattr = generic_setxattr, diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c index e1af5b4cf80..e69beed839a 100644 --- a/fs/ext2/namei.c +++ b/fs/ext2/namei.c @@ -373,7 +373,7 @@ out: return err; } -struct inode_operations ext2_dir_inode_operations = { +const struct inode_operations ext2_dir_inode_operations = { .create = ext2_create, .lookup = ext2_lookup, .link = ext2_link, @@ -393,7 +393,7 @@ struct inode_operations ext2_dir_inode_operations = { .permission = ext2_permission, }; -struct inode_operations ext2_special_inode_operations = { +const struct inode_operations ext2_special_inode_operations = { #ifdef CONFIG_EXT2_FS_XATTR .setxattr = generic_setxattr, .getxattr = generic_getxattr, diff --git a/fs/ext2/super.c b/fs/ext2/super.c index 6347c2dbdd8..a046a419d8a 100644 --- a/fs/ext2/super.c +++ b/fs/ext2/super.c @@ -231,7 +231,7 @@ static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, siz static ssize_t ext2_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off); #endif -static struct super_operations ext2_sops = { +static const struct super_operations ext2_sops = { .alloc_inode = ext2_alloc_inode, .destroy_inode = ext2_destroy_inode, .read_inode = ext2_read_inode, @@ -708,10 +708,14 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent) set_opt(sbi->s_mount_opt, GRPID); if (def_mount_opts & EXT2_DEFM_UID16) set_opt(sbi->s_mount_opt, NO_UID32); +#ifdef CONFIG_EXT2_FS_XATTR if (def_mount_opts & EXT2_DEFM_XATTR_USER) set_opt(sbi->s_mount_opt, XATTR_USER); +#endif +#ifdef CONFIG_EXT2_FS_POSIX_ACL if (def_mount_opts & EXT2_DEFM_ACL) set_opt(sbi->s_mount_opt, POSIX_ACL); +#endif if (le16_to_cpu(sbi->s_es->s_errors) == EXT2_ERRORS_PANIC) set_opt(sbi->s_mount_opt, ERRORS_PANIC); diff --git a/fs/ext2/symlink.c b/fs/ext2/symlink.c index 1e67d87cfa9..4e2426e22bb 100644 --- a/fs/ext2/symlink.c +++ b/fs/ext2/symlink.c @@ -28,7 +28,7 @@ static void *ext2_follow_link(struct dentry *dentry, struct nameidata *nd) return NULL; } -struct inode_operations ext2_symlink_inode_operations = { +const struct inode_operations ext2_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link, @@ -40,7 +40,7 @@ struct inode_operations ext2_symlink_inode_operations = { #endif }; -struct inode_operations ext2_fast_symlink_inode_operations = { +const struct inode_operations ext2_fast_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = ext2_follow_link, #ifdef CONFIG_EXT2_FS_XATTR diff --git a/fs/ext3/file.c b/fs/ext3/file.c index 881f6365c41..1e6f1386453 100644 --- a/fs/ext3/file.c +++ b/fs/ext3/file.c @@ -125,7 +125,7 @@ const struct file_operations ext3_file_operations = { .splice_write = generic_file_splice_write, }; -struct inode_operations ext3_file_inode_operations = { +const struct inode_operations ext3_file_inode_operations = { .truncate = ext3_truncate, .setattr = ext3_setattr, #ifdef CONFIG_EXT3_FS_XATTR diff --git a/fs/ext3/inode.c b/fs/ext3/inode.c index beaf25f5112..8a824f4ce5c 100644 --- a/fs/ext3/inode.c +++ b/fs/ext3/inode.c @@ -947,7 +947,7 @@ out: static int ext3_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { - handle_t *handle = journal_current_handle(); + handle_t *handle = ext3_journal_current_handle(); int ret = 0; unsigned max_blocks = bh_result->b_size >> inode->i_blkbits; @@ -1717,7 +1717,7 @@ static ssize_t ext3_direct_IO(int rw, struct kiocb *iocb, /* * Reacquire the handle: ext3_get_block() can restart the transaction */ - handle = journal_current_handle(); + handle = ext3_journal_current_handle(); out_stop: if (handle) { diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c index 4df39c4315e..49159f13cc1 100644 --- a/fs/ext3/namei.c +++ b/fs/ext3/namei.c @@ -1618,21 +1618,6 @@ static int ext3_delete_entry (handle_t *handle, return -ENOENT; } -/* - * ext3_mark_inode_dirty is somewhat expensive, so unlike ext2 we - * do not perform it in these functions. We perform it at the call site, - * if it is needed. - */ -static inline void ext3_inc_count(handle_t *handle, struct inode *inode) -{ - inc_nlink(inode); -} - -static inline void ext3_dec_count(handle_t *handle, struct inode *inode) -{ - drop_nlink(inode); -} - static int ext3_add_nondir(handle_t *handle, struct dentry *dentry, struct inode *inode) { @@ -1642,7 +1627,7 @@ static int ext3_add_nondir(handle_t *handle, d_instantiate(dentry, inode); return 0; } - ext3_dec_count(handle, inode); + drop_nlink(inode); iput(inode); return err; } @@ -2163,7 +2148,7 @@ retry: err = __page_symlink(inode, symname, l, mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); if (err) { - ext3_dec_count(handle, inode); + drop_nlink(inode); ext3_mark_inode_dirty(handle, inode); iput (inode); goto out_stop; @@ -2191,6 +2176,12 @@ static int ext3_link (struct dentry * old_dentry, if (inode->i_nlink >= EXT3_LINK_MAX) return -EMLINK; + /* + * Return -ENOENT if we've raced with unlink and i_nlink is 0. Doing + * otherwise has the potential to corrupt the orphan inode list. + */ + if (inode->i_nlink == 0) + return -ENOENT; retry: handle = ext3_journal_start(dir, EXT3_DATA_TRANS_BLOCKS(dir->i_sb) + @@ -2202,7 +2193,7 @@ retry: handle->h_sync = 1; inode->i_ctime = CURRENT_TIME_SEC; - ext3_inc_count(handle, inode); + inc_nlink(inode); atomic_inc(&inode->i_count); err = ext3_add_nondir(handle, dentry, inode); @@ -2374,7 +2365,7 @@ end_rename: /* * directories can handle most operations... */ -struct inode_operations ext3_dir_inode_operations = { +const struct inode_operations ext3_dir_inode_operations = { .create = ext3_create, .lookup = ext3_lookup, .link = ext3_link, @@ -2394,7 +2385,7 @@ struct inode_operations ext3_dir_inode_operations = { .permission = ext3_permission, }; -struct inode_operations ext3_special_inode_operations = { +const struct inode_operations ext3_special_inode_operations = { .setattr = ext3_setattr, #ifdef CONFIG_EXT3_FS_XATTR .setxattr = generic_setxattr, diff --git a/fs/ext3/super.c b/fs/ext3/super.c index b34886734a4..4a4fcd6868c 100644 --- a/fs/ext3/super.c +++ b/fs/ext3/super.c @@ -639,7 +639,7 @@ static struct quotactl_ops ext3_qctl_operations = { }; #endif -static struct super_operations ext3_sops = { +static const struct super_operations ext3_sops = { .alloc_inode = ext3_alloc_inode, .destroy_inode = ext3_destroy_inode, .read_inode = ext3_read_inode, @@ -1459,10 +1459,14 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent) set_opt(sbi->s_mount_opt, GRPID); if (def_mount_opts & EXT3_DEFM_UID16) set_opt(sbi->s_mount_opt, NO_UID32); +#ifdef CONFIG_EXT3_FS_XATTR if (def_mount_opts & EXT3_DEFM_XATTR_USER) set_opt(sbi->s_mount_opt, XATTR_USER); +#endif +#ifdef CONFIG_EXT3_FS_POSIX_ACL if (def_mount_opts & EXT3_DEFM_ACL) set_opt(sbi->s_mount_opt, POSIX_ACL); +#endif if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_DATA) sbi->s_mount_opt |= EXT3_MOUNT_JOURNAL_DATA; else if ((def_mount_opts & EXT3_DEFM_JMODE) == EXT3_DEFM_JMODE_ORDERED) @@ -2344,6 +2348,22 @@ static int ext3_remount (struct super_block * sb, int * flags, char * data) err = -EROFS; goto restore_opts; } + + /* + * If we have an unprocessed orphan list hanging + * around from a previously readonly bdev mount, + * require a full umount/remount for now. + */ + if (es->s_last_orphan) { + printk(KERN_WARNING "EXT3-fs: %s: couldn't " + "remount RDWR because of unprocessed " + "orphan inode list. Please " + "umount/remount instead.\n", + sb->s_id); + err = -EINVAL; + goto restore_opts; + } + /* * Mounting a RDONLY partition read-write, so reread * and store the current valid flag. (It may have diff --git a/fs/ext3/symlink.c b/fs/ext3/symlink.c index 4f79122cde6..ff7b4ccd898 100644 --- a/fs/ext3/symlink.c +++ b/fs/ext3/symlink.c @@ -30,7 +30,7 @@ static void * ext3_follow_link(struct dentry *dentry, struct nameidata *nd) return NULL; } -struct inode_operations ext3_symlink_inode_operations = { +const struct inode_operations ext3_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link, @@ -42,7 +42,7 @@ struct inode_operations ext3_symlink_inode_operations = { #endif }; -struct inode_operations ext3_fast_symlink_inode_operations = { +const struct inode_operations ext3_fast_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = ext3_follow_link, #ifdef CONFIG_EXT3_FS_XATTR diff --git a/fs/ext4/file.c b/fs/ext4/file.c index 3bbc24b5878..3c6c1fd2be9 100644 --- a/fs/ext4/file.c +++ b/fs/ext4/file.c @@ -125,7 +125,7 @@ const struct file_operations ext4_file_operations = { .splice_write = generic_file_splice_write, }; -struct inode_operations ext4_file_inode_operations = { +const struct inode_operations ext4_file_inode_operations = { .truncate = ext4_truncate, .setattr = ext4_setattr, #ifdef CONFIG_EXT4DEV_FS_XATTR diff --git a/fs/ext4/inode.c b/fs/ext4/inode.c index a127cc03c9f..fbff4b9e122 100644 --- a/fs/ext4/inode.c +++ b/fs/ext4/inode.c @@ -946,7 +946,7 @@ out: static int ext4_get_block(struct inode *inode, sector_t iblock, struct buffer_head *bh_result, int create) { - handle_t *handle = journal_current_handle(); + handle_t *handle = ext4_journal_current_handle(); int ret = 0; unsigned max_blocks = bh_result->b_size >> inode->i_blkbits; @@ -1716,7 +1716,7 @@ static ssize_t ext4_direct_IO(int rw, struct kiocb *iocb, /* * Reacquire the handle: ext4_get_block() can restart the transaction */ - handle = journal_current_handle(); + handle = ext4_journal_current_handle(); out_stop: if (handle) { diff --git a/fs/ext4/namei.c b/fs/ext4/namei.c index e5a74a5ac26..e7e1d79a7d7 100644 --- a/fs/ext4/namei.c +++ b/fs/ext4/namei.c @@ -1616,21 +1616,6 @@ static int ext4_delete_entry (handle_t *handle, return -ENOENT; } -/* - * ext4_mark_inode_dirty is somewhat expensive, so unlike ext2 we - * do not perform it in these functions. We perform it at the call site, - * if it is needed. - */ -static inline void ext4_inc_count(handle_t *handle, struct inode *inode) -{ - inc_nlink(inode); -} - -static inline void ext4_dec_count(handle_t *handle, struct inode *inode) -{ - drop_nlink(inode); -} - static int ext4_add_nondir(handle_t *handle, struct dentry *dentry, struct inode *inode) { @@ -1640,7 +1625,7 @@ static int ext4_add_nondir(handle_t *handle, d_instantiate(dentry, inode); return 0; } - ext4_dec_count(handle, inode); + drop_nlink(inode); iput(inode); return err; } @@ -2161,7 +2146,7 @@ retry: err = __page_symlink(inode, symname, l, mapping_gfp_mask(inode->i_mapping) & ~__GFP_FS); if (err) { - ext4_dec_count(handle, inode); + drop_nlink(inode); ext4_mark_inode_dirty(handle, inode); iput (inode); goto out_stop; @@ -2189,6 +2174,12 @@ static int ext4_link (struct dentry * old_dentry, if (inode->i_nlink >= EXT4_LINK_MAX) return -EMLINK; + /* + * Return -ENOENT if we've raced with unlink and i_nlink is 0. Doing + * otherwise has the potential to corrupt the orphan inode list. + */ + if (inode->i_nlink == 0) + return -ENOENT; retry: handle = ext4_journal_start(dir, EXT4_DATA_TRANS_BLOCKS(dir->i_sb) + @@ -2200,7 +2191,7 @@ retry: handle->h_sync = 1; inode->i_ctime = CURRENT_TIME_SEC; - ext4_inc_count(handle, inode); + inc_nlink(inode); atomic_inc(&inode->i_count); err = ext4_add_nondir(handle, dentry, inode); @@ -2372,7 +2363,7 @@ end_rename: /* * directories can handle most operations... */ -struct inode_operations ext4_dir_inode_operations = { +const struct inode_operations ext4_dir_inode_operations = { .create = ext4_create, .lookup = ext4_lookup, .link = ext4_link, @@ -2392,7 +2383,7 @@ struct inode_operations ext4_dir_inode_operations = { .permission = ext4_permission, }; -struct inode_operations ext4_special_inode_operations = { +const struct inode_operations ext4_special_inode_operations = { .setattr = ext4_setattr, #ifdef CONFIG_EXT4DEV_FS_XATTR .setxattr = generic_setxattr, diff --git a/fs/ext4/super.c b/fs/ext4/super.c index 486a641ca71..61c4718e4a5 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -690,7 +690,7 @@ static struct quotactl_ops ext4_qctl_operations = { }; #endif -static struct super_operations ext4_sops = { +static const struct super_operations ext4_sops = { .alloc_inode = ext4_alloc_inode, .destroy_inode = ext4_destroy_inode, .read_inode = ext4_read_inode, @@ -1518,10 +1518,14 @@ static int ext4_fill_super (struct super_block *sb, void *data, int silent) set_opt(sbi->s_mount_opt, GRPID); if (def_mount_opts & EXT4_DEFM_UID16) set_opt(sbi->s_mount_opt, NO_UID32); +#ifdef CONFIG_EXT4DEV_FS_XATTR if (def_mount_opts & EXT4_DEFM_XATTR_USER) set_opt(sbi->s_mount_opt, XATTR_USER); +#endif +#ifdef CONFIG_EXT4DEV_FS_POSIX_ACL if (def_mount_opts & EXT4_DEFM_ACL) set_opt(sbi->s_mount_opt, POSIX_ACL); +#endif if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_DATA) sbi->s_mount_opt |= EXT4_MOUNT_JOURNAL_DATA; else if ((def_mount_opts & EXT4_DEFM_JMODE) == EXT4_DEFM_JMODE_ORDERED) @@ -2419,6 +2423,22 @@ static int ext4_remount (struct super_block * sb, int * flags, char * data) err = -EROFS; goto restore_opts; } + + /* + * If we have an unprocessed orphan list hanging + * around from a previously readonly bdev mount, + * require a full umount/remount for now. + */ + if (es->s_last_orphan) { + printk(KERN_WARNING "EXT4-fs: %s: couldn't " + "remount RDWR because of unprocessed " + "orphan inode list. Please " + "umount/remount instead.\n", + sb->s_id); + err = -EINVAL; + goto restore_opts; + } + /* * Mounting a RDONLY partition read-write, so reread * and store the current valid flag. (It may have diff --git a/fs/ext4/symlink.c b/fs/ext4/symlink.c index fcf527286d7..e6f9da4287c 100644 --- a/fs/ext4/symlink.c +++ b/fs/ext4/symlink.c @@ -30,7 +30,7 @@ static void * ext4_follow_link(struct dentry *dentry, struct nameidata *nd) return NULL; } -struct inode_operations ext4_symlink_inode_operations = { +const struct inode_operations ext4_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link, @@ -42,7 +42,7 @@ struct inode_operations ext4_symlink_inode_operations = { #endif }; -struct inode_operations ext4_fast_symlink_inode_operations = { +const struct inode_operations ext4_fast_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = ext4_follow_link, #ifdef CONFIG_EXT4DEV_FS_XATTR diff --git a/fs/fat/file.c b/fs/fat/file.c index c1237b70c1f..55d3c7461c5 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c @@ -312,7 +312,7 @@ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) } EXPORT_SYMBOL_GPL(fat_getattr); -struct inode_operations fat_file_inode_operations = { +const struct inode_operations fat_file_inode_operations = { .truncate = fat_truncate, .setattr = fat_notify_change, .getattr = fat_getattr, diff --git a/fs/fat/inode.c b/fs/fat/inode.c index a9e4688582a..76107354421 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c @@ -618,7 +618,7 @@ int fat_sync_inode(struct inode *inode) EXPORT_SYMBOL_GPL(fat_sync_inode); static int fat_show_options(struct seq_file *m, struct vfsmount *mnt); -static struct super_operations fat_sops = { +static const struct super_operations fat_sops = { .alloc_inode = fat_alloc_inode, .destroy_inode = fat_destroy_inode, .write_inode = fat_write_inode, @@ -1151,7 +1151,7 @@ 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, - struct inode_operations *fs_dir_inode_ops, int isvfat) + const struct inode_operations *fs_dir_inode_ops, int isvfat) { struct inode *root_inode = NULL; struct buffer_head *bh; diff --git a/fs/freevxfs/vxfs_extern.h b/fs/freevxfs/vxfs_extern.h index 1cf1fe8466a..91ccee8723f 100644 --- a/fs/freevxfs/vxfs_extern.h +++ b/fs/freevxfs/vxfs_extern.h @@ -62,7 +62,7 @@ extern void vxfs_read_inode(struct inode *); extern void vxfs_clear_inode(struct inode *); /* vxfs_lookup.c */ -extern struct inode_operations vxfs_dir_inode_ops; +extern const struct inode_operations vxfs_dir_inode_ops; extern const struct file_operations vxfs_dir_operations; /* vxfs_olt.c */ diff --git a/fs/freevxfs/vxfs_immed.c b/fs/freevxfs/vxfs_immed.c index 4e25f3fbed8..24b5a775ff9 100644 --- a/fs/freevxfs/vxfs_immed.c +++ b/fs/freevxfs/vxfs_immed.c @@ -48,7 +48,7 @@ static int vxfs_immed_readpage(struct file *, struct page *); * Unliked all other operations we do not go through the pagecache, * but do all work directly on the inode. */ -struct inode_operations vxfs_immed_symlink_iops = { +const struct inode_operations vxfs_immed_symlink_iops = { .readlink = generic_readlink, .follow_link = vxfs_immed_follow_link, }; diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c index 0b7ae897cb7..098a915fd9a 100644 --- a/fs/freevxfs/vxfs_inode.c +++ b/fs/freevxfs/vxfs_inode.c @@ -44,7 +44,7 @@ extern const struct address_space_operations vxfs_aops; extern const struct address_space_operations vxfs_immed_aops; -extern struct inode_operations vxfs_immed_symlink_iops; +extern const struct inode_operations vxfs_immed_symlink_iops; struct kmem_cache *vxfs_inode_cachep; diff --git a/fs/freevxfs/vxfs_lookup.c b/fs/freevxfs/vxfs_lookup.c index 3995d7fbeda..bf86e5444ea 100644 --- a/fs/freevxfs/vxfs_lookup.c +++ b/fs/freevxfs/vxfs_lookup.c @@ -52,7 +52,7 @@ static struct dentry * vxfs_lookup(struct inode *, struct dentry *, struct nameidata *); static int vxfs_readdir(struct file *, void *, filldir_t); -struct inode_operations vxfs_dir_inode_ops = { +const struct inode_operations vxfs_dir_inode_ops = { .lookup = vxfs_lookup, }; diff --git a/fs/freevxfs/vxfs_super.c b/fs/freevxfs/vxfs_super.c index ac28b0835ff..647d600f0bc 100644 --- a/fs/freevxfs/vxfs_super.c +++ b/fs/freevxfs/vxfs_super.c @@ -59,7 +59,7 @@ static void vxfs_put_super(struct super_block *); static int vxfs_statfs(struct dentry *, struct kstatfs *); static int vxfs_remount(struct super_block *, int *, char *); -static struct super_operations vxfs_super_ops = { +static const struct super_operations vxfs_super_ops = { .read_inode = vxfs_read_inode, .clear_inode = vxfs_clear_inode, .put_super = vxfs_put_super, diff --git a/fs/fuse/control.c b/fs/fuse/control.c index 1794305f9ed..105d4a271e0 100644 --- a/fs/fuse/control.c +++ b/fs/fuse/control.c @@ -73,7 +73,7 @@ static struct dentry *fuse_ctl_add_dentry(struct dentry *parent, struct fuse_conn *fc, const char *name, int mode, int nlink, - struct inode_operations *iop, + const struct inode_operations *iop, const struct file_operations *fop) { struct dentry *dentry; diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 40080477ceb..406bf61ed51 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c @@ -1242,7 +1242,7 @@ static int fuse_removexattr(struct dentry *entry, const char *name) return err; } -static struct inode_operations fuse_dir_inode_operations = { +static const struct inode_operations fuse_dir_inode_operations = { .lookup = fuse_lookup, .mkdir = fuse_mkdir, .symlink = fuse_symlink, @@ -1270,7 +1270,7 @@ static const struct file_operations fuse_dir_operations = { .fsync = fuse_dir_fsync, }; -static struct inode_operations fuse_common_inode_operations = { +static const struct inode_operations fuse_common_inode_operations = { .setattr = fuse_setattr, .permission = fuse_permission, .getattr = fuse_getattr, @@ -1280,7 +1280,7 @@ static struct inode_operations fuse_common_inode_operations = { .removexattr = fuse_removexattr, }; -static struct inode_operations fuse_symlink_inode_operations = { +static const struct inode_operations fuse_symlink_inode_operations = { .setattr = fuse_setattr, .follow_link = fuse_follow_link, .put_link = fuse_put_link, diff --git a/fs/fuse/file.c b/fs/fuse/file.c index f63efe1337e..2fd06927e85 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -69,7 +69,7 @@ void fuse_finish_open(struct inode *inode, struct file *file, if (outarg->open_flags & FOPEN_DIRECT_IO) file->f_op = &fuse_direct_io_file_operations; if (!(outarg->open_flags & FOPEN_KEEP_CACHE)) - invalidate_inode_pages(inode->i_mapping); + invalidate_mapping_pages(inode->i_mapping, 0, -1); ff->fh = outarg->fh; file->private_data = ff; } diff --git a/fs/fuse/inode.c b/fs/fuse/inode.c index 12450d2b320..5ab8e50e780 100644 --- a/fs/fuse/inode.c +++ b/fs/fuse/inode.c @@ -112,7 +112,7 @@ void fuse_change_attributes(struct inode *inode, struct fuse_attr *attr) { struct fuse_conn *fc = get_fuse_conn(inode); if (S_ISREG(inode->i_mode) && i_size_read(inode) != attr->size) - invalidate_inode_pages(inode->i_mapping); + invalidate_mapping_pages(inode->i_mapping, 0, -1); inode->i_ino = attr->ino; inode->i_mode = (inode->i_mode & S_IFMT) + (attr->mode & 07777); @@ -446,7 +446,7 @@ static struct inode *get_root_inode(struct super_block *sb, unsigned mode) return fuse_iget(sb, 1, 0, &attr); } -static struct super_operations fuse_super_operations = { +static const struct super_operations fuse_super_operations = { .alloc_inode = fuse_alloc_inode, .destroy_inode = fuse_destroy_inode, .read_inode = fuse_read_inode, diff --git a/fs/gfs2/locking/dlm/plock.c b/fs/gfs2/locking/dlm/plock.c index 3799f19b282..1dd4215b83d 100644 --- a/fs/gfs2/locking/dlm/plock.c +++ b/fs/gfs2/locking/dlm/plock.c @@ -264,7 +264,7 @@ static unsigned int dev_poll(struct file *file, poll_table *wait) return 0; } -static struct file_operations dev_fops = { +static const struct file_operations dev_fops = { .read = dev_read, .write = dev_write, .poll = dev_poll, diff --git a/fs/gfs2/meta_io.c b/fs/gfs2/meta_io.c index 0e34d991897..e62d4f620c5 100644 --- a/fs/gfs2/meta_io.c +++ b/fs/gfs2/meta_io.c @@ -282,8 +282,7 @@ void gfs2_attach_bufdata(struct gfs2_glock *gl, struct buffer_head *bh, return; } - bd = kmem_cache_alloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL), - memset(bd, 0, sizeof(struct gfs2_bufdata)); + bd = kmem_cache_zalloc(gfs2_bufdata_cachep, GFP_NOFS | __GFP_NOFAIL), bd->bd_bh = bh; bd->bd_gl = gl; diff --git a/fs/gfs2/ops_inode.c b/fs/gfs2/ops_inode.c index f40a84807d7..60f47bf2e8e 100644 --- a/fs/gfs2/ops_inode.c +++ b/fs/gfs2/ops_inode.c @@ -1115,7 +1115,7 @@ static int gfs2_removexattr(struct dentry *dentry, const char *name) return gfs2_ea_remove(GFS2_I(dentry->d_inode), &er); } -struct inode_operations gfs2_file_iops = { +const struct inode_operations gfs2_file_iops = { .permission = gfs2_permission, .setattr = gfs2_setattr, .getattr = gfs2_getattr, @@ -1125,7 +1125,7 @@ struct inode_operations gfs2_file_iops = { .removexattr = gfs2_removexattr, }; -struct inode_operations gfs2_dev_iops = { +const struct inode_operations gfs2_dev_iops = { .permission = gfs2_permission, .setattr = gfs2_setattr, .getattr = gfs2_getattr, @@ -1135,7 +1135,7 @@ struct inode_operations gfs2_dev_iops = { .removexattr = gfs2_removexattr, }; -struct inode_operations gfs2_dir_iops = { +const struct inode_operations gfs2_dir_iops = { .create = gfs2_create, .lookup = gfs2_lookup, .link = gfs2_link, @@ -1154,7 +1154,7 @@ struct inode_operations gfs2_dir_iops = { .removexattr = gfs2_removexattr, }; -struct inode_operations gfs2_symlink_iops = { +const struct inode_operations gfs2_symlink_iops = { .readlink = gfs2_readlink, .follow_link = gfs2_follow_link, .permission = gfs2_permission, diff --git a/fs/gfs2/ops_inode.h b/fs/gfs2/ops_inode.h index b15acb4fd34..34f0caac1a0 100644 --- a/fs/gfs2/ops_inode.h +++ b/fs/gfs2/ops_inode.h @@ -12,9 +12,9 @@ #include <linux/fs.h> -extern struct inode_operations gfs2_file_iops; -extern struct inode_operations gfs2_dir_iops; -extern struct inode_operations gfs2_symlink_iops; -extern struct inode_operations gfs2_dev_iops; +extern const struct inode_operations gfs2_file_iops; +extern const struct inode_operations gfs2_dir_iops; +extern const struct inode_operations gfs2_symlink_iops; +extern const struct inode_operations gfs2_dev_iops; #endif /* __OPS_INODE_DOT_H__ */ diff --git a/fs/gfs2/ops_super.c b/fs/gfs2/ops_super.c index 47369d01121..b89999d3a76 100644 --- a/fs/gfs2/ops_super.c +++ b/fs/gfs2/ops_super.c @@ -468,7 +468,7 @@ static void gfs2_destroy_inode(struct inode *inode) kmem_cache_free(gfs2_inode_cachep, inode); } -struct super_operations gfs2_super_ops = { +const struct super_operations gfs2_super_ops = { .alloc_inode = gfs2_alloc_inode, .destroy_inode = gfs2_destroy_inode, .write_inode = gfs2_write_inode, diff --git a/fs/gfs2/ops_super.h b/fs/gfs2/ops_super.h index 9de73f042f7..442a274c627 100644 --- a/fs/gfs2/ops_super.h +++ b/fs/gfs2/ops_super.h @@ -12,6 +12,6 @@ #include <linux/fs.h> -extern struct super_operations gfs2_super_ops; +extern const struct super_operations gfs2_super_ops; #endif /* __OPS_SUPER_DOT_H__ */ diff --git a/fs/hfs/dir.c b/fs/hfs/dir.c index e2e0358da33..7c69b98a2e4 100644 --- a/fs/hfs/dir.c +++ b/fs/hfs/dir.c @@ -320,7 +320,7 @@ const struct file_operations hfs_dir_operations = { .release = hfs_dir_release, }; -struct inode_operations hfs_dir_inode_operations = { +const struct inode_operations hfs_dir_inode_operations = { .create = hfs_create, .lookup = hfs_lookup, .unlink = hfs_unlink, diff --git a/fs/hfs/hfs.h b/fs/hfs/hfs.h index 88099ab1a18..1445e3a56ed 100644 --- a/fs/hfs/hfs.h +++ b/fs/hfs/hfs.h @@ -83,8 +83,6 @@ /*======== HFS structures as they appear on the disk ========*/ -#define __packed __attribute__ ((packed)) - /* Pascal-style string of up to 31 characters */ struct hfs_name { u8 len; diff --git a/fs/hfs/hfs_fs.h b/fs/hfs/hfs_fs.h index 735332dfd1b..147374b6f67 100644 --- a/fs/hfs/hfs_fs.h +++ b/fs/hfs/hfs_fs.h @@ -170,7 +170,7 @@ extern void hfs_cat_build_key(struct super_block *, btree_key *, u32, struct qst /* dir.c */ extern const struct file_operations hfs_dir_operations; -extern struct inode_operations hfs_dir_inode_operations; +extern const struct inode_operations hfs_dir_inode_operations; /* extent.c */ extern int hfs_ext_keycmp(const btree_key *, const btree_key *); diff --git a/fs/hfs/inode.c b/fs/hfs/inode.c index 5cb7f8fee8d..fafcba59387 100644 --- a/fs/hfs/inode.c +++ b/fs/hfs/inode.c @@ -18,7 +18,7 @@ #include "btree.h" static const struct file_operations hfs_file_operations; -static struct inode_operations hfs_file_inode_operations; +static const struct inode_operations hfs_file_inode_operations; /*================ Variable-like macros ================*/ @@ -612,7 +612,7 @@ static const struct file_operations hfs_file_operations = { .release = hfs_file_release, }; -static struct inode_operations hfs_file_inode_operations = { +static const struct inode_operations hfs_file_inode_operations = { .lookup = hfs_file_lookup, .truncate = hfs_file_truncate, .setattr = hfs_inode_setattr, diff --git a/fs/hfs/super.c b/fs/hfs/super.c index a3698796600..623f509f1d4 100644 --- a/fs/hfs/super.c +++ b/fs/hfs/super.c @@ -154,7 +154,7 @@ static void hfs_destroy_inode(struct inode *inode) kmem_cache_free(hfs_inode_cachep, HFS_I(inode)); } -static struct super_operations hfs_super_operations = { +static const struct super_operations hfs_super_operations = { .alloc_inode = hfs_alloc_inode, .destroy_inode = hfs_destroy_inode, .write_inode = hfs_write_inode, diff --git a/fs/hfsplus/dir.c b/fs/hfsplus/dir.c index e886ac8460d..78137007ccc 100644 --- a/fs/hfsplus/dir.c +++ b/fs/hfsplus/dir.c @@ -471,7 +471,7 @@ static int hfsplus_rename(struct inode *old_dir, struct dentry *old_dentry, return res; } -struct inode_operations hfsplus_dir_inode_operations = { +const struct inode_operations hfsplus_dir_inode_operations = { .lookup = hfsplus_lookup, .create = hfsplus_create, .link = hfsplus_link, diff --git a/fs/hfsplus/hfsplus_raw.h b/fs/hfsplus/hfsplus_raw.h index 49205531a50..fe99fe8db61 100644 --- a/fs/hfsplus/hfsplus_raw.h +++ b/fs/hfsplus/hfsplus_raw.h @@ -15,8 +15,6 @@ #include <linux/types.h> -#define __packed __attribute__ ((packed)) - /* Some constants */ #define HFSPLUS_SECTOR_SIZE 512 #define HFSPLUS_SECTOR_SHIFT 9 diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c index 75e8c4d8aac..642012ac337 100644 --- a/fs/hfsplus/inode.c +++ b/fs/hfsplus/inode.c @@ -268,10 +268,10 @@ static int hfsplus_file_release(struct inode *inode, struct file *file) return 0; } -extern struct inode_operations hfsplus_dir_inode_operations; +extern const struct inode_operations hfsplus_dir_inode_operations; extern struct file_operations hfsplus_dir_operations; -static struct inode_operations hfsplus_file_inode_operations = { +static const struct inode_operations hfsplus_file_inode_operations = { .lookup = hfsplus_file_lookup, .truncate = hfsplus_file_truncate, .permission = hfsplus_permission, diff --git a/fs/hfsplus/super.c b/fs/hfsplus/super.c index 0f513c6bf84..5a282f64c63 100644 --- a/fs/hfsplus/super.c +++ b/fs/hfsplus/super.c @@ -260,7 +260,7 @@ static int hfsplus_remount(struct super_block *sb, int *flags, char *data) return 0; } -static struct super_operations hfsplus_sops = { +static const struct super_operations hfsplus_sops = { .alloc_inode = hfsplus_alloc_inode, .destroy_inode = hfsplus_destroy_inode, .read_inode = hfsplus_read_inode, diff --git a/fs/hostfs/hostfs_kern.c b/fs/hostfs/hostfs_kern.c index 69a376f35a6..e965eb11d76 100644 --- a/fs/hostfs/hostfs_kern.c +++ b/fs/hostfs/hostfs_kern.c @@ -52,8 +52,8 @@ static int append = 0; #define HOSTFS_SUPER_MAGIC 0x00c0ffee -static struct inode_operations hostfs_iops; -static struct inode_operations hostfs_dir_iops; +static const struct inode_operations hostfs_iops; +static const struct inode_operations hostfs_dir_iops; static const struct address_space_operations hostfs_link_aops; #ifndef MODULE @@ -309,7 +309,7 @@ static void hostfs_read_inode(struct inode *inode) read_inode(inode); } -static struct super_operations hostfs_sbops = { +static const struct super_operations hostfs_sbops = { .alloc_inode = hostfs_alloc_inode, .drop_inode = generic_delete_inode, .delete_inode = hostfs_delete_inode, @@ -880,7 +880,7 @@ int hostfs_getattr(struct vfsmount *mnt, struct dentry *dentry, return(0); } -static struct inode_operations hostfs_iops = { +static const struct inode_operations hostfs_iops = { .create = hostfs_create, .link = hostfs_link, .unlink = hostfs_unlink, @@ -894,7 +894,7 @@ static struct inode_operations hostfs_iops = { .getattr = hostfs_getattr, }; -static struct inode_operations hostfs_dir_iops = { +static const struct inode_operations hostfs_dir_iops = { .create = hostfs_create, .lookup = hostfs_lookup, .link = hostfs_link, diff --git a/fs/hpfs/file.c b/fs/hpfs/file.c index fb4c8915010..b4eafc0f1e5 100644 --- a/fs/hpfs/file.c +++ b/fs/hpfs/file.c @@ -132,7 +132,7 @@ const struct file_operations hpfs_file_ops = .sendfile = generic_file_sendfile, }; -struct inode_operations hpfs_file_iops = +const struct inode_operations hpfs_file_iops = { .truncate = hpfs_truncate, .setattr = hpfs_notify_change, diff --git a/fs/hpfs/hpfs_fn.h b/fs/hpfs/hpfs_fn.h index 1c07aa82d32..42ff60ccf2a 100644 --- a/fs/hpfs/hpfs_fn.h +++ b/fs/hpfs/hpfs_fn.h @@ -266,7 +266,7 @@ void hpfs_set_ea(struct inode *, struct fnode *, char *, char *, int); int hpfs_file_fsync(struct file *, struct dentry *, int); extern const struct file_operations hpfs_file_ops; -extern struct inode_operations hpfs_file_iops; +extern const struct inode_operations hpfs_file_iops; extern const struct address_space_operations hpfs_aops; /* inode.c */ @@ -302,7 +302,7 @@ void hpfs_decide_conv(struct inode *, unsigned char *, unsigned); /* namei.c */ -extern struct inode_operations hpfs_dir_iops; +extern const struct inode_operations hpfs_dir_iops; extern const struct address_space_operations hpfs_symlink_aops; static inline struct hpfs_inode_info *hpfs_i(struct inode *inode) diff --git a/fs/hpfs/namei.c b/fs/hpfs/namei.c index 2507e7393f3..9953cf9a2f1 100644 --- a/fs/hpfs/namei.c +++ b/fs/hpfs/namei.c @@ -659,7 +659,7 @@ end1: return err; } -struct inode_operations hpfs_dir_iops = +const struct inode_operations hpfs_dir_iops = { .create = hpfs_create, .lookup = hpfs_lookup, diff --git a/fs/hpfs/super.c b/fs/hpfs/super.c index d4abc1a1d56..e0174e33852 100644 --- a/fs/hpfs/super.c +++ b/fs/hpfs/super.c @@ -426,7 +426,7 @@ static int hpfs_remount_fs(struct super_block *s, int *flags, char *data) /* Super operations */ -static struct super_operations hpfs_sops = +static const struct super_operations hpfs_sops = { .alloc_inode = hpfs_alloc_inode, .destroy_inode = hpfs_destroy_inode, diff --git a/fs/hppfs/hppfs_kern.c b/fs/hppfs/hppfs_kern.c index afd340a45da..affb7412125 100644 --- a/fs/hppfs/hppfs_kern.c +++ b/fs/hppfs/hppfs_kern.c @@ -43,7 +43,7 @@ static inline struct hppfs_inode_info *HPPFS_I(struct inode *inode) #define HPPFS_SUPER_MAGIC 0xb00000ee -static struct super_operations hppfs_sbops; +static const struct super_operations hppfs_sbops; static int is_pid(struct dentry *dentry) { @@ -212,7 +212,7 @@ static struct dentry *hppfs_lookup(struct inode *ino, struct dentry *dentry, return(ERR_PTR(err)); } -static struct inode_operations hppfs_file_iops = { +static const struct inode_operations hppfs_file_iops = { }; static ssize_t read_proc(struct file *file, char __user *buf, ssize_t count, @@ -649,7 +649,7 @@ static void hppfs_destroy_inode(struct inode *inode) kfree(HPPFS_I(inode)); } -static struct super_operations hppfs_sbops = { +static const struct super_operations hppfs_sbops = { .alloc_inode = hppfs_alloc_inode, .destroy_inode = hppfs_destroy_inode, .read_inode = hppfs_read_inode, @@ -693,11 +693,11 @@ static void* hppfs_follow_link(struct dentry *dentry, struct nameidata *nd) return ret; } -static struct inode_operations hppfs_dir_iops = { +static const struct inode_operations hppfs_dir_iops = { .lookup = hppfs_lookup, }; -static struct inode_operations hppfs_link_iops = { +static const struct inode_operations hppfs_link_iops = { .readlink = hppfs_readlink, .follow_link = hppfs_follow_link, }; diff --git a/fs/hugetlbfs/inode.c b/fs/hugetlbfs/inode.c index 4f4cd132b57..8c718a3d413 100644 --- a/fs/hugetlbfs/inode.c +++ b/fs/hugetlbfs/inode.c @@ -33,11 +33,11 @@ /* some random number */ #define HUGETLBFS_MAGIC 0x958458f6 -static struct super_operations hugetlbfs_ops; +static const struct super_operations hugetlbfs_ops; static const struct address_space_operations hugetlbfs_aops; const struct file_operations hugetlbfs_file_operations; -static struct inode_operations hugetlbfs_dir_inode_operations; -static struct inode_operations hugetlbfs_inode_operations; +static const struct inode_operations hugetlbfs_dir_inode_operations; +static const struct inode_operations hugetlbfs_inode_operations; static struct backing_dev_info hugetlbfs_backing_dev_info = { .ra_pages = 0, /* No readahead */ @@ -449,10 +449,13 @@ static int hugetlbfs_symlink(struct inode *dir, } /* - * For direct-IO reads into hugetlb pages + * mark the head page dirty */ static int hugetlbfs_set_page_dirty(struct page *page) { + struct page *head = (struct page *)page_private(page); + + SetPageDirty(head); return 0; } @@ -560,7 +563,7 @@ const struct file_operations hugetlbfs_file_operations = { .get_unmapped_area = hugetlb_get_unmapped_area, }; -static struct inode_operations hugetlbfs_dir_inode_operations = { +static const struct inode_operations hugetlbfs_dir_inode_operations = { .create = hugetlbfs_create, .lookup = simple_lookup, .link = simple_link, @@ -573,11 +576,11 @@ static struct inode_operations hugetlbfs_dir_inode_operations = { .setattr = hugetlbfs_setattr, }; -static struct inode_operations hugetlbfs_inode_operations = { +static const struct inode_operations hugetlbfs_inode_operations = { .setattr = hugetlbfs_setattr, }; -static struct super_operations hugetlbfs_ops = { +static const struct super_operations hugetlbfs_ops = { .alloc_inode = hugetlbfs_alloc_inode, .destroy_inode = hugetlbfs_destroy_inode, .statfs = hugetlbfs_statfs, diff --git a/fs/inode.c b/fs/inode.c index bf21dc6d0db..5abb097ab1b 100644 --- a/fs/inode.c +++ b/fs/inode.c @@ -414,7 +414,8 @@ static void prune_icache(int nr_to_scan) __iget(inode); spin_unlock(&inode_lock); if (remove_inode_buffers(inode)) - reap += invalidate_inode_pages(&inode->i_data); + reap += invalidate_mapping_pages(&inode->i_data, + 0, -1); iput(inode); spin_lock(&inode_lock); @@ -709,7 +710,7 @@ EXPORT_SYMBOL(iunique); struct inode *igrab(struct inode *inode) { spin_lock(&inode_lock); - if (!(inode->i_state & (I_FREEING|I_WILL_FREE))) + if (!(inode->i_state & (I_FREEING|I_CLEAR|I_WILL_FREE))) __iget(inode); else /* @@ -999,7 +1000,7 @@ EXPORT_SYMBOL(remove_inode_hash); */ void generic_delete_inode(struct inode *inode) { - struct super_operations *op = inode->i_sb->s_op; + const struct super_operations *op = inode->i_sb->s_op; list_del_init(&inode->i_list); list_del_init(&inode->i_sb_list); @@ -1092,7 +1093,7 @@ EXPORT_SYMBOL_GPL(generic_drop_inode); */ static inline void iput_final(struct inode *inode) { - struct super_operations *op = inode->i_sb->s_op; + const struct super_operations *op = inode->i_sb->s_op; void (*drop)(struct inode *) = generic_drop_inode; if (op && op->drop_inode) @@ -1112,7 +1113,7 @@ static inline void iput_final(struct inode *inode) void iput(struct inode *inode) { if (inode) { - struct super_operations *op = inode->i_sb->s_op; + const struct super_operations *op = inode->i_sb->s_op; BUG_ON(inode->i_state == I_CLEAR); @@ -1160,11 +1161,9 @@ void touch_atime(struct vfsmount *mnt, struct dentry *dentry) struct inode *inode = dentry->d_inode; struct timespec now; - if (IS_RDONLY(inode)) - return; if (inode->i_flags & S_NOATIME) return; - if (inode->i_sb->s_flags & MS_NOATIME) + if (IS_NOATIME(inode)) return; if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode)) return; @@ -1252,33 +1251,6 @@ int inode_needs_sync(struct inode *inode) EXPORT_SYMBOL(inode_needs_sync); -/* - * Quota functions that want to walk the inode lists.. - */ -#ifdef CONFIG_QUOTA - -void remove_dquot_ref(struct super_block *sb, int type, - struct list_head *tofree_head) -{ - struct inode *inode; - - if (!sb->dq_op) - return; /* nothing to do */ - spin_lock(&inode_lock); /* This lock is for inodes code */ - - /* - * We don't have to lock against quota code - test IS_QUOTAINIT is - * just for speedup... - */ - list_for_each_entry(inode, &sb->s_inodes, i_sb_list) - if (!IS_NOQUOTA(inode)) - remove_inode_dquot_ref(inode, type, tofree_head); - - spin_unlock(&inode_lock); -} - -#endif - int inode_wait(void *word) { schedule(); diff --git a/fs/inotify_user.c b/fs/inotify_user.c index 55f6da55b7c..9f2224f65a1 100644 --- a/fs/inotify_user.c +++ b/fs/inotify_user.c @@ -455,8 +455,16 @@ static ssize_t inotify_read(struct file *file, char __user *buf, break; kevent = inotify_dev_get_event(dev); - if (event_size + kevent->event.len > count) + if (event_size + kevent->event.len > count) { + if (ret == 0 && count > 0) { + /* + * could not get a single event because we + * didn't have enough buffer space. + */ + ret = -EINVAL; + } break; + } if (copy_to_user(buf, &kevent->event, event_size)) { ret = -EFAULT; diff --git a/fs/ioprio.c b/fs/ioprio.c index 89e8da112a7..10d2c211d18 100644 --- a/fs/ioprio.c +++ b/fs/ioprio.c @@ -60,6 +60,7 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio) int data = IOPRIO_PRIO_DATA(ioprio); struct task_struct *p, *g; struct user_struct *user; + struct pid *pgrp; int ret; switch (class) { @@ -98,12 +99,14 @@ asmlinkage long sys_ioprio_set(int which, int who, int ioprio) break; case IOPRIO_WHO_PGRP: if (!who) - who = process_group(current); - do_each_task_pid(who, PIDTYPE_PGID, p) { + pgrp = task_pgrp(current); + else + pgrp = find_pid(who); + do_each_pid_task(pgrp, PIDTYPE_PGID, p) { ret = set_task_ioprio(p, ioprio); if (ret) break; - } while_each_task_pid(who, PIDTYPE_PGID, p); + } while_each_pid_task(pgrp, PIDTYPE_PGID, p); break; case IOPRIO_WHO_USER: if (!who) @@ -167,6 +170,7 @@ asmlinkage long sys_ioprio_get(int which, int who) { struct task_struct *g, *p; struct user_struct *user; + struct pid *pgrp; int ret = -ESRCH; int tmpio; @@ -182,8 +186,10 @@ asmlinkage long sys_ioprio_get(int which, int who) break; case IOPRIO_WHO_PGRP: if (!who) - who = process_group(current); - do_each_task_pid(who, PIDTYPE_PGID, p) { + pgrp = task_pgrp(current); + else + pgrp = find_pid(who); + do_each_pid_task(pgrp, PIDTYPE_PGID, p) { tmpio = get_task_ioprio(p); if (tmpio < 0) continue; @@ -191,7 +197,7 @@ asmlinkage long sys_ioprio_get(int which, int who) ret = tmpio; else ret = ioprio_best(ret, tmpio); - } while_each_task_pid(who, PIDTYPE_PGID, p); + } while_each_pid_task(pgrp, PIDTYPE_PGID, p); break; case IOPRIO_WHO_USER: if (!who) diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c index 4af2548f97a..0e94c31cad9 100644 --- a/fs/isofs/dir.c +++ b/fs/isofs/dir.c @@ -24,7 +24,7 @@ const struct file_operations isofs_dir_operations = /* * directories can handle most operations... */ -struct inode_operations isofs_dir_inode_operations = +const struct inode_operations isofs_dir_inode_operations = { .lookup = isofs_lookup, }; diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index ea55b6c469e..64a96cdfe3a 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -106,7 +106,7 @@ static int isofs_remount(struct super_block *sb, int *flags, char *data) return 0; } -static struct super_operations isofs_sops = { +static const struct super_operations isofs_sops = { .alloc_inode = isofs_alloc_inode, .destroy_inode = isofs_destroy_inode, .read_inode = isofs_read_inode, diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h index e6308c8b573..efe2872cd4e 100644 --- a/fs/isofs/isofs.h +++ b/fs/isofs/isofs.h @@ -174,7 +174,7 @@ isofs_normalize_block_and_offset(struct iso_directory_record* de, } } -extern struct inode_operations isofs_dir_inode_operations; +extern const struct inode_operations isofs_dir_inode_operations; extern const struct file_operations isofs_dir_operations; extern const struct address_space_operations isofs_symlink_aops; extern struct export_operations isofs_export_ops; diff --git a/fs/jffs/inode-v23.c b/fs/jffs/inode-v23.c index 43baa1afa02..9602b925da0 100644 --- a/fs/jffs/inode-v23.c +++ b/fs/jffs/inode-v23.c @@ -54,11 +54,11 @@ static int jffs_remove(struct inode *dir, struct dentry *dentry, int type); -static struct super_operations jffs_ops; +static const struct super_operations jffs_ops; static const struct file_operations jffs_file_operations; -static struct inode_operations jffs_file_inode_operations; +static const struct inode_operations jffs_file_inode_operations; static const struct file_operations jffs_dir_operations; -static struct inode_operations jffs_dir_inode_operations; +static const struct inode_operations jffs_dir_inode_operations; static const struct address_space_operations jffs_address_operations; struct kmem_cache *node_cache = NULL; @@ -296,7 +296,7 @@ jffs_setattr(struct dentry *dentry, struct iattr *iattr) inode->i_blocks = (inode->i_size + 511) >> 9; if (len) { - invalidate_inode_pages(inode->i_mapping); + invalidate_mapping_pages(inode->i_mapping, 0, -1); } inode->i_ctime = CURRENT_TIME_SEC; inode->i_mtime = inode->i_ctime; @@ -1518,7 +1518,7 @@ jffs_file_write(struct file *filp, const char *buf, size_t count, } inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; mark_inode_dirty(inode); - invalidate_inode_pages(inode->i_mapping); + invalidate_mapping_pages(inode->i_mapping, 0, -1); out_isem: return err; @@ -1642,7 +1642,7 @@ static const struct file_operations jffs_file_operations = }; -static struct inode_operations jffs_file_inode_operations = +static const struct inode_operations jffs_file_inode_operations = { .lookup = jffs_lookup, /* lookup */ .setattr = jffs_setattr, @@ -1655,7 +1655,7 @@ static const struct file_operations jffs_dir_operations = }; -static struct inode_operations jffs_dir_inode_operations = +static const struct inode_operations jffs_dir_inode_operations = { .create = jffs_create, .lookup = jffs_lookup, @@ -1774,7 +1774,7 @@ static int jffs_remount(struct super_block *sb, int *flags, char *data) return 0; } -static struct super_operations jffs_ops = +static const struct super_operations jffs_ops = { .read_inode = jffs_read_inode, .delete_inode = jffs_delete_inode, diff --git a/fs/jffs2/dir.c b/fs/jffs2/dir.c index da6034d5071..cdbe2fe14e2 100644 --- a/fs/jffs2/dir.c +++ b/fs/jffs2/dir.c @@ -46,7 +46,7 @@ const struct file_operations jffs2_dir_operations = }; -struct inode_operations jffs2_dir_inode_operations = +const struct inode_operations jffs2_dir_inode_operations = { .create = jffs2_create, .lookup = jffs2_lookup, diff --git a/fs/jffs2/file.c b/fs/jffs2/file.c index 242875f77cb..e82eeaf7590 100644 --- a/fs/jffs2/file.c +++ b/fs/jffs2/file.c @@ -54,7 +54,7 @@ const struct file_operations jffs2_file_operations = /* jffs2_file_inode_operations */ -struct inode_operations jffs2_file_inode_operations = +const struct inode_operations jffs2_file_inode_operations = { .permission = jffs2_permission, .setattr = jffs2_setattr, diff --git a/fs/jffs2/os-linux.h b/fs/jffs2/os-linux.h index 9f41fc01a37..e07a0edcdb4 100644 --- a/fs/jffs2/os-linux.h +++ b/fs/jffs2/os-linux.h @@ -153,11 +153,11 @@ void jffs2_garbage_collect_trigger(struct jffs2_sb_info *c); /* dir.c */ extern const struct file_operations jffs2_dir_operations; -extern struct inode_operations jffs2_dir_inode_operations; +extern const struct inode_operations jffs2_dir_inode_operations; /* file.c */ extern const struct file_operations jffs2_file_operations; -extern struct inode_operations jffs2_file_inode_operations; +extern const struct inode_operations jffs2_file_inode_operations; extern const struct address_space_operations jffs2_file_address_operations; int jffs2_fsync(struct file *, struct dentry *, int); int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg); @@ -166,7 +166,7 @@ int jffs2_do_readpage_unlock (struct inode *inode, struct page *pg); int jffs2_ioctl(struct inode *, struct file *, unsigned int, unsigned long); /* symlink.c */ -extern struct inode_operations jffs2_symlink_inode_operations; +extern const struct inode_operations jffs2_symlink_inode_operations; /* fs.c */ int jffs2_setattr (struct dentry *, struct iattr *); diff --git a/fs/jffs2/super.c b/fs/jffs2/super.c index 08a0e6c49e6..cc7e8e71ad4 100644 --- a/fs/jffs2/super.c +++ b/fs/jffs2/super.c @@ -66,7 +66,7 @@ static int jffs2_sync_fs(struct super_block *sb, int wait) return 0; } -static struct super_operations jffs2_super_operations = +static const struct super_operations jffs2_super_operations = { .alloc_inode = jffs2_alloc_inode, .destroy_inode =jffs2_destroy_inode, diff --git a/fs/jffs2/symlink.c b/fs/jffs2/symlink.c index b90d5aa3d96..7e4882c8a7e 100644 --- a/fs/jffs2/symlink.c +++ b/fs/jffs2/symlink.c @@ -20,7 +20,7 @@ static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd); -struct inode_operations jffs2_symlink_inode_operations = +const struct inode_operations jffs2_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = jffs2_follow_link, diff --git a/fs/jfs/file.c b/fs/jfs/file.c index aa9132d0492..f7f8eff19b7 100644 --- a/fs/jfs/file.c +++ b/fs/jfs/file.c @@ -88,7 +88,7 @@ static int jfs_release(struct inode *inode, struct file *file) return 0; } -struct inode_operations jfs_file_inode_operations = { +const struct inode_operations jfs_file_inode_operations = { .truncate = jfs_truncate, .setxattr = jfs_setxattr, .getxattr = jfs_getxattr, diff --git a/fs/jfs/jfs_inode.h b/fs/jfs/jfs_inode.h index 0d06ccfaff0..6802837f757 100644 --- a/fs/jfs/jfs_inode.h +++ b/fs/jfs/jfs_inode.h @@ -35,10 +35,10 @@ extern void jfs_set_inode_flags(struct inode *); extern int jfs_get_block(struct inode *, sector_t, struct buffer_head *, int); extern const struct address_space_operations jfs_aops; -extern struct inode_operations jfs_dir_inode_operations; +extern const struct inode_operations jfs_dir_inode_operations; extern const struct file_operations jfs_dir_operations; -extern struct inode_operations jfs_file_inode_operations; +extern const struct inode_operations jfs_file_inode_operations; extern const struct file_operations jfs_file_operations; -extern struct inode_operations jfs_symlink_inode_operations; +extern const struct inode_operations jfs_symlink_inode_operations; extern struct dentry_operations jfs_ci_dentry_operations; #endif /* _H_JFS_INODE */ diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c index 7ab47561b68..41c20477126 100644 --- a/fs/jfs/namei.c +++ b/fs/jfs/namei.c @@ -1503,7 +1503,7 @@ struct dentry *jfs_get_parent(struct dentry *dentry) return parent; } -struct inode_operations jfs_dir_inode_operations = { +const struct inode_operations jfs_dir_inode_operations = { .create = jfs_create, .lookup = jfs_lookup, .link = jfs_link, diff --git a/fs/jfs/super.c b/fs/jfs/super.c index 846ac8f3451..52d73d54a93 100644 --- a/fs/jfs/super.c +++ b/fs/jfs/super.c @@ -46,7 +46,7 @@ MODULE_LICENSE("GPL"); static struct kmem_cache * jfs_inode_cachep; -static struct super_operations jfs_super_operations; +static const struct super_operations jfs_super_operations; static struct export_operations jfs_export_operations; static struct file_system_type jfs_fs_type; @@ -716,7 +716,7 @@ out: #endif -static struct super_operations jfs_super_operations = { +static const struct super_operations jfs_super_operations = { .alloc_inode = jfs_alloc_inode, .destroy_inode = jfs_destroy_inode, .read_inode = jfs_read_inode, diff --git a/fs/jfs/symlink.c b/fs/jfs/symlink.c index cee43f36f51..4af1a05aad0 100644 --- a/fs/jfs/symlink.c +++ b/fs/jfs/symlink.c @@ -29,7 +29,7 @@ static void *jfs_follow_link(struct dentry *dentry, struct nameidata *nd) return NULL; } -struct inode_operations jfs_symlink_inode_operations = { +const struct inode_operations jfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = jfs_follow_link, .setxattr = jfs_setxattr, diff --git a/fs/libfs.c b/fs/libfs.c index 503898d5c4a..7d487047dbb 100644 --- a/fs/libfs.c +++ b/fs/libfs.c @@ -186,7 +186,7 @@ const struct file_operations simple_dir_operations = { .fsync = simple_sync_file, }; -struct inode_operations simple_dir_inode_operations = { +const struct inode_operations simple_dir_inode_operations = { .lookup = simple_lookup, }; @@ -195,11 +195,11 @@ struct inode_operations simple_dir_inode_operations = { * will never be mountable) */ int get_sb_pseudo(struct file_system_type *fs_type, char *name, - struct super_operations *ops, unsigned long magic, + const struct super_operations *ops, unsigned long magic, struct vfsmount *mnt) { struct super_block *s = sget(fs_type, NULL, set_anon_super, NULL); - static struct super_operations default_ops = {.statfs = simple_statfs}; + static const struct super_operations default_ops = {.statfs = simple_statfs}; struct dentry *dentry; struct inode *root; struct qstr d_name = {.name = name, .len = strlen(name)}; diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 3d4610c2a26..22d40320897 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -192,7 +192,7 @@ struct nlm_host * nlmsvc_lookup_host(struct svc_rqst *rqstp, const char *hostname, int hostname_len) { - return nlm_lookup_host(1, &rqstp->rq_addr, + return nlm_lookup_host(1, svc_addr_in(rqstp), rqstp->rq_prot, rqstp->rq_vers, hostname, hostname_len); } diff --git a/fs/lockd/svc.c b/fs/lockd/svc.c index 8ca18085e68..80fcacc1acf 100644 --- a/fs/lockd/svc.c +++ b/fs/lockd/svc.c @@ -141,6 +141,7 @@ lockd(struct svc_rqst *rqstp) */ while ((nlmsvc_users || !signalled()) && nlmsvc_pid == current->pid) { long timeout = MAX_SCHEDULE_TIMEOUT; + char buf[RPC_MAX_ADDRBUFLEN]; if (signalled()) { flush_signals(current); @@ -175,11 +176,10 @@ lockd(struct svc_rqst *rqstp) break; } - dprintk("lockd: request from %08x\n", - (unsigned)ntohl(rqstp->rq_addr.sin_addr.s_addr)); + dprintk("lockd: request from %s\n", + svc_print_addr(rqstp, buf, sizeof(buf))); svc_process(rqstp); - } flush_signals(current); @@ -223,23 +223,29 @@ static int find_socket(struct svc_serv *serv, int proto) return found; } +/* + * Make any sockets that are needed but not present. + * If nlm_udpport or nlm_tcpport were set as module + * options, make those sockets unconditionally + */ static int make_socks(struct svc_serv *serv, int proto) { - /* Make any sockets that are needed but not present. - * If nlm_udpport or nlm_tcpport were set as module - * options, make those sockets unconditionally - */ - static int warned; + static int warned; int err = 0; + if (proto == IPPROTO_UDP || nlm_udpport) if (!find_socket(serv, IPPROTO_UDP)) - err = svc_makesock(serv, IPPROTO_UDP, nlm_udpport); - if (err == 0 && (proto == IPPROTO_TCP || nlm_tcpport)) + err = svc_makesock(serv, IPPROTO_UDP, nlm_udpport, + SVC_SOCK_DEFAULTS); + if (err >= 0 && (proto == IPPROTO_TCP || nlm_tcpport)) if (!find_socket(serv, IPPROTO_TCP)) - err= svc_makesock(serv, IPPROTO_TCP, nlm_tcpport); - if (!err) + err = svc_makesock(serv, IPPROTO_TCP, nlm_tcpport, + SVC_SOCK_DEFAULTS); + + if (err >= 0) { warned = 0; - else if (warned++ == 0) + err = 0; + } else if (warned++ == 0) printk(KERN_WARNING "lockd_up: makesock failed, error=%d\n", err); return err; diff --git a/fs/lockd/svc4proc.c b/fs/lockd/svc4proc.c index f67146a8199..47a66aa5d55 100644 --- a/fs/lockd/svc4proc.c +++ b/fs/lockd/svc4proc.c @@ -224,7 +224,7 @@ nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp, resp->cookie = argp->cookie; dprintk("lockd: GRANTED called\n"); - resp->status = nlmclnt_grant(&rqstp->rq_addr, &argp->lock); + resp->status = nlmclnt_grant(svc_addr_in(rqstp), &argp->lock); dprintk("lockd: GRANTED status %d\n", ntohl(resp->status)); return rpc_success; } @@ -421,15 +421,16 @@ static __be32 nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, void *resp) { - struct sockaddr_in saddr = rqstp->rq_addr; + struct sockaddr_in saddr; + + memcpy(&saddr, svc_addr_in(rqstp), sizeof(saddr)); dprintk("lockd: SM_NOTIFY called\n"); if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK) || ntohs(saddr.sin_port) >= 1024) { - printk(KERN_WARNING - "lockd: rejected NSM callback from %08x:%d\n", - ntohl(rqstp->rq_addr.sin_addr.s_addr), - ntohs(rqstp->rq_addr.sin_port)); + char buf[RPC_MAX_ADDRBUFLEN]; + printk(KERN_WARNING "lockd: rejected NSM callback from %s\n", + svc_print_addr(rqstp, buf, sizeof(buf))); return rpc_system_err; } diff --git a/fs/lockd/svcproc.c b/fs/lockd/svcproc.c index 3707c3a23e9..31cb4842573 100644 --- a/fs/lockd/svcproc.c +++ b/fs/lockd/svcproc.c @@ -253,7 +253,7 @@ nlmsvc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp, resp->cookie = argp->cookie; dprintk("lockd: GRANTED called\n"); - resp->status = nlmclnt_grant(&rqstp->rq_addr, &argp->lock); + resp->status = nlmclnt_grant(svc_addr_in(rqstp), &argp->lock); dprintk("lockd: GRANTED status %d\n", ntohl(resp->status)); return rpc_success; } @@ -452,15 +452,16 @@ static __be32 nlmsvc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp, void *resp) { - struct sockaddr_in saddr = rqstp->rq_addr; + struct sockaddr_in saddr; + + memcpy(&saddr, svc_addr_in(rqstp), sizeof(saddr)); dprintk("lockd: SM_NOTIFY called\n"); if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK) || ntohs(saddr.sin_port) >= 1024) { - printk(KERN_WARNING - "lockd: rejected NSM callback from %08x:%d\n", - ntohl(rqstp->rq_addr.sin_addr.s_addr), - ntohs(rqstp->rq_addr.sin_port)); + char buf[RPC_MAX_ADDRBUFLEN]; + printk(KERN_WARNING "lockd: rejected NSM callback from %s\n", + svc_print_addr(rqstp, buf, sizeof(buf))); return rpc_system_err; } diff --git a/fs/minix/bitmap.c b/fs/minix/bitmap.c index df6b1075b54..c4a554df7b7 100644 --- a/fs/minix/bitmap.c +++ b/fs/minix/bitmap.c @@ -26,14 +26,14 @@ static unsigned long count_free(struct buffer_head *map[], unsigned numblocks, _ for (i=0; i<numblocks-1; i++) { if (!(bh=map[i])) return(0); - for (j=0; j<BLOCK_SIZE; j++) + for (j=0; j<bh->b_size; j++) sum += nibblemap[bh->b_data[j] & 0xf] + nibblemap[(bh->b_data[j]>>4) & 0xf]; } if (numblocks==0 || !(bh=map[numblocks-1])) return(0); - i = ((numbits-(numblocks-1)*BLOCK_SIZE*8)/16)*2; + i = ((numbits - (numblocks-1) * bh->b_size * 8) / 16) * 2; for (j=0; j<i; j++) { sum += nibblemap[bh->b_data[j] & 0xf] + nibblemap[(bh->b_data[j]>>4) & 0xf]; @@ -48,28 +48,29 @@ static unsigned long count_free(struct buffer_head *map[], unsigned numblocks, _ return(sum); } -void minix_free_block(struct inode * inode, int block) +void minix_free_block(struct inode *inode, unsigned long block) { - struct super_block * sb = inode->i_sb; - struct minix_sb_info * sbi = minix_sb(sb); - struct buffer_head * bh; - unsigned int bit,zone; + struct super_block *sb = inode->i_sb; + struct minix_sb_info *sbi = minix_sb(sb); + struct buffer_head *bh; + int k = sb->s_blocksize_bits + 3; + unsigned long bit, zone; if (block < sbi->s_firstdatazone || block >= sbi->s_nzones) { printk("Trying to free block not in datazone\n"); return; } zone = block - sbi->s_firstdatazone + 1; - bit = zone & 8191; - zone >>= 13; + bit = zone & ((1<<k) - 1); + zone >>= k; if (zone >= sbi->s_zmap_blocks) { printk("minix_free_block: nonexistent bitmap buffer\n"); return; } bh = sbi->s_zmap[zone]; lock_kernel(); - if (!minix_test_and_clear_bit(bit,bh->b_data)) - printk("free_block (%s:%d): bit already cleared\n", + if (!minix_test_and_clear_bit(bit, bh->b_data)) + printk("minix_free_block (%s:%lu): bit already cleared\n", sb->s_id, block); unlock_kernel(); mark_buffer_dirty(bh); @@ -79,6 +80,7 @@ void minix_free_block(struct inode * inode, int block) int minix_new_block(struct inode * inode) { struct minix_sb_info *sbi = minix_sb(inode->i_sb); + int bits_per_zone = 8 * inode->i_sb->s_blocksize; int i; for (i = 0; i < sbi->s_zmap_blocks; i++) { @@ -86,11 +88,12 @@ int minix_new_block(struct inode * inode) int j; lock_kernel(); - if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192) { - minix_set_bit(j,bh->b_data); + j = minix_find_first_zero_bit(bh->b_data, bits_per_zone); + if (j < bits_per_zone) { + minix_set_bit(j, bh->b_data); unlock_kernel(); mark_buffer_dirty(bh); - j += i*8192 + sbi->s_firstdatazone-1; + j += i * bits_per_zone + sbi->s_firstdatazone-1; if (j < sbi->s_firstdatazone || j >= sbi->s_nzones) break; return j; @@ -137,6 +140,7 @@ minix_V2_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh) int block; struct minix_sb_info *sbi = minix_sb(sb); struct minix2_inode *p; + int minix2_inodes_per_block = sb->s_blocksize / sizeof(struct minix2_inode); *bh = NULL; if (!ino || ino > sbi->s_ninodes) { @@ -146,14 +150,14 @@ minix_V2_raw_inode(struct super_block *sb, ino_t ino, struct buffer_head **bh) } ino--; block = 2 + sbi->s_imap_blocks + sbi->s_zmap_blocks + - ino / MINIX2_INODES_PER_BLOCK; + ino / minix2_inodes_per_block; *bh = sb_bread(sb, block); if (!*bh) { printk("Unable to read inode block\n"); return NULL; } p = (void *)(*bh)->b_data; - return p + ino % MINIX2_INODES_PER_BLOCK; + return p + ino % minix2_inodes_per_block; } /* Clear the link count and mode of a deleted inode on disk. */ @@ -185,26 +189,30 @@ static void minix_clear_inode(struct inode *inode) void minix_free_inode(struct inode * inode) { + struct super_block *sb = inode->i_sb; struct minix_sb_info *sbi = minix_sb(inode->i_sb); - struct buffer_head * bh; - unsigned long ino; + struct buffer_head *bh; + int k = sb->s_blocksize_bits + 3; + unsigned long ino, bit; ino = inode->i_ino; if (ino < 1 || ino > sbi->s_ninodes) { printk("minix_free_inode: inode 0 or nonexistent inode\n"); goto out; } - if ((ino >> 13) >= sbi->s_imap_blocks) { + bit = ino & ((1<<k) - 1); + ino >>= k; + if (ino >= sbi->s_imap_blocks) { printk("minix_free_inode: nonexistent imap in superblock\n"); goto out; } minix_clear_inode(inode); /* clear on-disk copy */ - bh = sbi->s_imap[ino >> 13]; + bh = sbi->s_imap[ino]; lock_kernel(); - if (!minix_test_and_clear_bit(ino & 8191, bh->b_data)) - printk("minix_free_inode: bit %lu already cleared\n", ino); + if (!minix_test_and_clear_bit(bit, bh->b_data)) + printk("minix_free_inode: bit %lu already cleared\n", bit); unlock_kernel(); mark_buffer_dirty(bh); out: @@ -217,35 +225,38 @@ struct inode * minix_new_inode(const struct inode * dir, int * error) struct minix_sb_info *sbi = minix_sb(sb); struct inode *inode = new_inode(sb); struct buffer_head * bh; - int i,j; + int bits_per_zone = 8 * sb->s_blocksize; + unsigned long j; + int i; if (!inode) { *error = -ENOMEM; return NULL; } - j = 8192; + j = bits_per_zone; bh = NULL; *error = -ENOSPC; lock_kernel(); for (i = 0; i < sbi->s_imap_blocks; i++) { bh = sbi->s_imap[i]; - if ((j = minix_find_first_zero_bit(bh->b_data, 8192)) < 8192) + j = minix_find_first_zero_bit(bh->b_data, bits_per_zone); + if (j < bits_per_zone) break; } - if (!bh || j >= 8192) { + if (!bh || j >= bits_per_zone) { unlock_kernel(); iput(inode); return NULL; } - if (minix_test_and_set_bit(j,bh->b_data)) { /* shouldn't happen */ - printk("new_inode: bit already set\n"); + if (minix_test_and_set_bit(j, bh->b_data)) { /* shouldn't happen */ unlock_kernel(); + printk("minix_new_inode: bit already set\n"); iput(inode); return NULL; } unlock_kernel(); mark_buffer_dirty(bh); - j += i*8192; + j += i * bits_per_zone; if (!j || j > sbi->s_ninodes) { iput(inode); return NULL; diff --git a/fs/minix/dir.c b/fs/minix/dir.c index ab782c4086f..cb4cb571fdd 100644 --- a/fs/minix/dir.c +++ b/fs/minix/dir.c @@ -4,6 +4,8 @@ * Copyright (C) 1991, 1992 Linus Torvalds * * minix directory handling functions + * + * Updated to filesystem version 3 by Daniel Aragones */ #include "minix.h" @@ -11,6 +13,7 @@ #include <linux/smp_lock.h> typedef struct minix_dir_entry minix_dirent; +typedef struct minix3_dir_entry minix3_dirent; static int minix_readdir(struct file *, void *, filldir_t); @@ -89,6 +92,8 @@ static int minix_readdir(struct file * filp, void * dirent, filldir_t filldir) unsigned long npages = dir_pages(inode); struct minix_sb_info *sbi = minix_sb(sb); unsigned chunk_size = sbi->s_dirsize; + char *name; + __u32 inumber; lock_kernel(); @@ -105,16 +110,24 @@ static int minix_readdir(struct file * filp, void * dirent, filldir_t filldir) kaddr = (char *)page_address(page); p = kaddr+offset; limit = kaddr + minix_last_byte(inode, n) - chunk_size; - for ( ; p <= limit ; p = minix_next_entry(p, sbi)) { - minix_dirent *de = (minix_dirent *)p; - if (de->inode) { + for ( ; p <= limit; p = minix_next_entry(p, sbi)) { + if (sbi->s_version == MINIX_V3) { + minix3_dirent *de3 = (minix3_dirent *)p; + name = de3->name; + inumber = de3->inode; + } else { + minix_dirent *de = (minix_dirent *)p; + name = de->name; + inumber = de->inode; + } + if (inumber) { int over; - unsigned l = strnlen(de->name,sbi->s_namelen); + unsigned l = strnlen(name, sbi->s_namelen); offset = p - kaddr; - over = filldir(dirent, de->name, l, - (n<<PAGE_CACHE_SHIFT) | offset, - de->inode, DT_UNKNOWN); + over = filldir(dirent, name, l, + (n << PAGE_CACHE_SHIFT) | offset, + inumber, DT_UNKNOWN); if (over) { dir_put_page(page); goto done; @@ -156,23 +169,34 @@ minix_dirent *minix_find_entry(struct dentry *dentry, struct page **res_page) unsigned long n; unsigned long npages = dir_pages(dir); struct page *page = NULL; - struct minix_dir_entry *de; + char *p; + char *namx; + __u32 inumber; *res_page = NULL; for (n = 0; n < npages; n++) { - char *kaddr; + char *kaddr, *limit; + page = dir_get_page(dir, n); if (IS_ERR(page)) continue; kaddr = (char*)page_address(page); - de = (struct minix_dir_entry *) kaddr; - kaddr += minix_last_byte(dir, n) - sbi->s_dirsize; - for ( ; (char *) de <= kaddr ; de = minix_next_entry(de,sbi)) { - if (!de->inode) + limit = kaddr + minix_last_byte(dir, n) - sbi->s_dirsize; + for (p = kaddr; p <= limit; p = minix_next_entry(p, sbi)) { + if (sbi->s_version == MINIX_V3) { + minix3_dirent *de3 = (minix3_dirent *)p; + namx = de3->name; + inumber = de3->inode; + } else { + minix_dirent *de = (minix_dirent *)p; + namx = de->name; + inumber = de->inode; + } + if (!inumber) continue; - if (namecompare(namelen,sbi->s_namelen,name,de->name)) + if (namecompare(namelen, sbi->s_namelen, name, namx)) goto found; } dir_put_page(page); @@ -181,7 +205,7 @@ minix_dirent *minix_find_entry(struct dentry *dentry, struct page **res_page) found: *res_page = page; - return de; + return (minix_dirent *)p; } int minix_add_link(struct dentry *dentry, struct inode *inode) @@ -192,12 +216,15 @@ int minix_add_link(struct dentry *dentry, struct inode *inode) struct super_block * sb = dir->i_sb; struct minix_sb_info * sbi = minix_sb(sb); struct page *page = NULL; - struct minix_dir_entry * de; unsigned long npages = dir_pages(dir); unsigned long n; - char *kaddr; + char *kaddr, *p; + minix_dirent *de; + minix3_dirent *de3; unsigned from, to; int err; + char *namx = NULL; + __u32 inumber; /* * We take care of directory expansion in the same loop @@ -205,7 +232,7 @@ int minix_add_link(struct dentry *dentry, struct inode *inode) * to protect that region. */ for (n = 0; n <= npages; n++) { - char *dir_end; + char *limit, *dir_end; page = dir_get_page(dir, n); err = PTR_ERR(page); @@ -214,20 +241,30 @@ int minix_add_link(struct dentry *dentry, struct inode *inode) lock_page(page); kaddr = (char*)page_address(page); dir_end = kaddr + minix_last_byte(dir, n); - de = (minix_dirent *)kaddr; - kaddr += PAGE_CACHE_SIZE - sbi->s_dirsize; - while ((char *)de <= kaddr) { - if ((char *)de == dir_end) { + limit = kaddr + PAGE_CACHE_SIZE - sbi->s_dirsize; + for (p = kaddr; p <= limit; p = minix_next_entry(p, sbi)) { + de = (minix_dirent *)p; + de3 = (minix3_dirent *)p; + if (sbi->s_version == MINIX_V3) { + namx = de3->name; + inumber = de3->inode; + } else { + namx = de->name; + inumber = de->inode; + } + if (p == dir_end) { /* We hit i_size */ - de->inode = 0; + if (sbi->s_version == MINIX_V3) + de3->inode = 0; + else + de->inode = 0; goto got_it; } - if (!de->inode) + if (!inumber) goto got_it; err = -EEXIST; - if (namecompare(namelen,sbi->s_namelen,name,de->name)) + if (namecompare(namelen, sbi->s_namelen, name, namx)) goto out_unlock; - de = minix_next_entry(de, sbi); } unlock_page(page); dir_put_page(page); @@ -236,14 +273,19 @@ int minix_add_link(struct dentry *dentry, struct inode *inode) return -EINVAL; got_it: - from = (char*)de - (char*)page_address(page); + from = p - (char*)page_address(page); to = from + sbi->s_dirsize; err = page->mapping->a_ops->prepare_write(NULL, page, from, to); if (err) goto out_unlock; - memcpy (de->name, name, namelen); - memset (de->name + namelen, 0, sbi->s_dirsize - namelen - 2); - de->inode = inode->i_ino; + memcpy (namx, name, namelen); + if (sbi->s_version == MINIX_V3) { + memset (namx + namelen, 0, sbi->s_dirsize - namelen - 4); + de3->inode = inode->i_ino; + } else { + memset (namx + namelen, 0, sbi->s_dirsize - namelen - 2); + de->inode = inode->i_ino; + } err = dir_commit_chunk(page, from, to); dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(dir); @@ -283,8 +325,7 @@ int minix_make_empty(struct inode *inode, struct inode *dir) { struct address_space *mapping = inode->i_mapping; struct page *page = grab_cache_page(mapping, 0); - struct minix_sb_info * sbi = minix_sb(inode->i_sb); - struct minix_dir_entry * de; + struct minix_sb_info *sbi = minix_sb(inode->i_sb); char *kaddr; int err; @@ -299,12 +340,23 @@ int minix_make_empty(struct inode *inode, struct inode *dir) kaddr = kmap_atomic(page, KM_USER0); memset(kaddr, 0, PAGE_CACHE_SIZE); - de = (struct minix_dir_entry *)kaddr; - de->inode = inode->i_ino; - strcpy(de->name,"."); - de = minix_next_entry(de, sbi); - de->inode = dir->i_ino; - strcpy(de->name,".."); + if (sbi->s_version == MINIX_V3) { + minix3_dirent *de3 = (minix3_dirent *)kaddr; + + de3->inode = inode->i_ino; + strcpy(de3->name, "."); + de3 = minix_next_entry(de3, sbi); + de3->inode = dir->i_ino; + strcpy(de3->name, ".."); + } else { + minix_dirent *de = (minix_dirent *)kaddr; + + de->inode = inode->i_ino; + strcpy(de->name, "."); + de = minix_next_entry(de, sbi); + de->inode = dir->i_ino; + strcpy(de->name, ".."); + } kunmap_atomic(kaddr, KM_USER0); err = dir_commit_chunk(page, 0, 2 * sbi->s_dirsize); @@ -321,33 +373,41 @@ int minix_empty_dir(struct inode * inode) struct page *page = NULL; unsigned long i, npages = dir_pages(inode); struct minix_sb_info *sbi = minix_sb(inode->i_sb); + char *name; + __u32 inumber; for (i = 0; i < npages; i++) { - char *kaddr; - minix_dirent * de; - page = dir_get_page(inode, i); + char *p, *kaddr, *limit; + page = dir_get_page(inode, i); if (IS_ERR(page)) continue; kaddr = (char *)page_address(page); - de = (minix_dirent *)kaddr; - kaddr += minix_last_byte(inode, i) - sbi->s_dirsize; + limit = kaddr + minix_last_byte(inode, i) - sbi->s_dirsize; + for (p = kaddr; p <= limit; p = minix_next_entry(p, sbi)) { + if (sbi->s_version == MINIX_V3) { + minix3_dirent *de3 = (minix3_dirent *)p; + name = de3->name; + inumber = de3->inode; + } else { + minix_dirent *de = (minix_dirent *)p; + name = de->name; + inumber = de->inode; + } - while ((char *)de <= kaddr) { - if (de->inode != 0) { + if (inumber != 0) { /* check for . and .. */ - if (de->name[0] != '.') + if (name[0] != '.') goto not_empty; - if (!de->name[1]) { - if (de->inode != inode->i_ino) + if (!name[1]) { + if (inumber != inode->i_ino) goto not_empty; - } else if (de->name[1] != '.') + } else if (name[1] != '.') goto not_empty; - else if (de->name[2]) + else if (name[2]) goto not_empty; } - de = minix_next_entry(de, sbi); } dir_put_page(page); } diff --git a/fs/minix/file.c b/fs/minix/file.c index 40eac2e60d2..f92baa1d757 100644 --- a/fs/minix/file.c +++ b/fs/minix/file.c @@ -26,7 +26,7 @@ const struct file_operations minix_file_operations = { .sendfile = generic_file_sendfile, }; -struct inode_operations minix_file_inode_operations = { +const struct inode_operations minix_file_inode_operations = { .truncate = minix_truncate, .getattr = minix_getattr, }; diff --git a/fs/minix/inode.c b/fs/minix/inode.c index 629e09b38c5..92e383af370 100644 --- a/fs/minix/inode.c +++ b/fs/minix/inode.c @@ -7,6 +7,7 @@ * Minix V2 fs support. * * Modified for 680x0 by Andreas Schwab + * Updated to filesystem version 3 by Daniel Aragones */ #include <linux/module.h> @@ -36,7 +37,8 @@ static void minix_put_super(struct super_block *sb) struct minix_sb_info *sbi = minix_sb(sb); if (!(sb->s_flags & MS_RDONLY)) { - sbi->s_ms->s_state = sbi->s_mount_state; + if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */ + sbi->s_ms->s_state = sbi->s_mount_state; mark_buffer_dirty(sbi->s_sbh); } for (i = 0; i < sbi->s_imap_blocks; i++) @@ -93,7 +95,7 @@ static void destroy_inodecache(void) kmem_cache_destroy(minix_inode_cachep); } -static struct super_operations minix_sops = { +static const struct super_operations minix_sops = { .alloc_inode = minix_alloc_inode, .destroy_inode = minix_destroy_inode, .read_inode = minix_read_inode, @@ -117,12 +119,17 @@ static int minix_remount (struct super_block * sb, int * flags, char * data) !(sbi->s_mount_state & MINIX_VALID_FS)) return 0; /* Mounting a rw partition read-only. */ - ms->s_state = sbi->s_mount_state; + if (sbi->s_version != MINIX_V3) + ms->s_state = sbi->s_mount_state; mark_buffer_dirty(sbi->s_sbh); } else { /* Mount a partition which is read-only, read-write. */ - sbi->s_mount_state = ms->s_state; - ms->s_state &= ~MINIX_VALID_FS; + if (sbi->s_version != MINIX_V3) { + sbi->s_mount_state = ms->s_state; + ms->s_state &= ~MINIX_VALID_FS; + } else { + sbi->s_mount_state = MINIX_VALID_FS; + } mark_buffer_dirty(sbi->s_sbh); if (!(sbi->s_mount_state & MINIX_VALID_FS)) @@ -140,7 +147,8 @@ static int minix_fill_super(struct super_block *s, void *data, int silent) struct buffer_head *bh; struct buffer_head **map; struct minix_super_block *ms; - int i, block; + struct minix3_super_block *m3s = NULL; + unsigned long i, block; struct inode *root_inode; struct minix_sb_info *sbi; @@ -192,6 +200,22 @@ static int minix_fill_super(struct super_block *s, void *data, int silent) sbi->s_dirsize = 32; sbi->s_namelen = 30; sbi->s_link_max = MINIX2_LINK_MAX; + } else if ( *(__u16 *)(bh->b_data + 24) == MINIX3_SUPER_MAGIC) { + m3s = (struct minix3_super_block *) bh->b_data; + s->s_magic = m3s->s_magic; + sbi->s_imap_blocks = m3s->s_imap_blocks; + sbi->s_zmap_blocks = m3s->s_zmap_blocks; + sbi->s_firstdatazone = m3s->s_firstdatazone; + sbi->s_log_zone_size = m3s->s_log_zone_size; + sbi->s_max_size = m3s->s_max_size; + sbi->s_ninodes = m3s->s_ninodes; + sbi->s_nzones = m3s->s_zones; + sbi->s_dirsize = 64; + sbi->s_namelen = 60; + sbi->s_version = MINIX_V3; + sbi->s_link_max = MINIX2_LINK_MAX; + sbi->s_mount_state = MINIX_VALID_FS; + sb_set_blocksize(s, m3s->s_blocksize); } else goto out_no_fs; @@ -236,7 +260,8 @@ static int minix_fill_super(struct super_block *s, void *data, int silent) s->s_root->d_op = &minix_dentry_operations; if (!(s->s_flags & MS_RDONLY)) { - ms->s_state &= ~MINIX_VALID_FS; + if (sbi->s_version != MINIX_V3) /* s_state is now out from V3 sb */ + ms->s_state &= ~MINIX_VALID_FS; mark_buffer_dirty(bh); } if (!(sbi->s_mount_state & MINIX_VALID_FS)) @@ -278,8 +303,8 @@ out_illegal_sb: out_no_fs: if (!silent) - printk("VFS: Can't find a Minix or Minix V2 filesystem " - "on device %s\n", s->s_id); + printk("VFS: Can't find a Minix filesystem V1 | V2 | V3 " + "on device %s.\n", s->s_id); out_release: brelse(bh); goto out; @@ -344,7 +369,7 @@ static const struct address_space_operations minix_aops = { .bmap = minix_bmap }; -static struct inode_operations minix_symlink_inode_operations = { +static const struct inode_operations minix_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link, @@ -537,12 +562,14 @@ int minix_sync_inode(struct inode * inode) int minix_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { + struct inode *dir = dentry->d_parent->d_inode; + struct super_block *sb = dir->i_sb; generic_fillattr(dentry->d_inode, stat); if (INODE_VERSION(dentry->d_inode) == MINIX_V1) - stat->blocks = (BLOCK_SIZE / 512) * V1_minix_blocks(stat->size); + stat->blocks = (BLOCK_SIZE / 512) * V1_minix_blocks(stat->size, sb); else - stat->blocks = (BLOCK_SIZE / 512) * V2_minix_blocks(stat->size); - stat->blksize = BLOCK_SIZE; + stat->blocks = (sb->s_blocksize / 512) * V2_minix_blocks(stat->size, sb); + stat->blksize = sb->s_blocksize; return 0; } diff --git a/fs/minix/itree_common.c b/fs/minix/itree_common.c index 429baf8de10..a731cabf154 100644 --- a/fs/minix/itree_common.c +++ b/fs/minix/itree_common.c @@ -23,7 +23,7 @@ static inline int verify_chain(Indirect *from, Indirect *to) static inline block_t *block_end(struct buffer_head *bh) { - return (block_t *)((char*)bh->b_data + BLOCK_SIZE); + return (block_t *)((char*)bh->b_data + bh->b_size); } static inline Indirect *get_branch(struct inode *inode, @@ -85,7 +85,7 @@ static int alloc_branch(struct inode *inode, branch[n].key = cpu_to_block(nr); bh = sb_getblk(inode->i_sb, parent); lock_buffer(bh); - memset(bh->b_data, 0, BLOCK_SIZE); + memset(bh->b_data, 0, bh->b_size); branch[n].bh = bh; branch[n].p = (block_t*) bh->b_data + offsets[n]; *branch[n].p = branch[n].key; @@ -292,6 +292,7 @@ static void free_branches(struct inode *inode, block_t *p, block_t *q, int depth static inline void truncate (struct inode * inode) { + struct super_block *sb = inode->i_sb; block_t *idata = i_data(inode); int offsets[DEPTH]; Indirect chain[DEPTH]; @@ -301,7 +302,7 @@ static inline void truncate (struct inode * inode) int first_whole; long iblock; - iblock = (inode->i_size + BLOCK_SIZE-1) >> 10; + iblock = (inode->i_size + sb->s_blocksize -1) >> sb->s_blocksize_bits; block_truncate_page(inode->i_mapping, inode->i_size, get_block); n = block_to_path(inode, iblock, offsets); @@ -346,15 +347,16 @@ do_indirects: mark_inode_dirty(inode); } -static inline unsigned nblocks(loff_t size) +static inline unsigned nblocks(loff_t size, struct super_block *sb) { + int k = sb->s_blocksize_bits - 10; unsigned blocks, res, direct = DIRECT, i = DEPTH; - blocks = (size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS; + blocks = (size + sb->s_blocksize - 1) >> (BLOCK_SIZE_BITS + k); res = blocks; while (--i && blocks > direct) { blocks -= direct; - blocks += BLOCK_SIZE/sizeof(block_t) - 1; - blocks /= BLOCK_SIZE/sizeof(block_t); + blocks += sb->s_blocksize/sizeof(block_t) - 1; + blocks /= sb->s_blocksize/sizeof(block_t); res += blocks; direct = 1; } diff --git a/fs/minix/itree_v1.c b/fs/minix/itree_v1.c index 656b1347a25..1a5f3bf0bce 100644 --- a/fs/minix/itree_v1.c +++ b/fs/minix/itree_v1.c @@ -55,7 +55,7 @@ void V1_minix_truncate(struct inode * inode) truncate(inode); } -unsigned V1_minix_blocks(loff_t size) +unsigned V1_minix_blocks(loff_t size, struct super_block *sb) { - return nblocks(size); + return nblocks(size, sb); } diff --git a/fs/minix/itree_v2.c b/fs/minix/itree_v2.c index 9adcdc754e0..ad8f0dec4ef 100644 --- a/fs/minix/itree_v2.c +++ b/fs/minix/itree_v2.c @@ -23,10 +23,11 @@ static inline block_t *i_data(struct inode *inode) static int block_to_path(struct inode * inode, long block, int offsets[DEPTH]) { int n = 0; + struct super_block *sb = inode->i_sb; if (block < 0) { printk("minix_bmap: block<0\n"); - } else if (block >= (minix_sb(inode->i_sb)->s_max_size/BLOCK_SIZE)) { + } else if (block >= (minix_sb(inode->i_sb)->s_max_size/sb->s_blocksize)) { printk("minix_bmap: block>big\n"); } else if (block < 7) { offsets[n++] = block; @@ -60,7 +61,7 @@ void V2_minix_truncate(struct inode * inode) truncate(inode); } -unsigned V2_minix_blocks(loff_t size) +unsigned V2_minix_blocks(loff_t size, struct super_block *sb) { - return nblocks(size); + return nblocks(size, sb); } diff --git a/fs/minix/minix.h b/fs/minix/minix.h index c55b77cdcc8..73ef84f8fb0 100644 --- a/fs/minix/minix.h +++ b/fs/minix/minix.h @@ -7,11 +7,10 @@ * truncated. Else they will be disallowed (ENAMETOOLONG). */ #define NO_TRUNCATE 1 - #define INODE_VERSION(inode) minix_sb(inode->i_sb)->s_version - #define MINIX_V1 0x0001 /* original minix fs */ #define MINIX_V2 0x0002 /* minix V2 fs */ +#define MINIX_V3 0x0003 /* minix V3 fs */ /* * minix fs inode data in memory @@ -52,12 +51,10 @@ extern struct inode * minix_new_inode(const struct inode * dir, int * error); extern void minix_free_inode(struct inode * inode); extern unsigned long minix_count_free_inodes(struct minix_sb_info *sbi); extern int minix_new_block(struct inode * inode); -extern void minix_free_block(struct inode * inode, int block); +extern void minix_free_block(struct inode *inode, unsigned long block); extern unsigned long minix_count_free_blocks(struct minix_sb_info *sbi); - extern int minix_getattr(struct vfsmount *, struct dentry *, struct kstat *); -extern void V2_minix_truncate(struct inode *); extern void V1_minix_truncate(struct inode *); extern void V2_minix_truncate(struct inode *); extern void minix_truncate(struct inode *); @@ -65,8 +62,8 @@ extern int minix_sync_inode(struct inode *); extern void minix_set_inode(struct inode *, dev_t); extern int V1_minix_get_block(struct inode *, long, struct buffer_head *, int); extern int V2_minix_get_block(struct inode *, long, struct buffer_head *, int); -extern unsigned V1_minix_blocks(loff_t); -extern unsigned V2_minix_blocks(loff_t); +extern unsigned V1_minix_blocks(loff_t, struct super_block *); +extern unsigned V2_minix_blocks(loff_t, struct super_block *); extern struct minix_dir_entry *minix_find_entry(struct dentry*, struct page**); extern int minix_add_link(struct dentry*, struct inode*); @@ -76,11 +73,10 @@ extern int minix_empty_dir(struct inode*); extern void minix_set_link(struct minix_dir_entry*, struct page*, struct inode*); extern struct minix_dir_entry *minix_dotdot(struct inode*, struct page**); extern ino_t minix_inode_by_name(struct dentry*); - extern int minix_sync_file(struct file *, struct dentry *, int); -extern struct inode_operations minix_file_inode_operations; -extern struct inode_operations minix_dir_inode_operations; +extern const struct inode_operations minix_file_inode_operations; +extern const struct inode_operations minix_dir_inode_operations; extern const struct file_operations minix_file_operations; extern const struct file_operations minix_dir_operations; extern struct dentry_operations minix_dentry_operations; diff --git a/fs/minix/namei.c b/fs/minix/namei.c index 299bb66e3bd..f4aa7a93904 100644 --- a/fs/minix/namei.c +++ b/fs/minix/namei.c @@ -291,7 +291,7 @@ out: /* * directories can handle most operations... */ -struct inode_operations minix_dir_inode_operations = { +const struct inode_operations minix_dir_inode_operations = { .create = minix_create, .lookup = minix_lookup, .link = minix_link, diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index 452461955cb..30f7d0ae221 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c @@ -646,7 +646,7 @@ out: return err; } -static struct inode_operations msdos_dir_inode_operations = { +static const struct inode_operations msdos_dir_inode_operations = { .create = msdos_create, .lookup = msdos_lookup, .unlink = msdos_unlink, diff --git a/fs/namei.c b/fs/namei.c index e4f108f0823..161e2225c75 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -2744,7 +2744,7 @@ int page_symlink(struct inode *inode, const char *symname, int len) mapping_gfp_mask(inode->i_mapping)); } -struct inode_operations page_symlink_inode_operations = { +const struct inode_operations page_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link, diff --git a/fs/namespace.c b/fs/namespace.c index 5ef336c1103..fd999cab7b5 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -53,9 +53,8 @@ static inline unsigned long hash(struct vfsmount *mnt, struct dentry *dentry) struct vfsmount *alloc_vfsmnt(const char *name) { - struct vfsmount *mnt = kmem_cache_alloc(mnt_cache, GFP_KERNEL); + struct vfsmount *mnt = kmem_cache_zalloc(mnt_cache, GFP_KERNEL); if (mnt) { - memset(mnt, 0, sizeof(struct vfsmount)); atomic_set(&mnt->mnt_count, 1); INIT_LIST_HEAD(&mnt->mnt_hash); INIT_LIST_HEAD(&mnt->mnt_child); diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c index 73747772c3b..011ef0b6d2d 100644 --- a/fs/ncpfs/dir.c +++ b/fs/ncpfs/dir.c @@ -58,7 +58,7 @@ const struct file_operations ncp_dir_operations = #endif }; -struct inode_operations ncp_dir_inode_operations = +const struct inode_operations ncp_dir_inode_operations = { .create = ncp_create, .lookup = ncp_lookup, diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c index b91fea03b1c..6b1f6d27099 100644 --- a/fs/ncpfs/file.c +++ b/fs/ncpfs/file.c @@ -297,7 +297,7 @@ const struct file_operations ncp_file_operations = .fsync = ncp_fsync, }; -struct inode_operations ncp_file_inode_operations = +const struct inode_operations ncp_file_inode_operations = { .setattr = ncp_notify_change, }; diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c index 67a90bf795d..14939ddf74f 100644 --- a/fs/ncpfs/inode.c +++ b/fs/ncpfs/inode.c @@ -90,7 +90,7 @@ static int ncp_remount(struct super_block *sb, int *flags, char* data) return 0; } -static struct super_operations ncp_sops = +static const struct super_operations ncp_sops = { .alloc_inode = ncp_alloc_inode, .destroy_inode = ncp_destroy_inode, @@ -229,7 +229,7 @@ static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo) } #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) -static struct inode_operations ncp_symlink_inode_operations = { +static const struct inode_operations ncp_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link, diff --git a/fs/nfs/callback.c b/fs/nfs/callback.c index 7933e2e99db..75f309c8741 100644 --- a/fs/nfs/callback.c +++ b/fs/nfs/callback.c @@ -71,6 +71,8 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) complete(&nfs_callback_info.started); for(;;) { + char buf[RPC_MAX_ADDRBUFLEN]; + if (signalled()) { if (nfs_callback_info.users == 0) break; @@ -88,8 +90,8 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) __FUNCTION__, -err); break; } - dprintk("%s: request from %u.%u.%u.%u\n", __FUNCTION__, - NIPQUAD(rqstp->rq_addr.sin_addr.s_addr)); + dprintk("%s: request from %s\n", __FUNCTION__, + svc_print_addr(rqstp, buf, sizeof(buf))); svc_process(rqstp); } @@ -106,7 +108,6 @@ static void nfs_callback_svc(struct svc_rqst *rqstp) int nfs_callback_up(void) { struct svc_serv *serv; - struct svc_sock *svsk; int ret = 0; lock_kernel(); @@ -119,17 +120,14 @@ int nfs_callback_up(void) ret = -ENOMEM; if (!serv) goto out_err; - /* FIXME: We don't want to register this socket with the portmapper */ - ret = svc_makesock(serv, IPPROTO_TCP, nfs_callback_set_tcpport); - if (ret < 0) + + ret = svc_makesock(serv, IPPROTO_TCP, nfs_callback_set_tcpport, + SVC_SOCK_ANONYMOUS); + if (ret <= 0) goto out_destroy; - if (!list_empty(&serv->sv_permsocks)) { - svsk = list_entry(serv->sv_permsocks.next, - struct svc_sock, sk_list); - nfs_callback_tcpport = ntohs(inet_sk(svsk->sk_sk)->sport); - dprintk ("Callback port = 0x%x\n", nfs_callback_tcpport); - } else - BUG(); + nfs_callback_tcpport = ret; + dprintk("Callback port = 0x%x\n", nfs_callback_tcpport); + ret = svc_create_thread(nfs_callback_svc, serv); if (ret < 0) goto out_destroy; @@ -140,6 +138,8 @@ out: unlock_kernel(); return ret; out_destroy: + dprintk("Couldn't create callback socket or server thread; err = %d\n", + ret); svc_destroy(serv); out_err: nfs_callback_info.users--; @@ -166,15 +166,19 @@ void nfs_callback_down(void) static int nfs_callback_authenticate(struct svc_rqst *rqstp) { - struct sockaddr_in *addr = &rqstp->rq_addr; + struct sockaddr_in *addr = svc_addr_in(rqstp); struct nfs_client *clp; + char buf[RPC_MAX_ADDRBUFLEN]; /* Don't talk to strangers */ clp = nfs_find_client(addr, 4); if (clp == NULL) return SVC_DROP; - dprintk("%s: %u.%u.%u.%u NFSv4 callback!\n", __FUNCTION__, NIPQUAD(addr->sin_addr)); + + dprintk("%s: %s NFSv4 callback!\n", __FUNCTION__, + svc_print_addr(rqstp, buf, sizeof(buf))); nfs_put_client(clp); + switch (rqstp->rq_authop->flavour) { case RPC_AUTH_NULL: if (rqstp->rq_proc != CB_NULL) diff --git a/fs/nfs/callback_xdr.c b/fs/nfs/callback_xdr.c index f8ea1f51f59..849a2029975 100644 --- a/fs/nfs/callback_xdr.c +++ b/fs/nfs/callback_xdr.c @@ -176,7 +176,7 @@ static __be32 decode_getattr_args(struct svc_rqst *rqstp, struct xdr_stream *xdr status = decode_fh(xdr, &args->fh); if (unlikely(status != 0)) goto out; - args->addr = &rqstp->rq_addr; + args->addr = svc_addr_in(rqstp); status = decode_bitmap(xdr, args->bitmap); out: dprintk("%s: exit with status = %d\n", __FUNCTION__, status); @@ -188,7 +188,7 @@ static __be32 decode_recall_args(struct svc_rqst *rqstp, struct xdr_stream *xdr, __be32 *p; __be32 status; - args->addr = &rqstp->rq_addr; + args->addr = svc_addr_in(rqstp); status = decode_stateid(xdr, &args->stateid); if (unlikely(status != 0)) goto out; diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 23ab145daa2..ae9f36e393c 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -1173,7 +1173,7 @@ static struct seq_operations nfs_server_list_ops = { .show = nfs_server_list_show, }; -static struct file_operations nfs_server_list_fops = { +static const struct file_operations nfs_server_list_fops = { .open = nfs_server_list_open, .read = seq_read, .llseek = seq_lseek, @@ -1193,7 +1193,7 @@ static struct seq_operations nfs_volume_list_ops = { .show = nfs_volume_list_show, }; -static struct file_operations nfs_volume_list_fops = { +static const struct file_operations nfs_volume_list_fops = { .open = nfs_volume_list_open, .read = seq_read, .llseek = seq_lseek, diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index d9ba8cb0ee7..f03a770bacb 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -65,7 +65,7 @@ const struct file_operations nfs_dir_operations = { .fsync = nfs_fsync_dir, }; -struct inode_operations nfs_dir_inode_operations = { +const struct inode_operations nfs_dir_inode_operations = { .create = nfs_create, .lookup = nfs_lookup, .link = nfs_link, @@ -81,7 +81,7 @@ struct inode_operations nfs_dir_inode_operations = { }; #ifdef CONFIG_NFS_V3 -struct inode_operations nfs3_dir_inode_operations = { +const struct inode_operations nfs3_dir_inode_operations = { .create = nfs_create, .lookup = nfs_lookup, .link = nfs_link, @@ -104,7 +104,7 @@ struct inode_operations nfs3_dir_inode_operations = { #ifdef CONFIG_NFS_V4 static struct dentry *nfs_atomic_lookup(struct inode *, struct dentry *, struct nameidata *); -struct inode_operations nfs4_dir_inode_operations = { +const struct inode_operations nfs4_dir_inode_operations = { .create = nfs_create, .lookup = nfs_atomic_lookup, .link = nfs_link, diff --git a/fs/nfs/file.c b/fs/nfs/file.c index 9e4a2b70995..8e66b5a2d49 100644 --- a/fs/nfs/file.c +++ b/fs/nfs/file.c @@ -68,14 +68,14 @@ const struct file_operations nfs_file_operations = { .check_flags = nfs_check_flags, }; -struct inode_operations nfs_file_inode_operations = { +const struct inode_operations nfs_file_inode_operations = { .permission = nfs_permission, .getattr = nfs_getattr, .setattr = nfs_setattr, }; #ifdef CONFIG_NFS_V3 -struct inode_operations nfs3_file_inode_operations = { +const struct inode_operations nfs3_file_inode_operations = { .permission = nfs_permission, .getattr = nfs_getattr, .setattr = nfs_setattr, diff --git a/fs/nfs/namespace.c b/fs/nfs/namespace.c index 371b804e7cc..7f86e65182e 100644 --- a/fs/nfs/namespace.c +++ b/fs/nfs/namespace.c @@ -155,12 +155,12 @@ out_follow: goto out; } -struct inode_operations nfs_mountpoint_inode_operations = { +const struct inode_operations nfs_mountpoint_inode_operations = { .follow_link = nfs_follow_mountpoint, .getattr = nfs_getattr, }; -struct inode_operations nfs_referral_inode_operations = { +const struct inode_operations nfs_referral_inode_operations = { .follow_link = nfs_follow_mountpoint, }; diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h index c26cd978c7c..e2341766c4f 100644 --- a/fs/nfs/nfs4_fs.h +++ b/fs/nfs/nfs4_fs.h @@ -151,7 +151,7 @@ struct nfs4_state_recovery_ops { }; extern struct dentry_operations nfs4_dentry_operations; -extern struct inode_operations nfs4_dir_inode_operations; +extern const struct inode_operations nfs4_dir_inode_operations; /* inode.c */ extern ssize_t nfs4_getxattr(struct dentry *, const char *, void *, size_t); diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index b3fd29baadc..1daee65b517 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c @@ -3625,7 +3625,7 @@ struct nfs4_state_recovery_ops nfs4_network_partition_recovery_ops = { .recover_lock = nfs4_lock_expired, }; -static struct inode_operations nfs4_file_inode_operations = { +static const struct inode_operations nfs4_file_inode_operations = { .permission = nfs_permission, .getattr = nfs_getattr, .setattr = nfs_setattr, diff --git a/fs/nfs/super.c b/fs/nfs/super.c index 28108c82b88..baa28860ad2 100644 --- a/fs/nfs/super.c +++ b/fs/nfs/super.c @@ -44,6 +44,7 @@ #include <linux/vfs.h> #include <linux/inet.h> #include <linux/nfs_xdr.h> +#include <linux/magic.h> #include <asm/system.h> #include <asm/uaccess.h> @@ -81,7 +82,7 @@ struct file_system_type nfs_xdev_fs_type = { .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, }; -static struct super_operations nfs_sops = { +static const struct super_operations nfs_sops = { .alloc_inode = nfs_alloc_inode, .destroy_inode = nfs_destroy_inode, .write_inode = nfs_write_inode, @@ -125,7 +126,7 @@ struct file_system_type nfs4_referral_fs_type = { .fs_flags = FS_RENAME_DOES_D_MOVE|FS_REVAL_DOT|FS_BINARY_MOUNTDATA, }; -static struct super_operations nfs4_sops = { +static const struct super_operations nfs4_sops = { .alloc_inode = nfs_alloc_inode, .destroy_inode = nfs_destroy_inode, .write_inode = nfs_write_inode, diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c index 525c136c7d8..f4a0548b9ce 100644 --- a/fs/nfs/symlink.c +++ b/fs/nfs/symlink.c @@ -78,7 +78,7 @@ read_failed: /* * symlinks can't do much... */ -struct inode_operations nfs_symlink_inode_operations = { +const struct inode_operations nfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = nfs_follow_link, .put_link = page_put_link, diff --git a/fs/nfsd/nfs4state.c b/fs/nfsd/nfs4state.c index 9de89df961f..9e406799920 100644 --- a/fs/nfsd/nfs4state.c +++ b/fs/nfsd/nfs4state.c @@ -714,7 +714,7 @@ __be32 nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_setclientid *setclid) { - __be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; + struct sockaddr_in *sin = svc_addr_in(rqstp); struct xdr_netobj clname = { .len = setclid->se_namelen, .data = setclid->se_name, @@ -749,7 +749,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, */ status = nfserr_clid_inuse; if (!cmp_creds(&conf->cl_cred, &rqstp->rq_cred) - || conf->cl_addr != ip_addr) { + || conf->cl_addr != sin->sin_addr.s_addr) { printk("NFSD: setclientid: string in use by client" "(clientid %08x/%08x)\n", conf->cl_clientid.cl_boot, conf->cl_clientid.cl_id); @@ -769,7 +769,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (new == NULL) goto out; copy_verf(new, &clverifier); - new->cl_addr = ip_addr; + new->cl_addr = sin->sin_addr.s_addr; copy_cred(&new->cl_cred,&rqstp->rq_cred); gen_clid(new); gen_confirm(new); @@ -801,7 +801,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (new == NULL) goto out; copy_verf(new,&conf->cl_verifier); - new->cl_addr = ip_addr; + new->cl_addr = sin->sin_addr.s_addr; copy_cred(&new->cl_cred,&rqstp->rq_cred); copy_clid(new, conf); gen_confirm(new); @@ -820,7 +820,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (new == NULL) goto out; copy_verf(new,&clverifier); - new->cl_addr = ip_addr; + new->cl_addr = sin->sin_addr.s_addr; copy_cred(&new->cl_cred,&rqstp->rq_cred); gen_clid(new); gen_confirm(new); @@ -847,7 +847,7 @@ nfsd4_setclientid(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, if (new == NULL) goto out; copy_verf(new,&clverifier); - new->cl_addr = ip_addr; + new->cl_addr = sin->sin_addr.s_addr; copy_cred(&new->cl_cred,&rqstp->rq_cred); gen_clid(new); gen_confirm(new); @@ -881,7 +881,7 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_setclientid_confirm *setclientid_confirm) { - __be32 ip_addr = rqstp->rq_addr.sin_addr.s_addr; + struct sockaddr_in *sin = svc_addr_in(rqstp); struct nfs4_client *conf, *unconf; nfs4_verifier confirm = setclientid_confirm->sc_confirm; clientid_t * clid = &setclientid_confirm->sc_clientid; @@ -900,9 +900,9 @@ nfsd4_setclientid_confirm(struct svc_rqst *rqstp, unconf = find_unconfirmed_client(clid); status = nfserr_clid_inuse; - if (conf && conf->cl_addr != ip_addr) + if (conf && conf->cl_addr != sin->sin_addr.s_addr) goto out; - if (unconf && unconf->cl_addr != ip_addr) + if (unconf && unconf->cl_addr != sin->sin_addr.s_addr) goto out; if ((conf && unconf) && diff --git a/fs/nfsd/nfscache.c b/fs/nfsd/nfscache.c index f90d7047585..578f2c9d56b 100644 --- a/fs/nfsd/nfscache.c +++ b/fs/nfsd/nfscache.c @@ -185,7 +185,7 @@ nfsd_cache_lookup(struct svc_rqst *rqstp, int type) rp->c_state = RC_INPROG; rp->c_xid = xid; rp->c_proc = proc; - rp->c_addr = rqstp->rq_addr; + memcpy(&rp->c_addr, svc_addr_in(rqstp), sizeof(rp->c_addr)); rp->c_prot = proto; rp->c_vers = vers; rp->c_timestamp = jiffies; diff --git a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c index c59d6fbb7a6..a0b4282cb28 100644 --- a/fs/nfsd/nfsfh.c +++ b/fs/nfsd/nfsfh.c @@ -20,6 +20,7 @@ #include <linux/mount.h> #include <asm/pgtable.h> +#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/svc.h> #include <linux/nfsd/nfsd.h> @@ -180,10 +181,10 @@ fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access) /* Check if the request originated from a secure port. */ error = nfserr_perm; if (!rqstp->rq_secure && EX_SECURE(exp)) { + char buf[RPC_MAX_ADDRBUFLEN]; printk(KERN_WARNING - "nfsd: request from insecure port (%u.%u.%u.%u:%d)!\n", - NIPQUAD(rqstp->rq_addr.sin_addr.s_addr), - ntohs(rqstp->rq_addr.sin_port)); + "nfsd: request from insecure port %s!\n", + svc_print_addr(rqstp, buf, sizeof(buf))); goto out; } diff --git a/fs/nfsd/nfsproc.c b/fs/nfsd/nfsproc.c index ec983b77768..5cc2eec981b 100644 --- a/fs/nfsd/nfsproc.c +++ b/fs/nfsd/nfsproc.c @@ -19,6 +19,7 @@ #include <linux/unistd.h> #include <linux/slab.h> +#include <linux/sunrpc/clnt.h> #include <linux/sunrpc/svc.h> #include <linux/nfsd/nfsd.h> #include <linux/nfsd/cache.h> @@ -147,10 +148,10 @@ nfsd_proc_read(struct svc_rqst *rqstp, struct nfsd_readargs *argp, */ if (NFSSVC_MAXBLKSIZE_V2 < argp->count) { + char buf[RPC_MAX_ADDRBUFLEN]; printk(KERN_NOTICE - "oversized read request from %u.%u.%u.%u:%d (%d bytes)\n", - NIPQUAD(rqstp->rq_addr.sin_addr.s_addr), - ntohs(rqstp->rq_addr.sin_port), + "oversized read request from %s (%d bytes)\n", + svc_print_addr(rqstp, buf, sizeof(buf)), argp->count); argp->count = NFSSVC_MAXBLKSIZE_V2; } diff --git a/fs/nfsd/nfssvc.c b/fs/nfsd/nfssvc.c index fbf5d51947e..d7759ce6ed9 100644 --- a/fs/nfsd/nfssvc.c +++ b/fs/nfsd/nfssvc.c @@ -235,7 +235,8 @@ static int nfsd_init_socks(int port) error = lockd_up(IPPROTO_UDP); if (error >= 0) { - error = svc_makesock(nfsd_serv, IPPROTO_UDP, port); + error = svc_makesock(nfsd_serv, IPPROTO_UDP, port, + SVC_SOCK_DEFAULTS); if (error < 0) lockd_down(); } @@ -245,7 +246,8 @@ static int nfsd_init_socks(int port) #ifdef CONFIG_NFSD_TCP error = lockd_up(IPPROTO_TCP); if (error >= 0) { - error = svc_makesock(nfsd_serv, IPPROTO_TCP, port); + error = svc_makesock(nfsd_serv, IPPROTO_TCP, port, + SVC_SOCK_DEFAULTS); if (error < 0) lockd_down(); } diff --git a/fs/ntfs/attrib.c b/fs/ntfs/attrib.c index c577d8e1bd9..7659cc19299 100644 --- a/fs/ntfs/attrib.c +++ b/fs/ntfs/attrib.c @@ -1921,7 +1921,7 @@ s64 ntfs_attr_extend_allocation(ntfs_inode *ni, s64 new_alloc_size, u32 attr_len = 0; /* Silence stupid gcc warning. */ bool mp_rebuilt; -#ifdef NTFS_DEBUG +#ifdef DEBUG read_lock_irqsave(&ni->size_lock, flags); allocated_size = ni->allocated_size; read_unlock_irqrestore(&ni->size_lock, flags); diff --git a/fs/ntfs/file.c b/fs/ntfs/file.c index 076c9420c25..d69c4595ccd 100644 --- a/fs/ntfs/file.c +++ b/fs/ntfs/file.c @@ -2328,7 +2328,7 @@ const struct file_operations ntfs_file_ops = { the data source. */ }; -struct inode_operations ntfs_file_inode_ops = { +const struct inode_operations ntfs_file_inode_ops = { #ifdef NTFS_RW .truncate = ntfs_truncate_vfs, .setattr = ntfs_setattr, @@ -2337,4 +2337,4 @@ struct inode_operations ntfs_file_inode_ops = { const struct file_operations ntfs_empty_file_ops = {}; -struct inode_operations ntfs_empty_inode_ops = {}; +const struct inode_operations ntfs_empty_inode_ops = {}; diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c index eddb2247cec..bff01a54675 100644 --- a/fs/ntfs/namei.c +++ b/fs/ntfs/namei.c @@ -359,7 +359,7 @@ err_out: /** * Inode operations for directories. */ -struct inode_operations ntfs_dir_inode_ops = { +const struct inode_operations ntfs_dir_inode_ops = { .lookup = ntfs_lookup, /* VFS: Lookup directory. */ }; diff --git a/fs/ntfs/ntfs.h b/fs/ntfs/ntfs.h index a12847ae467..d73f5a9ac34 100644 --- a/fs/ntfs/ntfs.h +++ b/fs/ntfs/ntfs.h @@ -61,13 +61,13 @@ extern const struct address_space_operations ntfs_aops; extern const struct address_space_operations ntfs_mst_aops; extern const struct file_operations ntfs_file_ops; -extern struct inode_operations ntfs_file_inode_ops; +extern const struct inode_operations ntfs_file_inode_ops; extern const struct file_operations ntfs_dir_ops; -extern struct inode_operations ntfs_dir_inode_ops; +extern const struct inode_operations ntfs_dir_inode_ops; extern const struct file_operations ntfs_empty_file_ops; -extern struct inode_operations ntfs_empty_inode_ops; +extern const struct inode_operations ntfs_empty_inode_ops; extern struct export_operations ntfs_export_ops; diff --git a/fs/ntfs/super.c b/fs/ntfs/super.c index babf94d90de..1594c90b716 100644 --- a/fs/ntfs/super.c +++ b/fs/ntfs/super.c @@ -2699,7 +2699,7 @@ static int ntfs_statfs(struct dentry *dentry, struct kstatfs *sfs) /** * The complete super operations. */ -static struct super_operations ntfs_sops = { +static const struct super_operations ntfs_sops = { .alloc_inode = ntfs_alloc_big_inode, /* VFS: Allocate new inode. */ .destroy_inode = ntfs_destroy_big_inode, /* VFS: Deallocate inode. */ #ifdef NTFS_RW diff --git a/fs/ocfs2/dlm/dlmfs.c b/fs/ocfs2/dlm/dlmfs.c index b7f0ba97a1a..de952eba29a 100644 --- a/fs/ocfs2/dlm/dlmfs.c +++ b/fs/ocfs2/dlm/dlmfs.c @@ -61,11 +61,11 @@ #define MLOG_MASK_PREFIX ML_DLMFS #include "cluster/masklog.h" -static struct super_operations dlmfs_ops; -static struct file_operations dlmfs_file_operations; -static struct inode_operations dlmfs_dir_inode_operations; -static struct inode_operations dlmfs_root_inode_operations; -static struct inode_operations dlmfs_file_inode_operations; +static const struct super_operations dlmfs_ops; +static const struct file_operations dlmfs_file_operations; +static const struct inode_operations dlmfs_dir_inode_operations; +static const struct inode_operations dlmfs_root_inode_operations; +static const struct inode_operations dlmfs_file_inode_operations; static struct kmem_cache *dlmfs_inode_cache; struct workqueue_struct *user_dlm_worker; @@ -540,27 +540,27 @@ static int dlmfs_fill_super(struct super_block * sb, return 0; } -static struct file_operations dlmfs_file_operations = { +static const struct file_operations dlmfs_file_operations = { .open = dlmfs_file_open, .release = dlmfs_file_release, .read = dlmfs_file_read, .write = dlmfs_file_write, }; -static struct inode_operations dlmfs_dir_inode_operations = { +static const struct inode_operations dlmfs_dir_inode_operations = { .create = dlmfs_create, .lookup = simple_lookup, .unlink = dlmfs_unlink, }; /* this way we can restrict mkdir to only the toplevel of the fs. */ -static struct inode_operations dlmfs_root_inode_operations = { +static const struct inode_operations dlmfs_root_inode_operations = { .lookup = simple_lookup, .mkdir = dlmfs_mkdir, .rmdir = simple_rmdir, }; -static struct super_operations dlmfs_ops = { +static const struct super_operations dlmfs_ops = { .statfs = simple_statfs, .alloc_inode = dlmfs_alloc_inode, .destroy_inode = dlmfs_destroy_inode, @@ -568,7 +568,7 @@ static struct super_operations dlmfs_ops = { .drop_inode = generic_delete_inode, }; -static struct inode_operations dlmfs_file_inode_operations = { +static const struct inode_operations dlmfs_file_inode_operations = { .getattr = simple_getattr, }; diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 10953a508f2..f2cd3bf9efb 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -1365,13 +1365,13 @@ bail: return ret; } -struct inode_operations ocfs2_file_iops = { +const struct inode_operations ocfs2_file_iops = { .setattr = ocfs2_setattr, .getattr = ocfs2_getattr, .permission = ocfs2_permission, }; -struct inode_operations ocfs2_special_file_iops = { +const struct inode_operations ocfs2_special_file_iops = { .setattr = ocfs2_setattr, .getattr = ocfs2_getattr, .permission = ocfs2_permission, diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h index 601a453f18a..cc973f01f6c 100644 --- a/fs/ocfs2/file.h +++ b/fs/ocfs2/file.h @@ -28,8 +28,8 @@ extern const struct file_operations ocfs2_fops; extern const struct file_operations ocfs2_dops; -extern struct inode_operations ocfs2_file_iops; -extern struct inode_operations ocfs2_special_file_iops; +extern const struct inode_operations ocfs2_file_iops; +extern const struct inode_operations ocfs2_special_file_iops; struct ocfs2_alloc_context; enum ocfs2_alloc_restarted { diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index f3d7803b4b4..f7fa52bb3f6 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -2306,7 +2306,7 @@ leave: return status; } -struct inode_operations ocfs2_dir_iops = { +const struct inode_operations ocfs2_dir_iops = { .create = ocfs2_create, .lookup = ocfs2_lookup, .link = ocfs2_link, diff --git a/fs/ocfs2/namei.h b/fs/ocfs2/namei.h index 8425944fccc..0975c7b7212 100644 --- a/fs/ocfs2/namei.h +++ b/fs/ocfs2/namei.h @@ -26,7 +26,7 @@ #ifndef OCFS2_NAMEI_H #define OCFS2_NAMEI_H -extern struct inode_operations ocfs2_dir_iops; +extern const struct inode_operations ocfs2_dir_iops; struct dentry *ocfs2_get_parent(struct dentry *child); diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 6e300a88a47..6534f92424d 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -116,7 +116,7 @@ static void ocfs2_destroy_inode(struct inode *inode); static unsigned long long ocfs2_max_file_offset(unsigned int blockshift); -static struct super_operations ocfs2_sops = { +static const struct super_operations ocfs2_sops = { .statfs = ocfs2_statfs, .alloc_inode = ocfs2_alloc_inode, .destroy_inode = ocfs2_destroy_inode, diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c index 03b0191534d..40dc1a51f4a 100644 --- a/fs/ocfs2/symlink.c +++ b/fs/ocfs2/symlink.c @@ -170,12 +170,12 @@ bail: return ERR_PTR(status); } -struct inode_operations ocfs2_symlink_inode_operations = { +const struct inode_operations ocfs2_symlink_inode_operations = { .readlink = page_readlink, .follow_link = ocfs2_follow_link, .getattr = ocfs2_getattr, }; -struct inode_operations ocfs2_fast_symlink_inode_operations = { +const struct inode_operations ocfs2_fast_symlink_inode_operations = { .readlink = ocfs2_readlink, .follow_link = ocfs2_follow_link, .getattr = ocfs2_getattr, diff --git a/fs/ocfs2/symlink.h b/fs/ocfs2/symlink.h index 1ea9e4d9e9e..65a6c9c6ad5 100644 --- a/fs/ocfs2/symlink.h +++ b/fs/ocfs2/symlink.h @@ -26,8 +26,8 @@ #ifndef OCFS2_SYMLINK_H #define OCFS2_SYMLINK_H -extern struct inode_operations ocfs2_symlink_inode_operations; -extern struct inode_operations ocfs2_fast_symlink_inode_operations; +extern const struct inode_operations ocfs2_symlink_inode_operations; +extern const struct inode_operations ocfs2_fast_symlink_inode_operations; /* * Test whether an inode is a fast symlink. diff --git a/fs/openpromfs/inode.c b/fs/openpromfs/inode.c index 99c0bc37ba0..bde1c164417 100644 --- a/fs/openpromfs/inode.c +++ b/fs/openpromfs/inode.c @@ -169,7 +169,7 @@ static const struct file_operations openprom_operations = { static struct dentry *openpromfs_lookup(struct inode *, struct dentry *, struct nameidata *); -static struct inode_operations openprom_inode_operations = { +static const struct inode_operations openprom_inode_operations = { .lookup = openpromfs_lookup, }; @@ -364,7 +364,7 @@ static int openprom_remount(struct super_block *sb, int *flags, char *data) return 0; } -static struct super_operations openprom_sops = { +static const struct super_operations openprom_sops = { .alloc_inode = openprom_alloc_inode, .destroy_inode = openprom_destroy_inode, .read_inode = openprom_read_inode, diff --git a/fs/partitions/check.c b/fs/partitions/check.c index 3d73d94d93a..ac32a2e8540 100644 --- a/fs/partitions/check.c +++ b/fs/partitions/check.c @@ -365,7 +365,7 @@ void delete_partition(struct gendisk *disk, int part) kobject_put(&p->kobj); } -void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) +void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len, int flags) { struct hd_struct *p; @@ -390,6 +390,15 @@ void add_partition(struct gendisk *disk, int part, sector_t start, sector_t len) if (!disk->part_uevent_suppress) kobject_uevent(&p->kobj, KOBJ_ADD); sysfs_create_link(&p->kobj, &block_subsys.kset.kobj, "subsystem"); + if (flags & ADDPART_FLAG_WHOLEDISK) { + static struct attribute addpartattr = { + .name = "whole_disk", + .mode = S_IRUSR | S_IRGRP | S_IROTH, + .owner = THIS_MODULE, + }; + + sysfs_create_file(&p->kobj, &addpartattr); + } partition_sysfs_add_subdir(p); disk->part[part-1] = p; } @@ -543,9 +552,9 @@ int rescan_partitions(struct gendisk *disk, struct block_device *bdev) printk(" %s: p%d exceeds device capacity\n", disk->disk_name, p); } - add_partition(disk, p, from, size); + add_partition(disk, p, from, size, state->parts[p].flags); #ifdef CONFIG_BLK_DEV_MD - if (state->parts[p].flags) + if (state->parts[p].flags & ADDPART_FLAG_RAID) md_autodetect_dev(bdev->bd_dev+p); #endif } diff --git a/fs/partitions/msdos.c b/fs/partitions/msdos.c index 8c7af177781..4ccec4cd136 100644 --- a/fs/partitions/msdos.c +++ b/fs/partitions/msdos.c @@ -63,15 +63,25 @@ msdos_magic_present(unsigned char *p) #define AIX_LABEL_MAGIC4 0xC1 static int aix_magic_present(unsigned char *p, struct block_device *bdev) { + struct partition *pt = (struct partition *) (p + 0x1be); Sector sect; unsigned char *d; - int ret = 0; + int slot, ret = 0; - if (p[0] != AIX_LABEL_MAGIC1 && - p[1] != AIX_LABEL_MAGIC2 && - p[2] != AIX_LABEL_MAGIC3 && - p[3] != AIX_LABEL_MAGIC4) + if (!(p[0] == AIX_LABEL_MAGIC1 && + p[1] == AIX_LABEL_MAGIC2 && + p[2] == AIX_LABEL_MAGIC3 && + p[3] == AIX_LABEL_MAGIC4)) return 0; + /* Assume the partition table is valid if Linux partitions exists */ + for (slot = 1; slot <= 4; slot++, pt++) { + if (pt->sys_ind == LINUX_SWAP_PARTITION || + pt->sys_ind == LINUX_RAID_PARTITION || + pt->sys_ind == LINUX_DATA_PARTITION || + pt->sys_ind == LINUX_LVM_PARTITION || + is_extended_partition(pt)) + return 0; + } d = read_dev_sector(bdev, 7, §); if (d) { if (d[0] == '_' && d[1] == 'L' && d[2] == 'V' && d[3] == 'M') @@ -155,7 +165,7 @@ parse_extended(struct parsed_partitions *state, struct block_device *bdev, put_partition(state, state->next, next, size); if (SYS_IND(p) == LINUX_RAID_PARTITION) - state->parts[state->next].flags = 1; + state->parts[state->next].flags = ADDPART_FLAG_RAID; loopct = 0; if (++state->next == state->limit) goto done; diff --git a/fs/partitions/sgi.c b/fs/partitions/sgi.c index 6fa4ff89510..ed5ac83fe83 100644 --- a/fs/partitions/sgi.c +++ b/fs/partitions/sgi.c @@ -72,7 +72,7 @@ int sgi_partition(struct parsed_partitions *state, struct block_device *bdev) if (blocks) { put_partition(state, slot, start, blocks); if (be32_to_cpu(p->type) == LINUX_RAID_PARTITION) - state->parts[slot].flags = 1; + state->parts[slot].flags = ADDPART_FLAG_RAID; } slot++; } diff --git a/fs/partitions/sun.c b/fs/partitions/sun.c index 0a5927c806c..123f8b46c8b 100644 --- a/fs/partitions/sun.c +++ b/fs/partitions/sun.c @@ -80,8 +80,11 @@ int sun_partition(struct parsed_partitions *state, struct block_device *bdev) num_sectors = be32_to_cpu(p->num_sectors); if (num_sectors) { put_partition(state, slot, st_sector, num_sectors); + state->parts[slot].flags = 0; if (label->infos[i].id == LINUX_RAID_PARTITION) - state->parts[slot].flags = 1; + state->parts[slot].flags |= ADDPART_FLAG_RAID; + if (label->infos[i].id == SUN_WHOLE_DISK) + state->parts[slot].flags |= ADDPART_FLAG_WHOLEDISK; } slot++; } diff --git a/fs/proc/array.c b/fs/proc/array.c index 70e4fab117b..07c9cdbcdca 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -351,7 +351,7 @@ static int do_task_stat(struct task_struct *task, char * buffer, int whole) struct signal_struct *sig = task->signal; if (sig->tty) { - tty_pgrp = sig->tty->pgrp; + tty_pgrp = pid_nr(sig->tty->pgrp); tty_nr = new_encode_dev(tty_devnum(sig->tty)); } diff --git a/fs/proc/base.c b/fs/proc/base.c index 1a979ea3b37..4f5745af8c1 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c @@ -93,8 +93,8 @@ struct pid_entry { int len; char *name; mode_t mode; - struct inode_operations *iop; - struct file_operations *fop; + const struct inode_operations *iop; + const struct file_operations *fop; union proc_op op; }; @@ -352,7 +352,7 @@ static int proc_setattr(struct dentry *dentry, struct iattr *attr) return error; } -static struct inode_operations proc_def_inode_operations = { +static const struct inode_operations proc_def_inode_operations = { .setattr = proc_setattr, }; @@ -424,7 +424,7 @@ static unsigned mounts_poll(struct file *file, poll_table *wait) return res; } -static struct file_operations proc_mounts_operations = { +static const struct file_operations proc_mounts_operations = { .open = mounts_open, .read = seq_read, .llseek = seq_lseek, @@ -462,7 +462,7 @@ static int mountstats_open(struct inode *inode, struct file *file) return ret; } -static struct file_operations proc_mountstats_operations = { +static const struct file_operations proc_mountstats_operations = { .open = mountstats_open, .read = seq_read, .llseek = seq_lseek, @@ -501,7 +501,7 @@ out_no_task: return length; } -static struct file_operations proc_info_file_operations = { +static const struct file_operations proc_info_file_operations = { .read = proc_info_read, }; @@ -646,7 +646,7 @@ static loff_t mem_lseek(struct file * file, loff_t offset, int orig) return file->f_pos; } -static struct file_operations proc_mem_operations = { +static const struct file_operations proc_mem_operations = { .llseek = mem_lseek, .read = mem_read, .write = mem_write, @@ -710,7 +710,7 @@ static ssize_t oom_adjust_write(struct file *file, const char __user *buf, return end - buffer; } -static struct file_operations proc_oom_adjust_operations = { +static const struct file_operations proc_oom_adjust_operations = { .read = oom_adjust_read, .write = oom_adjust_write, }; @@ -777,7 +777,7 @@ out_free_page: return length; } -static struct file_operations proc_loginuid_operations = { +static const struct file_operations proc_loginuid_operations = { .read = proc_loginuid_read, .write = proc_loginuid_write, }; @@ -849,7 +849,7 @@ out_no_task: return result; } -static struct file_operations proc_seccomp_operations = { +static const struct file_operations proc_seccomp_operations = { .read = seccomp_read, .write = seccomp_write, }; @@ -908,7 +908,7 @@ static ssize_t proc_fault_inject_write(struct file * file, return end - buffer; } -static struct file_operations proc_fault_inject_operations = { +static const struct file_operations proc_fault_inject_operations = { .read = proc_fault_inject_read, .write = proc_fault_inject_write, }; @@ -980,7 +980,7 @@ out: return error; } -static struct inode_operations proc_pid_link_inode_operations = { +static const struct inode_operations proc_pid_link_inode_operations = { .readlink = proc_pid_readlink, .follow_link = proc_pid_follow_link, .setattr = proc_setattr, @@ -1408,7 +1408,7 @@ out_no_task: return retval; } -static struct file_operations proc_fd_operations = { +static const struct file_operations proc_fd_operations = { .read = generic_read_dir, .readdir = proc_readfd, }; @@ -1416,7 +1416,7 @@ static struct file_operations proc_fd_operations = { /* * proc directories can do almost nothing.. */ -static struct inode_operations proc_fd_inode_operations = { +static const struct inode_operations proc_fd_inode_operations = { .lookup = proc_lookupfd, .setattr = proc_setattr, }; @@ -1623,7 +1623,7 @@ out_no_task: return length; } -static struct file_operations proc_pid_attr_operations = { +static const struct file_operations proc_pid_attr_operations = { .read = proc_pid_attr_read, .write = proc_pid_attr_write, }; @@ -1644,7 +1644,7 @@ static int proc_attr_dir_readdir(struct file * filp, attr_dir_stuff,ARRAY_SIZE(attr_dir_stuff)); } -static struct file_operations proc_attr_dir_operations = { +static const struct file_operations proc_attr_dir_operations = { .read = generic_read_dir, .readdir = proc_attr_dir_readdir, }; @@ -1656,7 +1656,7 @@ static struct dentry *proc_attr_dir_lookup(struct inode *dir, attr_dir_stuff, ARRAY_SIZE(attr_dir_stuff)); } -static struct inode_operations proc_attr_dir_inode_operations = { +static const struct inode_operations proc_attr_dir_inode_operations = { .lookup = proc_attr_dir_lookup, .getattr = pid_getattr, .setattr = proc_setattr, @@ -1682,7 +1682,7 @@ static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) return ERR_PTR(vfs_follow_link(nd,tmp)); } -static struct inode_operations proc_self_inode_operations = { +static const struct inode_operations proc_self_inode_operations = { .readlink = proc_self_readlink, .follow_link = proc_self_follow_link, }; @@ -1810,17 +1810,21 @@ static int proc_base_fill_cache(struct file *filp, void *dirent, filldir_t filld static int proc_pid_io_accounting(struct task_struct *task, char *buffer) { return sprintf(buffer, +#ifdef CONFIG_TASK_XACCT "rchar: %llu\n" "wchar: %llu\n" "syscr: %llu\n" "syscw: %llu\n" +#endif "read_bytes: %llu\n" "write_bytes: %llu\n" "cancelled_write_bytes: %llu\n", +#ifdef CONFIG_TASK_XACCT (unsigned long long)task->rchar, (unsigned long long)task->wchar, (unsigned long long)task->syscr, (unsigned long long)task->syscw, +#endif (unsigned long long)task->ioac.read_bytes, (unsigned long long)task->ioac.write_bytes, (unsigned long long)task->ioac.cancelled_write_bytes); @@ -1830,8 +1834,8 @@ static int proc_pid_io_accounting(struct task_struct *task, char *buffer) /* * Thread groups */ -static struct file_operations proc_task_operations; -static struct inode_operations proc_task_inode_operations; +static const struct file_operations proc_task_operations; +static const struct inode_operations proc_task_inode_operations; static struct pid_entry tgid_base_stuff[] = { DIR("task", S_IRUGO|S_IXUGO, task), @@ -1890,7 +1894,7 @@ static int proc_tgid_base_readdir(struct file * filp, tgid_base_stuff,ARRAY_SIZE(tgid_base_stuff)); } -static struct file_operations proc_tgid_base_operations = { +static const struct file_operations proc_tgid_base_operations = { .read = generic_read_dir, .readdir = proc_tgid_base_readdir, }; @@ -1900,7 +1904,7 @@ static struct dentry *proc_tgid_base_lookup(struct inode *dir, struct dentry *de tgid_base_stuff, ARRAY_SIZE(tgid_base_stuff)); } -static struct inode_operations proc_tgid_base_inode_operations = { +static const struct inode_operations proc_tgid_base_inode_operations = { .lookup = proc_tgid_base_lookup, .getattr = pid_getattr, .setattr = proc_setattr, @@ -2173,12 +2177,12 @@ static struct dentry *proc_tid_base_lookup(struct inode *dir, struct dentry *den tid_base_stuff, ARRAY_SIZE(tid_base_stuff)); } -static struct file_operations proc_tid_base_operations = { +static const struct file_operations proc_tid_base_operations = { .read = generic_read_dir, .readdir = proc_tid_base_readdir, }; -static struct inode_operations proc_tid_base_inode_operations = { +static const struct inode_operations proc_tid_base_inode_operations = { .lookup = proc_tid_base_lookup, .getattr = pid_getattr, .setattr = proc_setattr, @@ -2404,13 +2408,13 @@ static int proc_task_getattr(struct vfsmount *mnt, struct dentry *dentry, struct return 0; } -static struct inode_operations proc_task_inode_operations = { +static const struct inode_operations proc_task_inode_operations = { .lookup = proc_task_lookup, .getattr = proc_task_getattr, .setattr = proc_setattr, }; -static struct file_operations proc_task_operations = { +static const struct file_operations proc_task_operations = { .read = generic_read_dir, .readdir = proc_task_readdir, }; diff --git a/fs/proc/generic.c b/fs/proc/generic.c index 853cb877d5f..0cdc00d9d97 100644 --- a/fs/proc/generic.c +++ b/fs/proc/generic.c @@ -39,7 +39,7 @@ int proc_match(int len, const char *name, struct proc_dir_entry *de) return !memcmp(name, de->name, len); } -static struct file_operations proc_file_operations = { +static const struct file_operations proc_file_operations = { .llseek = proc_file_lseek, .read = proc_file_read, .write = proc_file_write, @@ -265,7 +265,7 @@ static int proc_getattr(struct vfsmount *mnt, struct dentry *dentry, return 0; } -static struct inode_operations proc_file_inode_operations = { +static const struct inode_operations proc_file_inode_operations = { .setattr = proc_notify_change, }; @@ -357,7 +357,7 @@ static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd) return NULL; } -static struct inode_operations proc_link_inode_operations = { +static const struct inode_operations proc_link_inode_operations = { .readlink = generic_readlink, .follow_link = proc_follow_link, }; @@ -497,7 +497,7 @@ out: unlock_kernel(); * use the in-memory "struct proc_dir_entry" tree to parse * the /proc directory. */ -static struct file_operations proc_dir_operations = { +static const struct file_operations proc_dir_operations = { .read = generic_read_dir, .readdir = proc_readdir, }; @@ -505,7 +505,7 @@ static struct file_operations proc_dir_operations = { /* * proc directories can do almost nothing.. */ -static struct inode_operations proc_dir_inode_operations = { +static const struct inode_operations proc_dir_inode_operations = { .lookup = proc_lookup, .getattr = proc_getattr, .setattr = proc_notify_change, diff --git a/fs/proc/inode.c b/fs/proc/inode.c index e26945ba685..f6722be37dd 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -132,7 +132,7 @@ static int proc_remount(struct super_block *sb, int *flags, char *data) return 0; } -static struct super_operations proc_sops = { +static const struct super_operations proc_sops = { .alloc_inode = proc_alloc_inode, .destroy_inode = proc_destroy_inode, .read_inode = proc_read_inode, diff --git a/fs/proc/internal.h b/fs/proc/internal.h index 987c773dbb2..277dcd66ebe 100644 --- a/fs/proc/internal.h +++ b/fs/proc/internal.h @@ -38,13 +38,13 @@ extern int proc_tgid_stat(struct task_struct *, char *); extern int proc_pid_status(struct task_struct *, char *); extern int proc_pid_statm(struct task_struct *, char *); -extern struct file_operations proc_maps_operations; -extern struct file_operations proc_numa_maps_operations; -extern struct file_operations proc_smaps_operations; +extern const struct file_operations proc_maps_operations; +extern const struct file_operations proc_numa_maps_operations; +extern const struct file_operations proc_smaps_operations; -extern struct file_operations proc_maps_operations; -extern struct file_operations proc_numa_maps_operations; -extern struct file_operations proc_smaps_operations; +extern const struct file_operations proc_maps_operations; +extern const struct file_operations proc_numa_maps_operations; +extern const struct file_operations proc_smaps_operations; void free_proc_entry(struct proc_dir_entry *de); diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c index 5ec67257e5f..22f789de390 100644 --- a/fs/proc/nommu.c +++ b/fs/proc/nommu.c @@ -128,7 +128,7 @@ static int proc_nommu_vma_list_open(struct inode *inode, struct file *file) return seq_open(file, &proc_nommu_vma_list_seqop); } -static struct file_operations proc_nommu_vma_list_operations = { +static const struct file_operations proc_nommu_vma_list_operations = { .open = proc_nommu_vma_list_open, .read = seq_read, .llseek = seq_lseek, diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c index b37ce33f67e..e2c4c0a5c90 100644 --- a/fs/proc/proc_misc.c +++ b/fs/proc/proc_misc.c @@ -121,16 +121,11 @@ static int meminfo_read_proc(char *page, char **start, off_t off, { struct sysinfo i; int len; - unsigned long inactive; - unsigned long active; - unsigned long free; unsigned long committed; unsigned long allowed; struct vmalloc_info vmi; long cached; - get_zone_counts(&active, &inactive, &free); - /* * display in kilobytes. */ @@ -187,8 +182,8 @@ static int meminfo_read_proc(char *page, char **start, off_t off, K(i.bufferram), K(cached), K(total_swapcache_pages), - K(active), - K(inactive), + K(global_page_state(NR_ACTIVE)), + K(global_page_state(NR_INACTIVE)), #ifdef CONFIG_HIGHMEM K(i.totalhigh), K(i.freehigh), @@ -228,7 +223,7 @@ static int fragmentation_open(struct inode *inode, struct file *file) return seq_open(file, &fragmentation_op); } -static struct file_operations fragmentation_file_operations = { +static const struct file_operations fragmentation_file_operations = { .open = fragmentation_open, .read = seq_read, .llseek = seq_lseek, @@ -241,7 +236,7 @@ static int zoneinfo_open(struct inode *inode, struct file *file) return seq_open(file, &zoneinfo_op); } -static struct file_operations proc_zoneinfo_file_operations = { +static const struct file_operations proc_zoneinfo_file_operations = { .open = zoneinfo_open, .read = seq_read, .llseek = seq_lseek, @@ -266,7 +261,7 @@ static int cpuinfo_open(struct inode *inode, struct file *file) return seq_open(file, &cpuinfo_op); } -static struct file_operations proc_cpuinfo_operations = { +static const struct file_operations proc_cpuinfo_operations = { .open = cpuinfo_open, .read = seq_read, .llseek = seq_lseek, @@ -325,7 +320,7 @@ static int devinfo_open(struct inode *inode, struct file *filp) return seq_open(filp, &devinfo_ops); } -static struct file_operations proc_devinfo_operations = { +static const struct file_operations proc_devinfo_operations = { .open = devinfo_open, .read = seq_read, .llseek = seq_lseek, @@ -337,7 +332,7 @@ static int vmstat_open(struct inode *inode, struct file *file) { return seq_open(file, &vmstat_op); } -static struct file_operations proc_vmstat_file_operations = { +static const struct file_operations proc_vmstat_file_operations = { .open = vmstat_open, .read = seq_read, .llseek = seq_lseek, @@ -368,7 +363,7 @@ static int partitions_open(struct inode *inode, struct file *file) { return seq_open(file, &partitions_op); } -static struct file_operations proc_partitions_operations = { +static const struct file_operations proc_partitions_operations = { .open = partitions_open, .read = seq_read, .llseek = seq_lseek, @@ -380,7 +375,7 @@ static int diskstats_open(struct inode *inode, struct file *file) { return seq_open(file, &diskstats_op); } -static struct file_operations proc_diskstats_operations = { +static const struct file_operations proc_diskstats_operations = { .open = diskstats_open, .read = seq_read, .llseek = seq_lseek, @@ -394,7 +389,7 @@ static int modules_open(struct inode *inode, struct file *file) { return seq_open(file, &modules_op); } -static struct file_operations proc_modules_operations = { +static const struct file_operations proc_modules_operations = { .open = modules_open, .read = seq_read, .llseek = seq_lseek, @@ -409,7 +404,7 @@ static int slabinfo_open(struct inode *inode, struct file *file) { return seq_open(file, &slabinfo_op); } -static struct file_operations proc_slabinfo_operations = { +static const struct file_operations proc_slabinfo_operations = { .open = slabinfo_open, .read = seq_read, .write = slabinfo_write, @@ -443,7 +438,7 @@ static int slabstats_release(struct inode *inode, struct file *file) return seq_release(inode, file); } -static struct file_operations proc_slabstats_operations = { +static const struct file_operations proc_slabstats_operations = { .open = slabstats_open, .read = seq_read, .llseek = seq_lseek, @@ -556,7 +551,7 @@ static int stat_open(struct inode *inode, struct file *file) kfree(buf); return res; } -static struct file_operations proc_stat_operations = { +static const struct file_operations proc_stat_operations = { .open = stat_open, .read = seq_read, .llseek = seq_lseek, @@ -598,7 +593,7 @@ static int interrupts_open(struct inode *inode, struct file *filp) return seq_open(filp, &int_seq_ops); } -static struct file_operations proc_interrupts_operations = { +static const struct file_operations proc_interrupts_operations = { .open = interrupts_open, .read = seq_read, .llseek = seq_lseek, @@ -655,7 +650,7 @@ static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf, return count; } -static struct file_operations proc_sysrq_trigger_operations = { +static const struct file_operations proc_sysrq_trigger_operations = { .write = write_sysrq_trigger, }; #endif @@ -672,7 +667,6 @@ void create_seq_entry(char *name, mode_t mode, const struct file_operations *f) void __init proc_misc_init(void) { - struct proc_dir_entry *entry; static struct { char *name; int (*read_proc)(char*,char**,off_t,int,int*,void*); @@ -700,9 +694,12 @@ void __init proc_misc_init(void) /* And now for trickier ones */ #ifdef CONFIG_PRINTK - entry = create_proc_entry("kmsg", S_IRUSR, &proc_root); - if (entry) - entry->proc_fops = &proc_kmsg_operations; + { + struct proc_dir_entry *entry; + entry = create_proc_entry("kmsg", S_IRUSR, &proc_root); + if (entry) + entry->proc_fops = &proc_kmsg_operations; + } #endif create_seq_entry("devices", 0, &proc_devinfo_operations); create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations); @@ -743,8 +740,11 @@ void __init proc_misc_init(void) proc_vmcore->proc_fops = &proc_vmcore_operations; #endif #ifdef CONFIG_MAGIC_SYSRQ - entry = create_proc_entry("sysrq-trigger", S_IWUSR, NULL); - if (entry) - entry->proc_fops = &proc_sysrq_trigger_operations; + { + struct proc_dir_entry *entry; + entry = create_proc_entry("sysrq-trigger", S_IWUSR, NULL); + if (entry) + entry->proc_fops = &proc_sysrq_trigger_operations; + } #endif } diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c index 15c4455b09e..c1bbfbeb035 100644 --- a/fs/proc/proc_tty.c +++ b/fs/proc/proc_tty.c @@ -138,7 +138,7 @@ static int tty_drivers_open(struct inode *inode, struct file *file) return seq_open(file, &tty_drivers_op); } -static struct file_operations proc_tty_drivers_operations = { +static const struct file_operations proc_tty_drivers_operations = { .open = tty_drivers_open, .read = seq_read, .llseek = seq_lseek, diff --git a/fs/proc/root.c b/fs/proc/root.c index 64d242b6dcf..af154458b54 100644 --- a/fs/proc/root.c +++ b/fs/proc/root.c @@ -136,7 +136,7 @@ static int proc_root_readdir(struct file * filp, * <pid> directories. Thus we don't use the generic * directory handling functions for that.. */ -static struct file_operations proc_root_operations = { +static const struct file_operations proc_root_operations = { .read = generic_read_dir, .readdir = proc_root_readdir, }; @@ -144,7 +144,7 @@ static struct file_operations proc_root_operations = { /* * proc root can do almost nothing.. */ -static struct inode_operations proc_root_inode_operations = { +static const struct inode_operations proc_root_inode_operations = { .lookup = proc_root_lookup, .getattr = proc_root_getattr, }; diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c index 55ade0d1562..7445980c802 100644 --- a/fs/proc/task_mmu.c +++ b/fs/proc/task_mmu.c @@ -434,7 +434,7 @@ static int maps_open(struct inode *inode, struct file *file) return do_maps_open(inode, file, &proc_pid_maps_op); } -struct file_operations proc_maps_operations = { +const struct file_operations proc_maps_operations = { .open = maps_open, .read = seq_read, .llseek = seq_lseek, @@ -456,7 +456,7 @@ static int numa_maps_open(struct inode *inode, struct file *file) return do_maps_open(inode, file, &proc_pid_numa_maps_op); } -struct file_operations proc_numa_maps_operations = { +const struct file_operations proc_numa_maps_operations = { .open = numa_maps_open, .read = seq_read, .llseek = seq_lseek, @@ -469,7 +469,7 @@ static int smaps_open(struct inode *inode, struct file *file) return do_maps_open(inode, file, &proc_pid_smaps_op); } -struct file_operations proc_smaps_operations = { +const struct file_operations proc_smaps_operations = { .open = smaps_open, .read = seq_read, .llseek = seq_lseek, diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c index fcc5caf93f5..7cddf6b8635 100644 --- a/fs/proc/task_nommu.c +++ b/fs/proc/task_nommu.c @@ -220,7 +220,7 @@ static int maps_open(struct inode *inode, struct file *file) return ret; } -struct file_operations proc_maps_operations = { +const struct file_operations proc_maps_operations = { .open = maps_open, .read = seq_read, .llseek = seq_lseek, diff --git a/fs/qnx4/dir.c b/fs/qnx4/dir.c index c94db1db7a7..ea9ffefb48a 100644 --- a/fs/qnx4/dir.c +++ b/fs/qnx4/dir.c @@ -87,7 +87,7 @@ const struct file_operations qnx4_dir_operations = .fsync = file_fsync, }; -struct inode_operations qnx4_dir_inode_operations = +const struct inode_operations qnx4_dir_inode_operations = { .lookup = qnx4_lookup, #ifdef CONFIG_QNX4FS_RW diff --git a/fs/qnx4/file.c b/fs/qnx4/file.c index 467e5ac7280..44649981bbc 100644 --- a/fs/qnx4/file.c +++ b/fs/qnx4/file.c @@ -33,7 +33,7 @@ const struct file_operations qnx4_file_operations = #endif }; -struct inode_operations qnx4_file_inode_operations = +const struct inode_operations qnx4_file_inode_operations = { #ifdef CONFIG_QNX4FS_RW .truncate = qnx4_truncate, diff --git a/fs/qnx4/inode.c b/fs/qnx4/inode.c index c047dc654d5..83bc8e7824c 100644 --- a/fs/qnx4/inode.c +++ b/fs/qnx4/inode.c @@ -30,7 +30,7 @@ #define QNX4_VERSION 4 #define QNX4_BMNAME ".bitmap" -static struct super_operations qnx4_sops; +static const struct super_operations qnx4_sops; #ifdef CONFIG_QNX4FS_RW @@ -129,7 +129,7 @@ static void qnx4_read_inode(struct inode *); static int qnx4_remount(struct super_block *sb, int *flags, char *data); static int qnx4_statfs(struct dentry *, struct kstatfs *); -static struct super_operations qnx4_sops = +static const struct super_operations qnx4_sops = { .alloc_inode = qnx4_alloc_inode, .destroy_inode = qnx4_destroy_inode, diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c index 54ebbc84207..2f14774a124 100644 --- a/fs/ramfs/file-mmu.c +++ b/fs/ramfs/file-mmu.c @@ -31,7 +31,7 @@ const struct address_space_operations ramfs_aops = { .readpage = simple_readpage, .prepare_write = simple_prepare_write, .commit_write = simple_commit_write, - .set_page_dirty = __set_page_dirty_nobuffers, + .set_page_dirty = __set_page_dirty_no_writeback, }; const struct file_operations ramfs_file_operations = { @@ -45,6 +45,6 @@ const struct file_operations ramfs_file_operations = { .llseek = generic_file_llseek, }; -struct inode_operations ramfs_file_inode_operations = { +const struct inode_operations ramfs_file_inode_operations = { .getattr = simple_getattr, }; diff --git a/fs/ramfs/file-nommu.c b/fs/ramfs/file-nommu.c index e9d6c473328..d3fd7c6732d 100644 --- a/fs/ramfs/file-nommu.c +++ b/fs/ramfs/file-nommu.c @@ -32,7 +32,7 @@ const struct address_space_operations ramfs_aops = { .readpage = simple_readpage, .prepare_write = simple_prepare_write, .commit_write = simple_commit_write, - .set_page_dirty = __set_page_dirty_nobuffers, + .set_page_dirty = __set_page_dirty_no_writeback, }; const struct file_operations ramfs_file_operations = { @@ -47,7 +47,7 @@ const struct file_operations ramfs_file_operations = { .llseek = generic_file_llseek, }; -struct inode_operations ramfs_file_inode_operations = { +const struct inode_operations ramfs_file_inode_operations = { .setattr = ramfs_nommu_setattr, .getattr = simple_getattr, }; diff --git a/fs/ramfs/inode.c b/fs/ramfs/inode.c index 2faf4cdf61b..ff1f7639707 100644 --- a/fs/ramfs/inode.c +++ b/fs/ramfs/inode.c @@ -40,8 +40,8 @@ /* some random number */ #define RAMFS_MAGIC 0x858458f6 -static struct super_operations ramfs_ops; -static struct inode_operations ramfs_dir_inode_operations; +static const struct super_operations ramfs_ops; +static const struct inode_operations ramfs_dir_inode_operations; static struct backing_dev_info ramfs_backing_dev_info = { .ra_pages = 0, /* No readahead */ @@ -143,7 +143,7 @@ static int ramfs_symlink(struct inode * dir, struct dentry *dentry, const char * return error; } -static struct inode_operations ramfs_dir_inode_operations = { +static const struct inode_operations ramfs_dir_inode_operations = { .create = ramfs_create, .lookup = simple_lookup, .link = simple_link, @@ -155,7 +155,7 @@ static struct inode_operations ramfs_dir_inode_operations = { .rename = simple_rename, }; -static struct super_operations ramfs_ops = { +static const struct super_operations ramfs_ops = { .statfs = simple_statfs, .drop_inode = generic_delete_inode, }; diff --git a/fs/ramfs/internal.h b/fs/ramfs/internal.h index c2bb58e7465..af7cc074a47 100644 --- a/fs/ramfs/internal.h +++ b/fs/ramfs/internal.h @@ -12,4 +12,4 @@ extern const struct address_space_operations ramfs_aops; extern const struct file_operations ramfs_file_operations; -extern struct inode_operations ramfs_file_inode_operations; +extern const struct inode_operations ramfs_file_inode_operations; diff --git a/fs/read_write.c b/fs/read_write.c index 707ac21700d..1f8dc373ede 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -197,13 +197,13 @@ int rw_verify_area(int read_write, struct file *file, loff_t *ppos, size_t count struct inode *inode; loff_t pos; + inode = file->f_path.dentry->d_inode; if (unlikely((ssize_t) count < 0)) goto Einval; pos = *ppos; if (unlikely((pos < 0) || (loff_t) (pos + count) < 0)) goto Einval; - inode = file->f_path.dentry->d_inode; if (unlikely(inode->i_flock && MANDATORY_LOCK(inode))) { int retval = locks_mandatory_area( read_write == READ ? FLOCK_VERIFY_READ : FLOCK_VERIFY_WRITE, @@ -274,9 +274,9 @@ ssize_t vfs_read(struct file *file, char __user *buf, size_t count, loff_t *pos) ret = do_sync_read(file, buf, count, pos); if (ret > 0) { fsnotify_access(file->f_path.dentry); - current->rchar += ret; + add_rchar(current, ret); } - current->syscr++; + inc_syscr(current); } } @@ -332,9 +332,9 @@ ssize_t vfs_write(struct file *file, const char __user *buf, size_t count, loff_ ret = do_sync_write(file, buf, count, pos); if (ret > 0) { fsnotify_modify(file->f_path.dentry); - current->wchar += ret; + add_wchar(current, ret); } - current->syscw++; + inc_syscw(current); } } @@ -675,8 +675,8 @@ sys_readv(unsigned long fd, const struct iovec __user *vec, unsigned long vlen) } if (ret > 0) - current->rchar += ret; - current->syscr++; + add_rchar(current, ret); + inc_syscr(current); return ret; } @@ -696,8 +696,8 @@ sys_writev(unsigned long fd, const struct iovec __user *vec, unsigned long vlen) } if (ret > 0) - current->wchar += ret; - current->syscw++; + add_wchar(current, ret); + inc_syscw(current); return ret; } @@ -779,12 +779,12 @@ static ssize_t do_sendfile(int out_fd, int in_fd, loff_t *ppos, retval = in_file->f_op->sendfile(in_file, ppos, count, file_send_actor, out_file); if (retval > 0) { - current->rchar += retval; - current->wchar += retval; + add_rchar(current, retval); + add_wchar(current, retval); } - current->syscr++; - current->syscw++; + inc_syscr(current); + inc_syscw(current); if (*ppos > max) retval = -EOVERFLOW; diff --git a/fs/reiserfs/do_balan.c b/fs/reiserfs/do_balan.c index fba304e64de..f85c5cf4934 100644 --- a/fs/reiserfs/do_balan.c +++ b/fs/reiserfs/do_balan.c @@ -19,6 +19,7 @@ #include <linux/time.h> #include <linux/reiserfs_fs.h> #include <linux/buffer_head.h> +#include <linux/kernel.h> #ifdef CONFIG_REISERFS_CHECK @@ -1756,7 +1757,7 @@ static void store_thrown(struct tree_balance *tb, struct buffer_head *bh) if (buffer_dirty(bh)) reiserfs_warning(tb->tb_sb, "store_thrown deals with dirty buffer"); - for (i = 0; i < sizeof(tb->thrown) / sizeof(tb->thrown[0]); i++) + for (i = 0; i < ARRAY_SIZE(tb->thrown); i++) if (!tb->thrown[i]) { tb->thrown[i] = bh; get_bh(bh); /* free_thrown puts this */ @@ -1769,7 +1770,7 @@ static void free_thrown(struct tree_balance *tb) { int i; b_blocknr_t blocknr; - for (i = 0; i < sizeof(tb->thrown) / sizeof(tb->thrown[0]); i++) { + for (i = 0; i < ARRAY_SIZE(tb->thrown); i++) { if (tb->thrown[i]) { blocknr = tb->thrown[i]->b_blocknr; if (buffer_dirty(tb->thrown[i])) diff --git a/fs/reiserfs/file.c b/fs/reiserfs/file.c index 5109f1d5e7f..abfada2f52d 100644 --- a/fs/reiserfs/file.c +++ b/fs/reiserfs/file.c @@ -1556,7 +1556,7 @@ const struct file_operations reiserfs_file_operations = { .splice_write = generic_file_splice_write, }; -struct inode_operations reiserfs_file_inode_operations = { +const struct inode_operations reiserfs_file_inode_operations = { .truncate = reiserfs_vfs_truncate_file, .setattr = reiserfs_setattr, .setxattr = reiserfs_setxattr, diff --git a/fs/reiserfs/namei.c b/fs/reiserfs/namei.c index 23f5cd5bbf5..a2161840bc7 100644 --- a/fs/reiserfs/namei.c +++ b/fs/reiserfs/namei.c @@ -1525,7 +1525,7 @@ static int reiserfs_rename(struct inode *old_dir, struct dentry *old_dentry, /* * directories can handle most operations... */ -struct inode_operations reiserfs_dir_inode_operations = { +const struct inode_operations reiserfs_dir_inode_operations = { //&reiserfs_dir_operations, /* default_file_ops */ .create = reiserfs_create, .lookup = reiserfs_lookup, @@ -1548,7 +1548,7 @@ struct inode_operations reiserfs_dir_inode_operations = { * symlink operations.. same as page_symlink_inode_operations, with xattr * stuff added */ -struct inode_operations reiserfs_symlink_inode_operations = { +const struct inode_operations reiserfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link, @@ -1564,7 +1564,7 @@ struct inode_operations reiserfs_symlink_inode_operations = { /* * special file operations.. just xattr/acl stuff */ -struct inode_operations reiserfs_special_inode_operations = { +const struct inode_operations reiserfs_special_inode_operations = { .setattr = reiserfs_setattr, .setxattr = reiserfs_setxattr, .getxattr = reiserfs_getxattr, diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c index 58ad4551a7c..f13a7f164dc 100644 --- a/fs/reiserfs/super.c +++ b/fs/reiserfs/super.c @@ -593,7 +593,7 @@ static ssize_t reiserfs_quota_read(struct super_block *, int, char *, size_t, loff_t); #endif -static struct super_operations reiserfs_sops = { +static const struct super_operations reiserfs_sops = { .alloc_inode = reiserfs_alloc_inode, .destroy_inode = reiserfs_destroy_inode, .write_inode = reiserfs_write_inode, diff --git a/fs/romfs/inode.c b/fs/romfs/inode.c index d3e243a6f60..fd601014813 100644 --- a/fs/romfs/inode.c +++ b/fs/romfs/inode.c @@ -110,7 +110,7 @@ romfs_checksum(void *data, int size) return sum; } -static struct super_operations romfs_ops; +static const struct super_operations romfs_ops; static int romfs_fill_super(struct super_block *s, void *data, int silent) { @@ -468,7 +468,7 @@ static const struct file_operations romfs_dir_operations = { .readdir = romfs_readdir, }; -static struct inode_operations romfs_dir_inode_operations = { +static const struct inode_operations romfs_dir_inode_operations = { .lookup = romfs_lookup, }; @@ -598,7 +598,7 @@ static int romfs_remount(struct super_block *sb, int *flags, char *data) return 0; } -static struct super_operations romfs_ops = { +static const struct super_operations romfs_ops = { .alloc_inode = romfs_alloc_inode, .destroy_inode = romfs_destroy_inode, .read_inode = romfs_read_inode, diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index b1e58d1ac9c..50136b1a3ec 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -42,7 +42,7 @@ const struct file_operations smb_dir_operations = .open = smb_dir_open, }; -struct inode_operations smb_dir_inode_operations = +const struct inode_operations smb_dir_inode_operations = { .create = smb_create, .lookup = smb_lookup, @@ -54,7 +54,7 @@ struct inode_operations smb_dir_inode_operations = .setattr = smb_notify_change, }; -struct inode_operations smb_dir_inode_operations_unix = +const struct inode_operations smb_dir_inode_operations_unix = { .create = smb_create, .lookup = smb_lookup, diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index e50533a7951..f161797160c 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -418,7 +418,7 @@ const struct file_operations smb_file_operations = .sendfile = smb_file_sendfile, }; -struct inode_operations smb_file_inode_operations = +const struct inode_operations smb_file_inode_operations = { .permission = smb_file_permission, .getattr = smb_getattr, diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 84dfe3f3482..5faba4f1c9a 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -98,7 +98,7 @@ static int smb_remount(struct super_block *sb, int *flags, char *data) return 0; } -static struct super_operations smb_sops = +static const struct super_operations smb_sops = { .alloc_inode = smb_alloc_inode, .destroy_inode = smb_destroy_inode, diff --git a/fs/smbfs/proto.h b/fs/smbfs/proto.h index 34fb462b237..03f456c1b7d 100644 --- a/fs/smbfs/proto.h +++ b/fs/smbfs/proto.h @@ -36,8 +36,8 @@ extern int smb_proc_link(struct smb_sb_info *server, struct dentry *dentry, stru extern void smb_install_null_ops(struct smb_ops *ops); /* dir.c */ extern const struct file_operations smb_dir_operations; -extern struct inode_operations smb_dir_inode_operations; -extern struct inode_operations smb_dir_inode_operations_unix; +extern const struct inode_operations smb_dir_inode_operations; +extern const struct inode_operations smb_dir_inode_operations_unix; extern void smb_new_dentry(struct dentry *dentry); extern void smb_renew_times(struct dentry *dentry); /* cache.c */ @@ -65,7 +65,7 @@ extern int smb_notify_change(struct dentry *dentry, struct iattr *attr); /* file.c */ extern const struct address_space_operations smb_file_aops; extern const struct file_operations smb_file_operations; -extern struct inode_operations smb_file_inode_operations; +extern const struct inode_operations smb_file_inode_operations; /* ioctl.c */ extern int smb_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); /* smbiod.c */ @@ -84,4 +84,4 @@ extern int smb_request_send_server(struct smb_sb_info *server); extern int smb_request_recv(struct smb_sb_info *server); /* symlink.c */ extern int smb_symlink(struct inode *inode, struct dentry *dentry, const char *oldname); -extern struct inode_operations smb_link_inode_operations; +extern const struct inode_operations smb_link_inode_operations; diff --git a/fs/smbfs/request.c b/fs/smbfs/request.c index a4bcae8a9af..42261dbdf60 100644 --- a/fs/smbfs/request.c +++ b/fs/smbfs/request.c @@ -61,7 +61,7 @@ static struct smb_request *smb_do_alloc_request(struct smb_sb_info *server, struct smb_request *req; unsigned char *buf = NULL; - req = kmem_cache_alloc(req_cachep, GFP_KERNEL); + req = kmem_cache_zalloc(req_cachep, GFP_KERNEL); VERBOSE("allocating request: %p\n", req); if (!req) goto out; @@ -74,7 +74,6 @@ static struct smb_request *smb_do_alloc_request(struct smb_sb_info *server, } } - memset(req, 0, sizeof(struct smb_request)); req->rq_buffer = buf; req->rq_bufsize = bufsize; req->rq_server = server; diff --git a/fs/smbfs/symlink.c b/fs/smbfs/symlink.c index cdc53c4fb38..e4bf3456d07 100644 --- a/fs/smbfs/symlink.c +++ b/fs/smbfs/symlink.c @@ -62,7 +62,7 @@ static void smb_put_link(struct dentry *dentry, struct nameidata *nd, void *p) __putname(s); } -struct inode_operations smb_link_inode_operations = +const struct inode_operations smb_link_inode_operations = { .readlink = generic_readlink, .follow_link = smb_follow_link, diff --git a/fs/super.c b/fs/super.c index 3e7458c2bb7..60b1e50cbf5 100644 --- a/fs/super.c +++ b/fs/super.c @@ -285,7 +285,7 @@ int fsync_super(struct super_block *sb) */ void generic_shutdown_super(struct super_block *sb) { - struct super_operations *sop = sb->s_op; + const struct super_operations *sop = sb->s_op; if (sb->s_root) { shrink_dcache_for_umount(sb); diff --git a/fs/sysfs/dir.c b/fs/sysfs/dir.c index 9dcdf556c99..8813990304f 100644 --- a/fs/sysfs/dir.c +++ b/fs/sysfs/dir.c @@ -37,11 +37,10 @@ static struct sysfs_dirent * __sysfs_new_dirent(void * element) { struct sysfs_dirent * sd; - sd = kmem_cache_alloc(sysfs_dir_cachep, GFP_KERNEL); + sd = kmem_cache_zalloc(sysfs_dir_cachep, GFP_KERNEL); if (!sd) return NULL; - memset(sd, 0, sizeof(*sd)); atomic_set(&sd->s_count, 1); atomic_set(&sd->s_event, 1); INIT_LIST_HEAD(&sd->s_children); @@ -297,7 +296,7 @@ static struct dentry * sysfs_lookup(struct inode *dir, struct dentry *dentry, return ERR_PTR(err); } -struct inode_operations sysfs_dir_inode_operations = { +const struct inode_operations sysfs_dir_inode_operations = { .lookup = sysfs_lookup, .setattr = sysfs_setattr, }; diff --git a/fs/sysfs/inode.c b/fs/sysfs/inode.c index 542d2bcc73d..dd1344b007f 100644 --- a/fs/sysfs/inode.c +++ b/fs/sysfs/inode.c @@ -29,7 +29,7 @@ static struct backing_dev_info sysfs_backing_dev_info = { .capabilities = BDI_CAP_NO_ACCT_DIRTY | BDI_CAP_NO_WRITEBACK, }; -static struct inode_operations sysfs_inode_operations ={ +static const struct inode_operations sysfs_inode_operations ={ .setattr = sysfs_setattr, }; diff --git a/fs/sysfs/mount.c b/fs/sysfs/mount.c index f6a87a82488..23a48a38e6a 100644 --- a/fs/sysfs/mount.c +++ b/fs/sysfs/mount.c @@ -21,7 +21,7 @@ struct kmem_cache *sysfs_dir_cachep; static void sysfs_clear_inode(struct inode *inode); -static struct super_operations sysfs_ops = { +static const struct super_operations sysfs_ops = { .statfs = simple_statfs, .drop_inode = sysfs_delete_inode, .clear_inode = sysfs_clear_inode, diff --git a/fs/sysfs/symlink.c b/fs/sysfs/symlink.c index 4869f611192..7b9c5bfde92 100644 --- a/fs/sysfs/symlink.c +++ b/fs/sysfs/symlink.c @@ -181,7 +181,7 @@ static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *co free_page((unsigned long)page); } -struct inode_operations sysfs_symlink_inode_operations = { +const struct inode_operations sysfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = sysfs_follow_link, .put_link = sysfs_put_link, diff --git a/fs/sysfs/sysfs.h b/fs/sysfs/sysfs.h index fe1cbfd208e..d976b000554 100644 --- a/fs/sysfs/sysfs.h +++ b/fs/sysfs/sysfs.h @@ -26,8 +26,8 @@ extern struct super_block * sysfs_sb; extern const struct file_operations sysfs_dir_operations; extern const struct file_operations sysfs_file_operations; extern const struct file_operations bin_fops; -extern struct inode_operations sysfs_dir_inode_operations; -extern struct inode_operations sysfs_symlink_inode_operations; +extern const struct inode_operations sysfs_dir_inode_operations; +extern const struct inode_operations sysfs_symlink_inode_operations; struct sysfs_symlink { char * link_name; diff --git a/fs/sysv/file.c b/fs/sysv/file.c index 47a4b728f15..0732ddb9020 100644 --- a/fs/sysv/file.c +++ b/fs/sysv/file.c @@ -30,7 +30,7 @@ const struct file_operations sysv_file_operations = { .sendfile = generic_file_sendfile, }; -struct inode_operations sysv_file_inode_operations = { +const struct inode_operations sysv_file_inode_operations = { .truncate = sysv_truncate, .getattr = sysv_getattr, }; diff --git a/fs/sysv/inode.c b/fs/sysv/inode.c index ead9864567e..9311cac186f 100644 --- a/fs/sysv/inode.c +++ b/fs/sysv/inode.c @@ -142,7 +142,7 @@ static inline void write3byte(struct sysv_sb_info *sbi, } } -static struct inode_operations sysv_symlink_inode_operations = { +static const struct inode_operations sysv_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = page_follow_link_light, .put_link = page_put_link, @@ -327,7 +327,7 @@ static void init_once(void *p, struct kmem_cache *cachep, unsigned long flags) inode_init_once(&si->vfs_inode); } -struct super_operations sysv_sops = { +const struct super_operations sysv_sops = { .alloc_inode = sysv_alloc_inode, .destroy_inode = sysv_destroy_inode, .read_inode = sysv_read_inode, diff --git a/fs/sysv/namei.c b/fs/sysv/namei.c index f7c08db8e34..4e48abbd2b5 100644 --- a/fs/sysv/namei.c +++ b/fs/sysv/namei.c @@ -292,7 +292,7 @@ out: /* * directories can handle most operations... */ -struct inode_operations sysv_dir_inode_operations = { +const struct inode_operations sysv_dir_inode_operations = { .create = sysv_create, .lookup = sysv_lookup, .link = sysv_link, diff --git a/fs/sysv/symlink.c b/fs/sysv/symlink.c index b85ce61d635..00d2f8a43e4 100644 --- a/fs/sysv/symlink.c +++ b/fs/sysv/symlink.c @@ -14,7 +14,7 @@ static void *sysv_follow_link(struct dentry *dentry, struct nameidata *nd) return NULL; } -struct inode_operations sysv_fast_symlink_inode_operations = { +const struct inode_operations sysv_fast_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = sysv_follow_link, }; diff --git a/fs/sysv/sysv.h b/fs/sysv/sysv.h index dcb18b2171f..5b4fedf17cc 100644 --- a/fs/sysv/sysv.h +++ b/fs/sysv/sysv.h @@ -159,13 +159,13 @@ extern struct sysv_dir_entry *sysv_dotdot(struct inode *, struct page **); extern ino_t sysv_inode_by_name(struct dentry *); -extern struct inode_operations sysv_file_inode_operations; -extern struct inode_operations sysv_dir_inode_operations; -extern struct inode_operations sysv_fast_symlink_inode_operations; +extern const struct inode_operations sysv_file_inode_operations; +extern const struct inode_operations sysv_dir_inode_operations; +extern const struct inode_operations sysv_fast_symlink_inode_operations; extern const struct file_operations sysv_file_operations; extern const struct file_operations sysv_dir_operations; extern const struct address_space_operations sysv_aops; -extern struct super_operations sysv_sops; +extern const struct super_operations sysv_sops; extern struct dentry_operations sysv_dentry_operations; diff --git a/fs/udf/file.c b/fs/udf/file.c index d81f2db7b0e..40d5047defe 100644 --- a/fs/udf/file.c +++ b/fs/udf/file.c @@ -263,6 +263,6 @@ const struct file_operations udf_file_operations = { .sendfile = generic_file_sendfile, }; -struct inode_operations udf_file_inode_operations = { +const struct inode_operations udf_file_inode_operations = { .truncate = udf_truncate, }; diff --git a/fs/udf/namei.c b/fs/udf/namei.c index 73163325e5e..fe361cd19a9 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c @@ -1308,7 +1308,7 @@ end_rename: return retval; } -struct inode_operations udf_dir_inode_operations = { +const struct inode_operations udf_dir_inode_operations = { .lookup = udf_lookup, .create = udf_create, .link = udf_link, diff --git a/fs/udf/super.c b/fs/udf/super.c index 1dbc2955f02..8672b88f7ff 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -160,7 +160,7 @@ static void destroy_inodecache(void) } /* Superblock operations */ -static struct super_operations udf_sb_ops = { +static const struct super_operations udf_sb_ops = { .alloc_inode = udf_alloc_inode, .destroy_inode = udf_destroy_inode, .write_inode = udf_write_inode, diff --git a/fs/udf/udfdecl.h b/fs/udf/udfdecl.h index 1033b7cf293..ee1dece1f6f 100644 --- a/fs/udf/udfdecl.h +++ b/fs/udf/udfdecl.h @@ -42,9 +42,9 @@ struct task_struct; struct buffer_head; struct super_block; -extern struct inode_operations udf_dir_inode_operations; +extern const struct inode_operations udf_dir_inode_operations; extern const struct file_operations udf_dir_operations; -extern struct inode_operations udf_file_inode_operations; +extern const struct inode_operations udf_file_inode_operations; extern const struct file_operations udf_file_operations; extern const struct address_space_operations udf_aops; extern const struct address_space_operations udf_adinicb_aops; diff --git a/fs/ufs/balloc.c b/fs/ufs/balloc.c index 638f4c585e8..0e97a4f79c3 100644 --- a/fs/ufs/balloc.c +++ b/fs/ufs/balloc.c @@ -4,6 +4,8 @@ * Copyright (C) 1998 * Daniel Pirkl <daniel.pirkl@email.cz> * Charles University, Faculty of Mathematics and Physics + * + * UFS2 write support Evgeniy Dushistov <dushistov@mail.ru>, 2007 */ #include <linux/fs.h> @@ -21,38 +23,42 @@ #include "swab.h" #include "util.h" -static unsigned ufs_add_fragments (struct inode *, unsigned, unsigned, unsigned, int *); -static unsigned ufs_alloc_fragments (struct inode *, unsigned, unsigned, unsigned, int *); -static unsigned ufs_alloccg_block (struct inode *, struct ufs_cg_private_info *, unsigned, int *); -static unsigned ufs_bitmap_search (struct super_block *, struct ufs_cg_private_info *, unsigned, unsigned); +#define INVBLOCK ((u64)-1L) + +static u64 ufs_add_fragments(struct inode *, u64, unsigned, unsigned, int *); +static u64 ufs_alloc_fragments(struct inode *, unsigned, u64, unsigned, int *); +static u64 ufs_alloccg_block(struct inode *, struct ufs_cg_private_info *, u64, int *); +static u64 ufs_bitmap_search (struct super_block *, struct ufs_cg_private_info *, u64, unsigned); static unsigned char ufs_fragtable_8fpb[], ufs_fragtable_other[]; static void ufs_clusteracct(struct super_block *, struct ufs_cg_private_info *, unsigned, int); /* * Free 'count' fragments from fragment number 'fragment' */ -void ufs_free_fragments(struct inode *inode, unsigned fragment, unsigned count) +void ufs_free_fragments(struct inode *inode, u64 fragment, unsigned count) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_cg_private_info * ucpi; struct ufs_cylinder_group * ucg; - unsigned cgno, bit, end_bit, bbase, blkmap, i, blkno, cylno; + unsigned cgno, bit, end_bit, bbase, blkmap, i; + u64 blkno; sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first(uspi); - UFSD("ENTER, fragment %u, count %u\n", fragment, count); + UFSD("ENTER, fragment %llu, count %u\n", + (unsigned long long)fragment, count); if (ufs_fragnum(fragment) + count > uspi->s_fpg) ufs_error (sb, "ufs_free_fragments", "internal error"); lock_super(sb); - cgno = ufs_dtog(fragment); - bit = ufs_dtogd(fragment); + cgno = ufs_dtog(uspi, fragment); + bit = ufs_dtogd(uspi, fragment); if (cgno >= uspi->s_ncg) { ufs_panic (sb, "ufs_free_fragments", "freeing blocks are outside device"); goto failed; @@ -101,9 +107,13 @@ void ufs_free_fragments(struct inode *inode, unsigned fragment, unsigned count) fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1); uspi->cs_total.cs_nbfree++; fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1); - cylno = ufs_cbtocylno (bbase); - fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(bbase)), 1); - fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1); + if (uspi->fs_magic != UFS2_MAGIC) { + unsigned cylno = ufs_cbtocylno (bbase); + + fs16_add(sb, &ubh_cg_blks(ucpi, cylno, + ufs_cbtorpos(bbase)), 1); + fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1); + } } ubh_mark_buffer_dirty (USPI_UBH(uspi)); @@ -127,24 +137,27 @@ failed: /* * Free 'count' fragments from fragment number 'fragment' (free whole blocks) */ -void ufs_free_blocks(struct inode *inode, unsigned fragment, unsigned count) +void ufs_free_blocks(struct inode *inode, u64 fragment, unsigned count) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_cg_private_info * ucpi; struct ufs_cylinder_group * ucg; - unsigned overflow, cgno, bit, end_bit, blkno, i, cylno; + unsigned overflow, cgno, bit, end_bit, i; + u64 blkno; sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first(uspi); - UFSD("ENTER, fragment %u, count %u\n", fragment, count); + UFSD("ENTER, fragment %llu, count %u\n", + (unsigned long long)fragment, count); if ((fragment & uspi->s_fpbmask) || (count & uspi->s_fpbmask)) { ufs_error (sb, "ufs_free_blocks", "internal error, " - "fragment %u, count %u\n", fragment, count); + "fragment %llu, count %u\n", + (unsigned long long)fragment, count); goto failed; } @@ -152,8 +165,8 @@ void ufs_free_blocks(struct inode *inode, unsigned fragment, unsigned count) do_more: overflow = 0; - cgno = ufs_dtog (fragment); - bit = ufs_dtogd (fragment); + cgno = ufs_dtog(uspi, fragment); + bit = ufs_dtogd(uspi, fragment); if (cgno >= uspi->s_ncg) { ufs_panic (sb, "ufs_free_blocks", "freeing blocks are outside device"); goto failed_unlock; @@ -187,9 +200,14 @@ do_more: fs32_add(sb, &ucg->cg_cs.cs_nbfree, 1); uspi->cs_total.cs_nbfree++; fs32_add(sb, &UFS_SB(sb)->fs_cs(cgno).cs_nbfree, 1); - cylno = ufs_cbtocylno(i); - fs16_add(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(i)), 1); - fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1); + + if (uspi->fs_magic != UFS2_MAGIC) { + unsigned cylno = ufs_cbtocylno(i); + + fs16_add(sb, &ubh_cg_blks(ucpi, cylno, + ufs_cbtorpos(i)), 1); + fs32_add(sb, &ubh_cg_blktot(ucpi, cylno), 1); + } } ubh_mark_buffer_dirty (USPI_UBH(uspi)); @@ -308,15 +326,19 @@ static void ufs_clear_frags(struct inode *inode, sector_t beg, unsigned int n, } } -unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment, - unsigned goal, unsigned count, int * err, struct page *locked_page) +u64 ufs_new_fragments(struct inode *inode, void *p, u64 fragment, + u64 goal, unsigned count, int *err, + struct page *locked_page) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; - unsigned cgno, oldcount, newcount, tmp, request, result; + unsigned cgno, oldcount, newcount; + u64 tmp, request, result; - UFSD("ENTER, ino %lu, fragment %u, goal %u, count %u\n", inode->i_ino, fragment, goal, count); + UFSD("ENTER, ino %lu, fragment %llu, goal %llu, count %u\n", + inode->i_ino, (unsigned long long)fragment, + (unsigned long long)goal, count); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; @@ -324,11 +346,12 @@ unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment, *err = -ENOSPC; lock_super (sb); - - tmp = fs32_to_cpu(sb, *p); + tmp = ufs_data_ptr_to_cpu(sb, p); + if (count + ufs_fragnum(fragment) > uspi->s_fpb) { - ufs_warning (sb, "ufs_new_fragments", "internal warning" - " fragment %u, count %u", fragment, count); + ufs_warning(sb, "ufs_new_fragments", "internal warning" + " fragment %llu, count %u", + (unsigned long long)fragment, count); count = uspi->s_fpb - ufs_fragnum(fragment); } oldcount = ufs_fragnum (fragment); @@ -339,10 +362,12 @@ unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment, */ if (oldcount) { if (!tmp) { - ufs_error (sb, "ufs_new_fragments", "internal error, " - "fragment %u, tmp %u\n", fragment, tmp); - unlock_super (sb); - return (unsigned)-1; + ufs_error(sb, "ufs_new_fragments", "internal error, " + "fragment %llu, tmp %llu\n", + (unsigned long long)fragment, + (unsigned long long)tmp); + unlock_super(sb); + return INVBLOCK; } if (fragment < UFS_I(inode)->i_lastfrag) { UFSD("EXIT (ALREADY ALLOCATED)\n"); @@ -372,7 +397,7 @@ unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment, if (goal == 0) cgno = ufs_inotocg (inode->i_ino); else - cgno = ufs_dtog (goal); + cgno = ufs_dtog(uspi, goal); /* * allocate new fragment @@ -380,14 +405,16 @@ unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment, if (oldcount == 0) { result = ufs_alloc_fragments (inode, cgno, goal, count, err); if (result) { - *p = cpu_to_fs32(sb, result); + ufs_cpu_to_data_ptr(sb, p, result); *err = 0; - UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count); - ufs_clear_frags(inode, result + oldcount, newcount - oldcount, - locked_page != NULL); + UFS_I(inode)->i_lastfrag = + max_t(u32, UFS_I(inode)->i_lastfrag, + fragment + count); + ufs_clear_frags(inode, result + oldcount, + newcount - oldcount, locked_page != NULL); } unlock_super(sb); - UFSD("EXIT, result %u\n", result); + UFSD("EXIT, result %llu\n", (unsigned long long)result); return result; } @@ -401,7 +428,7 @@ unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment, ufs_clear_frags(inode, result + oldcount, newcount - oldcount, locked_page != NULL); unlock_super(sb); - UFSD("EXIT, result %u\n", result); + UFSD("EXIT, result %llu\n", (unsigned long long)result); return result; } @@ -433,15 +460,14 @@ unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment, locked_page != NULL); ufs_change_blocknr(inode, fragment - oldcount, oldcount, tmp, result, locked_page); - - *p = cpu_to_fs32(sb, result); + ufs_cpu_to_data_ptr(sb, p, result); *err = 0; UFS_I(inode)->i_lastfrag = max_t(u32, UFS_I(inode)->i_lastfrag, fragment + count); unlock_super(sb); if (newcount < request) ufs_free_fragments (inode, result + newcount, request - newcount); ufs_free_fragments (inode, tmp, oldcount); - UFSD("EXIT, result %u\n", result); + UFSD("EXIT, result %llu\n", (unsigned long long)result); return result; } @@ -450,9 +476,8 @@ unsigned ufs_new_fragments(struct inode * inode, __fs32 * p, unsigned fragment, return 0; } -static unsigned -ufs_add_fragments (struct inode * inode, unsigned fragment, - unsigned oldcount, unsigned newcount, int * err) +static u64 ufs_add_fragments(struct inode *inode, u64 fragment, + unsigned oldcount, unsigned newcount, int *err) { struct super_block * sb; struct ufs_sb_private_info * uspi; @@ -461,14 +486,15 @@ ufs_add_fragments (struct inode * inode, unsigned fragment, struct ufs_cylinder_group * ucg; unsigned cgno, fragno, fragoff, count, fragsize, i; - UFSD("ENTER, fragment %u, oldcount %u, newcount %u\n", fragment, oldcount, newcount); + UFSD("ENTER, fragment %llu, oldcount %u, newcount %u\n", + (unsigned long long)fragment, oldcount, newcount); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; usb1 = ubh_get_usb_first (uspi); count = newcount - oldcount; - cgno = ufs_dtog(fragment); + cgno = ufs_dtog(uspi, fragment); if (fs32_to_cpu(sb, UFS_SB(sb)->fs_cs(cgno).cs_nffree) < count) return 0; if ((ufs_fragnum (fragment) + newcount) > uspi->s_fpb) @@ -483,7 +509,7 @@ ufs_add_fragments (struct inode * inode, unsigned fragment, return 0; } - fragno = ufs_dtogd (fragment); + fragno = ufs_dtogd(uspi, fragment); fragoff = ufs_fragnum (fragno); for (i = oldcount; i < newcount; i++) if (ubh_isclr (UCPI_UBH(ucpi), ucpi->c_freeoff, fragno + i)) @@ -521,7 +547,7 @@ ufs_add_fragments (struct inode * inode, unsigned fragment, } sb->s_dirt = 1; - UFSD("EXIT, fragment %u\n", fragment); + UFSD("EXIT, fragment %llu\n", (unsigned long long)fragment); return fragment; } @@ -534,17 +560,19 @@ ufs_add_fragments (struct inode * inode, unsigned fragment, if (fs32_to_cpu(sb, ucg->cg_frsum[k])) \ goto cg_found; -static unsigned ufs_alloc_fragments (struct inode * inode, unsigned cgno, - unsigned goal, unsigned count, int * err) +static u64 ufs_alloc_fragments(struct inode *inode, unsigned cgno, + u64 goal, unsigned count, int *err) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_cg_private_info * ucpi; struct ufs_cylinder_group * ucg; - unsigned oldcg, i, j, k, result, allocsize; + unsigned oldcg, i, j, k, allocsize; + u64 result; - UFSD("ENTER, ino %lu, cgno %u, goal %u, count %u\n", inode->i_ino, cgno, goal, count); + UFSD("ENTER, ino %lu, cgno %u, goal %llu, count %u\n", + inode->i_ino, cgno, (unsigned long long)goal, count); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; @@ -593,7 +621,7 @@ cg_found: if (count == uspi->s_fpb) { result = ufs_alloccg_block (inode, ucpi, goal, err); - if (result == (unsigned)-1) + if (result == INVBLOCK) return 0; goto succed; } @@ -604,9 +632,9 @@ cg_found: if (allocsize == uspi->s_fpb) { result = ufs_alloccg_block (inode, ucpi, goal, err); - if (result == (unsigned)-1) + if (result == INVBLOCK) return 0; - goal = ufs_dtogd (result); + goal = ufs_dtogd(uspi, result); for (i = count; i < uspi->s_fpb; i++) ubh_setbit (UCPI_UBH(ucpi), ucpi->c_freeoff, goal + i); i = uspi->s_fpb - count; @@ -620,7 +648,7 @@ cg_found: } result = ufs_bitmap_search (sb, ucpi, goal, allocsize); - if (result == (unsigned)-1) + if (result == INVBLOCK) return 0; if(DQUOT_ALLOC_BLOCK(inode, count)) { *err = -EDQUOT; @@ -647,20 +675,21 @@ succed: sb->s_dirt = 1; result += cgno * uspi->s_fpg; - UFSD("EXIT3, result %u\n", result); + UFSD("EXIT3, result %llu\n", (unsigned long long)result); return result; } -static unsigned ufs_alloccg_block (struct inode * inode, - struct ufs_cg_private_info * ucpi, unsigned goal, int * err) +static u64 ufs_alloccg_block(struct inode *inode, + struct ufs_cg_private_info *ucpi, + u64 goal, int *err) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_super_block_first * usb1; struct ufs_cylinder_group * ucg; - unsigned result, cylno, blkno; + u64 result, blkno; - UFSD("ENTER, goal %u\n", goal); + UFSD("ENTER, goal %llu\n", (unsigned long long)goal); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; @@ -672,7 +701,7 @@ static unsigned ufs_alloccg_block (struct inode * inode, goto norot; } goal = ufs_blknum (goal); - goal = ufs_dtogd (goal); + goal = ufs_dtogd(uspi, goal); /* * If the requested block is available, use it. @@ -684,8 +713,8 @@ static unsigned ufs_alloccg_block (struct inode * inode, norot: result = ufs_bitmap_search (sb, ucpi, goal, uspi->s_fpb); - if (result == (unsigned)-1) - return (unsigned)-1; + if (result == INVBLOCK) + return INVBLOCK; ucpi->c_rotor = result; gotit: blkno = ufs_fragstoblks(result); @@ -694,17 +723,22 @@ gotit: ufs_clusteracct (sb, ucpi, blkno, -1); if(DQUOT_ALLOC_BLOCK(inode, uspi->s_fpb)) { *err = -EDQUOT; - return (unsigned)-1; + return INVBLOCK; } fs32_sub(sb, &ucg->cg_cs.cs_nbfree, 1); uspi->cs_total.cs_nbfree--; fs32_sub(sb, &UFS_SB(sb)->fs_cs(ucpi->c_cgx).cs_nbfree, 1); - cylno = ufs_cbtocylno(result); - fs16_sub(sb, &ubh_cg_blks(ucpi, cylno, ufs_cbtorpos(result)), 1); - fs32_sub(sb, &ubh_cg_blktot(ucpi, cylno), 1); + + if (uspi->fs_magic != UFS2_MAGIC) { + unsigned cylno = ufs_cbtocylno((unsigned)result); + + fs16_sub(sb, &ubh_cg_blks(ucpi, cylno, + ufs_cbtorpos((unsigned)result)), 1); + fs32_sub(sb, &ubh_cg_blktot(ucpi, cylno), 1); + } - UFSD("EXIT, result %u\n", result); + UFSD("EXIT, result %llu\n", (unsigned long long)result); return result; } @@ -744,9 +778,9 @@ static unsigned ubh_scanc(struct ufs_sb_private_info *uspi, * @goal: near which block we want find new one * @count: specified size */ -static unsigned ufs_bitmap_search(struct super_block *sb, - struct ufs_cg_private_info *ucpi, - unsigned goal, unsigned count) +static u64 ufs_bitmap_search(struct super_block *sb, + struct ufs_cg_private_info *ucpi, + u64 goal, unsigned count) { /* * Bit patterns for identifying fragments in the block map @@ -761,16 +795,18 @@ static unsigned ufs_bitmap_search(struct super_block *sb, struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; struct ufs_super_block_first *usb1; struct ufs_cylinder_group *ucg; - unsigned start, length, loc, result; + unsigned start, length, loc; unsigned pos, want, blockmap, mask, end; + u64 result; - UFSD("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count); + UFSD("ENTER, cg %u, goal %llu, count %u\n", ucpi->c_cgx, + (unsigned long long)goal, count); usb1 = ubh_get_usb_first (uspi); ucg = ubh_get_ucg(UCPI_UBH(ucpi)); if (goal) - start = ufs_dtogd(goal) >> 3; + start = ufs_dtogd(uspi, goal) >> 3; else start = ucpi->c_frotor >> 3; @@ -790,7 +826,7 @@ static unsigned ufs_bitmap_search(struct super_block *sb, " length %u, count %u, freeoff %u\n", ucpi->c_cgx, start, length, count, ucpi->c_freeoff); - return (unsigned)-1; + return INVBLOCK; } start = 0; } @@ -808,7 +844,8 @@ static unsigned ufs_bitmap_search(struct super_block *sb, want = want_arr[count]; for (pos = 0; pos <= uspi->s_fpb - count; pos++) { if ((blockmap & mask) == want) { - UFSD("EXIT, result %u\n", result); + UFSD("EXIT, result %llu\n", + (unsigned long long)result); return result + pos; } mask <<= 1; @@ -819,7 +856,7 @@ static unsigned ufs_bitmap_search(struct super_block *sb, ufs_error(sb, "ufs_bitmap_search", "block not in map on cg %u\n", ucpi->c_cgx); UFSD("EXIT (FAILED)\n"); - return (unsigned)-1; + return INVBLOCK; } static void ufs_clusteracct(struct super_block * sb, diff --git a/fs/ufs/dir.c b/fs/ufs/dir.c index 433b6f68403..a6c0ca9f48b 100644 --- a/fs/ufs/dir.c +++ b/fs/ufs/dir.c @@ -106,12 +106,13 @@ static void ufs_check_page(struct page *page) char *kaddr = page_address(page); unsigned offs, rec_len; unsigned limit = PAGE_CACHE_SIZE; + const unsigned chunk_mask = UFS_SB(sb)->s_uspi->s_dirblksize - 1; struct ufs_dir_entry *p; char *error; if ((dir->i_size >> PAGE_CACHE_SHIFT) == page->index) { limit = dir->i_size & ~PAGE_CACHE_MASK; - if (limit & (UFS_SECTOR_SIZE - 1)) + if (limit & chunk_mask) goto Ebadsize; if (!limit) goto out; @@ -126,7 +127,7 @@ static void ufs_check_page(struct page *page) goto Ealign; if (rec_len < UFS_DIR_REC_LEN(ufs_get_de_namlen(sb, p))) goto Enamelen; - if (((offs + rec_len - 1) ^ offs) & ~(UFS_SECTOR_SIZE-1)) + if (((offs + rec_len - 1) ^ offs) & ~chunk_mask) goto Espan; if (fs32_to_cpu(sb, p->d_ino) > (UFS_SB(sb)->s_uspi->s_ipg * UFS_SB(sb)->s_uspi->s_ncg)) @@ -310,6 +311,7 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode) int namelen = dentry->d_name.len; struct super_block *sb = dir->i_sb; unsigned reclen = UFS_DIR_REC_LEN(namelen); + const unsigned int chunk_size = UFS_SB(sb)->s_uspi->s_dirblksize; unsigned short rec_len, name_len; struct page *page = NULL; struct ufs_dir_entry *de; @@ -342,8 +344,8 @@ int ufs_add_link(struct dentry *dentry, struct inode *inode) if ((char *)de == dir_end) { /* We hit i_size */ name_len = 0; - rec_len = UFS_SECTOR_SIZE; - de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE); + rec_len = chunk_size; + de->d_reclen = cpu_to_fs16(sb, chunk_size); de->d_ino = 0; goto got_it; } @@ -431,7 +433,7 @@ ufs_readdir(struct file *filp, void *dirent, filldir_t filldir) unsigned int offset = pos & ~PAGE_CACHE_MASK; unsigned long n = pos >> PAGE_CACHE_SHIFT; unsigned long npages = ufs_dir_pages(inode); - unsigned chunk_mask = ~(UFS_SECTOR_SIZE - 1); + unsigned chunk_mask = ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1); int need_revalidate = filp->f_version != inode->i_version; unsigned flags = UFS_SB(sb)->s_flags; @@ -511,7 +513,7 @@ int ufs_delete_entry(struct inode *inode, struct ufs_dir_entry *dir, struct super_block *sb = inode->i_sb; struct address_space *mapping = page->mapping; char *kaddr = page_address(page); - unsigned from = ((char*)dir - kaddr) & ~(UFS_SECTOR_SIZE - 1); + unsigned from = ((char*)dir - kaddr) & ~(UFS_SB(sb)->s_uspi->s_dirblksize - 1); unsigned to = ((char*)dir - kaddr) + fs16_to_cpu(sb, dir->d_reclen); struct ufs_dir_entry *pde = NULL; struct ufs_dir_entry *de = (struct ufs_dir_entry *) (kaddr + from); @@ -556,6 +558,7 @@ int ufs_make_empty(struct inode * inode, struct inode *dir) struct super_block * sb = dir->i_sb; struct address_space *mapping = inode->i_mapping; struct page *page = grab_cache_page(mapping, 0); + const unsigned int chunk_size = UFS_SB(sb)->s_uspi->s_dirblksize; struct ufs_dir_entry * de; char *base; int err; @@ -563,7 +566,7 @@ int ufs_make_empty(struct inode * inode, struct inode *dir) if (!page) return -ENOMEM; kmap(page); - err = mapping->a_ops->prepare_write(NULL, page, 0, UFS_SECTOR_SIZE); + err = mapping->a_ops->prepare_write(NULL, page, 0, chunk_size); if (err) { unlock_page(page); goto fail; @@ -584,11 +587,11 @@ int ufs_make_empty(struct inode * inode, struct inode *dir) ((char *)de + fs16_to_cpu(sb, de->d_reclen)); de->d_ino = cpu_to_fs32(sb, dir->i_ino); ufs_set_de_type(sb, de, dir->i_mode); - de->d_reclen = cpu_to_fs16(sb, UFS_SECTOR_SIZE - UFS_DIR_REC_LEN(1)); + de->d_reclen = cpu_to_fs16(sb, chunk_size - UFS_DIR_REC_LEN(1)); ufs_set_de_namlen(sb, de, 2); strcpy (de->d_name, ".."); - err = ufs_commit_chunk(page, 0, UFS_SECTOR_SIZE); + err = ufs_commit_chunk(page, 0, chunk_size); fail: kunmap(page); page_cache_release(page); diff --git a/fs/ufs/ialloc.c b/fs/ufs/ialloc.c index 2ad1259c6ec..b868878009b 100644 --- a/fs/ufs/ialloc.c +++ b/fs/ufs/ialloc.c @@ -18,6 +18,9 @@ * Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 * Big-endian to little-endian byte-swapping/bitmaps by * David S. Miller (davem@caip.rutgers.edu), 1995 + * + * UFS2 write support added by + * Evgeniy Dushistov <dushistov@mail.ru>, 2007 */ #include <linux/fs.h> @@ -126,6 +129,47 @@ void ufs_free_inode (struct inode * inode) } /* + * Nullify new chunk of inodes, + * BSD people also set ui_gen field of inode + * during nullification, but we not care about + * that because of linux ufs do not support NFS + */ +static void ufs2_init_inodes_chunk(struct super_block *sb, + struct ufs_cg_private_info *ucpi, + struct ufs_cylinder_group *ucg) +{ + struct buffer_head *bh; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + sector_t beg = uspi->s_sbbase + + ufs_inotofsba(ucpi->c_cgx * uspi->s_ipg + + fs32_to_cpu(sb, ucg->cg_u.cg_u2.cg_initediblk)); + sector_t end = beg + uspi->s_fpb; + + UFSD("ENTER cgno %d\n", ucpi->c_cgx); + + for (; beg < end; ++beg) { + bh = sb_getblk(sb, beg); + lock_buffer(bh); + memset(bh->b_data, 0, sb->s_blocksize); + set_buffer_uptodate(bh); + mark_buffer_dirty(bh); + unlock_buffer(bh); + if (sb->s_flags & MS_SYNCHRONOUS) + sync_dirty_buffer(bh); + brelse(bh); + } + + fs32_add(sb, &ucg->cg_u.cg_u2.cg_initediblk, uspi->s_inopb); + ubh_mark_buffer_dirty(UCPI_UBH(ucpi)); + if (sb->s_flags & MS_SYNCHRONOUS) { + ubh_ll_rw_block(SWRITE, UCPI_UBH(ucpi)); + ubh_wait_on_buffer(UCPI_UBH(ucpi)); + } + + UFSD("EXIT\n"); +} + +/* * There are two policies for allocating an inode. If the new inode is * a directory, then a forward search is made for a block group with both * free space and a low directory-to-inode ratio; if that fails, then of @@ -146,6 +190,7 @@ struct inode * ufs_new_inode(struct inode * dir, int mode) struct inode * inode; unsigned cg, bit, i, j, start; struct ufs_inode_info *ufsi; + int err = -ENOSPC; UFSD("ENTER\n"); @@ -198,13 +243,15 @@ struct inode * ufs_new_inode(struct inode * dir, int mode) goto cg_found; } } - + goto failed; cg_found: ucpi = ufs_load_cylinder (sb, cg); - if (!ucpi) + if (!ucpi) { + err = -EIO; goto failed; + } ucg = ubh_get_ucg(UCPI_UBH(ucpi)); if (!ufs_cg_chkmagic(sb, ucg)) ufs_panic (sb, "ufs_new_inode", "internal error, bad cg magic number"); @@ -216,6 +263,7 @@ cg_found: if (!(bit < start)) { ufs_error (sb, "ufs_new_inode", "cylinder group %u corrupted - error in inode bitmap\n", cg); + err = -EIO; goto failed; } } @@ -224,9 +272,18 @@ cg_found: ubh_setbit (UCPI_UBH(ucpi), ucpi->c_iusedoff, bit); else { ufs_panic (sb, "ufs_new_inode", "internal error"); + err = -EIO; goto failed; } - + + if (uspi->fs_magic == UFS2_MAGIC) { + u32 initediblk = fs32_to_cpu(sb, ucg->cg_u.cg_u2.cg_initediblk); + + if (bit + uspi->s_inopb > initediblk && + initediblk < fs32_to_cpu(sb, ucg->cg_u.cg_u2.cg_niblk)) + ufs2_init_inodes_chunk(sb, ucpi, ucg); + } + fs32_sub(sb, &ucg->cg_cs.cs_nifree, 1); uspi->cs_total.cs_nifree--; fs32_sub(sb, &sbi->fs_cs(cg).cs_nifree, 1); @@ -236,7 +293,6 @@ cg_found: uspi->cs_total.cs_ndir++; fs32_add(sb, &sbi->fs_cs(cg).cs_ndir, 1); } - ubh_mark_buffer_dirty (USPI_UBH(uspi)); ubh_mark_buffer_dirty (UCPI_UBH(ucpi)); if (sb->s_flags & MS_SYNCHRONOUS) { @@ -245,6 +301,7 @@ cg_found: } sb->s_dirt = 1; + inode->i_ino = cg * uspi->s_ipg + bit; inode->i_mode = mode; inode->i_uid = current->fsuid; if (dir->i_mode & S_ISGID) { @@ -254,39 +311,72 @@ cg_found: } else inode->i_gid = current->fsgid; - inode->i_ino = cg * uspi->s_ipg + bit; inode->i_blocks = 0; + inode->i_generation = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; ufsi->i_flags = UFS_I(dir)->i_flags; ufsi->i_lastfrag = 0; - ufsi->i_gen = 0; ufsi->i_shadow = 0; ufsi->i_osync = 0; ufsi->i_oeftflag = 0; ufsi->i_dir_start_lookup = 0; memset(&ufsi->i_u1, 0, sizeof(ufsi->i_u1)); - insert_inode_hash(inode); mark_inode_dirty(inode); + if (uspi->fs_magic == UFS2_MAGIC) { + struct buffer_head *bh; + struct ufs2_inode *ufs2_inode; + + /* + * setup birth date, we do it here because of there is no sense + * to hold it in struct ufs_inode_info, and lose 64 bit + */ + bh = sb_bread(sb, uspi->s_sbbase + ufs_inotofsba(inode->i_ino)); + if (!bh) { + ufs_warning(sb, "ufs_read_inode", + "unable to read inode %lu\n", + inode->i_ino); + err = -EIO; + goto fail_remove_inode; + } + lock_buffer(bh); + ufs2_inode = (struct ufs2_inode *)bh->b_data; + ufs2_inode += ufs_inotofsbo(inode->i_ino); + ufs2_inode->ui_birthtime.tv_sec = + cpu_to_fs32(sb, CURRENT_TIME_SEC.tv_sec); + ufs2_inode->ui_birthtime.tv_usec = 0; + mark_buffer_dirty(bh); + unlock_buffer(bh); + if (sb->s_flags & MS_SYNCHRONOUS) + sync_dirty_buffer(bh); + brelse(bh); + } + unlock_super (sb); if (DQUOT_ALLOC_INODE(inode)) { DQUOT_DROP(inode); - inode->i_flags |= S_NOQUOTA; - inode->i_nlink = 0; - iput(inode); - return ERR_PTR(-EDQUOT); + err = -EDQUOT; + goto fail_without_unlock; } UFSD("allocating inode %lu\n", inode->i_ino); UFSD("EXIT\n"); return inode; +fail_remove_inode: + unlock_super(sb); +fail_without_unlock: + inode->i_flags |= S_NOQUOTA; + inode->i_nlink = 0; + iput(inode); + UFSD("EXIT (FAILED): err %d\n", err); + return ERR_PTR(err); failed: unlock_super (sb); make_bad_inode(inode); iput (inode); - UFSD("EXIT (FAILED)\n"); - return ERR_PTR(-ENOSPC); + UFSD("EXIT (FAILED): err %d\n", err); + return ERR_PTR(err); } diff --git a/fs/ufs/inode.c b/fs/ufs/inode.c index 4295ca91cf8..fb34ad03e22 100644 --- a/fs/ufs/inode.c +++ b/fs/ufs/inode.c @@ -170,7 +170,7 @@ out: * @locked_page - for ufs_new_fragments() */ static struct buffer_head * -ufs_inode_getfrag(struct inode *inode, unsigned int fragment, +ufs_inode_getfrag(struct inode *inode, u64 fragment, sector_t new_fragment, unsigned int required, int *err, long *phys, int *new, struct page *locked_page) { @@ -178,12 +178,12 @@ ufs_inode_getfrag(struct inode *inode, unsigned int fragment, struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; struct buffer_head * result; - unsigned block, blockoff, lastfrag, lastblock, lastblockoff; - unsigned tmp, goal; - __fs32 * p, * p2; + unsigned blockoff, lastblockoff; + u64 tmp, goal, lastfrag, block, lastblock; + void *p, *p2; - UFSD("ENTER, ino %lu, fragment %u, new_fragment %llu, required %u, " - "metadata %d\n", inode->i_ino, fragment, + UFSD("ENTER, ino %lu, fragment %llu, new_fragment %llu, required %u, " + "metadata %d\n", inode->i_ino, (unsigned long long)fragment, (unsigned long long)new_fragment, required, !phys); /* TODO : to be done for write support @@ -193,17 +193,20 @@ ufs_inode_getfrag(struct inode *inode, unsigned int fragment, block = ufs_fragstoblks (fragment); blockoff = ufs_fragnum (fragment); - p = ufsi->i_u1.i_data + block; + p = ufs_get_direct_data_ptr(uspi, ufsi, block); + goal = 0; repeat: - tmp = fs32_to_cpu(sb, *p); + tmp = ufs_data_ptr_to_cpu(sb, p); + lastfrag = ufsi->i_lastfrag; if (tmp && fragment < lastfrag) { if (!phys) { result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); - if (tmp == fs32_to_cpu(sb, *p)) { - UFSD("EXIT, result %u\n", tmp + blockoff); + if (tmp == ufs_data_ptr_to_cpu(sb, p)) { + UFSD("EXIT, result %llu\n", + (unsigned long long)tmp + blockoff); return result; } brelse (result); @@ -224,10 +227,11 @@ repeat: * We must reallocate last allocated block */ if (lastblockoff) { - p2 = ufsi->i_u1.i_data + lastblock; - tmp = ufs_new_fragments (inode, p2, lastfrag, - fs32_to_cpu(sb, *p2), uspi->s_fpb - lastblockoff, - err, locked_page); + p2 = ufs_get_direct_data_ptr(uspi, ufsi, lastblock); + tmp = ufs_new_fragments(inode, p2, lastfrag, + ufs_data_ptr_to_cpu(sb, p2), + uspi->s_fpb - lastblockoff, + err, locked_page); if (!tmp) { if (lastfrag != ufsi->i_lastfrag) goto repeat; @@ -237,27 +241,31 @@ repeat: lastfrag = ufsi->i_lastfrag; } - tmp = fs32_to_cpu(sb, ufsi->i_u1.i_data[lastblock]); + tmp = ufs_data_ptr_to_cpu(sb, + ufs_get_direct_data_ptr(uspi, ufsi, + lastblock)); if (tmp) goal = tmp + uspi->s_fpb; tmp = ufs_new_fragments (inode, p, fragment - blockoff, goal, required + blockoff, err, phys != NULL ? locked_page : NULL); - } + } else if (lastblock == block) { /* * We will extend last allocated block */ - else if (lastblock == block) { - tmp = ufs_new_fragments(inode, p, fragment - (blockoff - lastblockoff), - fs32_to_cpu(sb, *p), required + (blockoff - lastblockoff), + tmp = ufs_new_fragments(inode, p, fragment - + (blockoff - lastblockoff), + ufs_data_ptr_to_cpu(sb, p), + required + (blockoff - lastblockoff), err, phys != NULL ? locked_page : NULL); } else /* (lastblock > block) */ { /* * We will allocate new block before last allocated block */ if (block) { - tmp = fs32_to_cpu(sb, ufsi->i_u1.i_data[block-1]); + tmp = ufs_data_ptr_to_cpu(sb, + ufs_get_direct_data_ptr(uspi, ufsi, block - 1)); if (tmp) goal = tmp + uspi->s_fpb; } @@ -266,7 +274,7 @@ repeat: phys != NULL ? locked_page : NULL); } if (!tmp) { - if ((!blockoff && *p) || + if ((!blockoff && ufs_data_ptr_to_cpu(sb, p)) || (blockoff && lastfrag != ufsi->i_lastfrag)) goto repeat; *err = -ENOSPC; @@ -286,7 +294,7 @@ repeat: if (IS_SYNC(inode)) ufs_sync_inode (inode); mark_inode_dirty(inode); - UFSD("EXIT, result %u\n", tmp + blockoff); + UFSD("EXIT, result %llu\n", (unsigned long long)tmp + blockoff); return result; /* This part : To be implemented .... @@ -320,20 +328,22 @@ repeat2: */ static struct buffer_head * ufs_inode_getblock(struct inode *inode, struct buffer_head *bh, - unsigned int fragment, sector_t new_fragment, int *err, + u64 fragment, sector_t new_fragment, int *err, long *phys, int *new, struct page *locked_page) { struct super_block *sb = inode->i_sb; struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; struct buffer_head * result; - unsigned tmp, goal, block, blockoff; - __fs32 * p; + unsigned blockoff; + u64 tmp, goal, block; + void *p; block = ufs_fragstoblks (fragment); blockoff = ufs_fragnum (fragment); - UFSD("ENTER, ino %lu, fragment %u, new_fragment %llu, metadata %d\n", - inode->i_ino, fragment, (unsigned long long)new_fragment, !phys); + UFSD("ENTER, ino %lu, fragment %llu, new_fragment %llu, metadata %d\n", + inode->i_ino, (unsigned long long)fragment, + (unsigned long long)new_fragment, !phys); result = NULL; if (!bh) @@ -344,14 +354,16 @@ ufs_inode_getblock(struct inode *inode, struct buffer_head *bh, if (!buffer_uptodate(bh)) goto out; } - - p = (__fs32 *) bh->b_data + block; + if (uspi->fs_magic == UFS2_MAGIC) + p = (__fs64 *)bh->b_data + block; + else + p = (__fs32 *)bh->b_data + block; repeat: - tmp = fs32_to_cpu(sb, *p); + tmp = ufs_data_ptr_to_cpu(sb, p); if (tmp) { if (!phys) { result = sb_getblk(sb, uspi->s_sbbase + tmp + blockoff); - if (tmp == fs32_to_cpu(sb, *p)) + if (tmp == ufs_data_ptr_to_cpu(sb, p)) goto out; brelse (result); goto repeat; @@ -361,14 +373,16 @@ repeat: } } - if (block && (tmp = fs32_to_cpu(sb, ((__fs32*)bh->b_data)[block-1]))) + if (block && (uspi->fs_magic == UFS2_MAGIC ? + (tmp = fs64_to_cpu(sb, ((__fs64 *)bh->b_data)[block-1])) : + (tmp = fs32_to_cpu(sb, ((__fs32 *)bh->b_data)[block-1])))) goal = tmp + uspi->s_fpb; else goal = bh->b_blocknr + uspi->s_fpb; tmp = ufs_new_fragments(inode, p, ufs_blknum(new_fragment), goal, uspi->s_fpb, err, locked_page); if (!tmp) { - if (fs32_to_cpu(sb, *p)) + if (ufs_data_ptr_to_cpu(sb, p)) goto repeat; goto out; } @@ -386,7 +400,7 @@ repeat: sync_dirty_buffer(bh); inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(inode); - UFSD("result %u\n", tmp + blockoff); + UFSD("result %llu\n", (unsigned long long)tmp + blockoff); out: brelse (bh); UFSD("EXIT\n"); @@ -616,8 +630,8 @@ static void ufs1_read_inode(struct inode *inode, struct ufs_inode *ufs_inode) inode->i_atime.tv_nsec = 0; inode->i_ctime.tv_nsec = 0; inode->i_blocks = fs32_to_cpu(sb, ufs_inode->ui_blocks); + inode->i_generation = fs32_to_cpu(sb, ufs_inode->ui_gen); ufsi->i_flags = fs32_to_cpu(sb, ufs_inode->ui_flags); - ufsi->i_gen = fs32_to_cpu(sb, ufs_inode->ui_gen); ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow); ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag); @@ -661,8 +675,8 @@ static void ufs2_read_inode(struct inode *inode, struct ufs2_inode *ufs2_inode) inode->i_atime.tv_nsec = 0; inode->i_ctime.tv_nsec = 0; inode->i_blocks = fs64_to_cpu(sb, ufs2_inode->ui_blocks); + inode->i_generation = fs32_to_cpu(sb, ufs2_inode->ui_gen); ufsi->i_flags = fs32_to_cpu(sb, ufs2_inode->ui_flags); - ufsi->i_gen = fs32_to_cpu(sb, ufs2_inode->ui_gen); /* ufsi->i_shadow = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_shadow); ufsi->i_oeftflag = fs32_to_cpu(sb, ufs_inode->ui_u3.ui_sun.ui_oeftflag); @@ -731,34 +745,11 @@ bad_inode: make_bad_inode(inode); } -static int ufs_update_inode(struct inode * inode, int do_sync) +static void ufs1_update_inode(struct inode *inode, struct ufs_inode *ufs_inode) { - struct ufs_inode_info *ufsi = UFS_I(inode); - struct super_block * sb; - struct ufs_sb_private_info * uspi; - struct buffer_head * bh; - struct ufs_inode * ufs_inode; - unsigned i; - unsigned flags; - - UFSD("ENTER, ino %lu\n", inode->i_ino); - - sb = inode->i_sb; - uspi = UFS_SB(sb)->s_uspi; - flags = UFS_SB(sb)->s_flags; - - if (inode->i_ino < UFS_ROOTINO || - inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) { - ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino); - return -1; - } - - bh = sb_bread(sb, ufs_inotofsba(inode->i_ino)); - if (!bh) { - ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino); - return -1; - } - ufs_inode = (struct ufs_inode *) (bh->b_data + ufs_inotofsbo(inode->i_ino) * sizeof(struct ufs_inode)); + struct super_block *sb = inode->i_sb; + struct ufs_inode_info *ufsi = UFS_I(inode); + unsigned i; ufs_inode->ui_mode = cpu_to_fs16(sb, inode->i_mode); ufs_inode->ui_nlink = cpu_to_fs16(sb, inode->i_nlink); @@ -775,9 +766,9 @@ static int ufs_update_inode(struct inode * inode, int do_sync) ufs_inode->ui_mtime.tv_usec = 0; ufs_inode->ui_blocks = cpu_to_fs32(sb, inode->i_blocks); ufs_inode->ui_flags = cpu_to_fs32(sb, ufsi->i_flags); - ufs_inode->ui_gen = cpu_to_fs32(sb, ufsi->i_gen); + ufs_inode->ui_gen = cpu_to_fs32(sb, inode->i_generation); - if ((flags & UFS_UID_MASK) == UFS_UID_EFT) { + if ((UFS_SB(sb)->s_flags & UFS_UID_MASK) == UFS_UID_EFT) { ufs_inode->ui_u3.ui_sun.ui_shadow = cpu_to_fs32(sb, ufsi->i_shadow); ufs_inode->ui_u3.ui_sun.ui_oeftflag = cpu_to_fs32(sb, ufsi->i_oeftflag); } @@ -796,6 +787,78 @@ static int ufs_update_inode(struct inode * inode, int do_sync) if (!inode->i_nlink) memset (ufs_inode, 0, sizeof(struct ufs_inode)); +} + +static void ufs2_update_inode(struct inode *inode, struct ufs2_inode *ufs_inode) +{ + struct super_block *sb = inode->i_sb; + struct ufs_inode_info *ufsi = UFS_I(inode); + unsigned i; + + UFSD("ENTER\n"); + ufs_inode->ui_mode = cpu_to_fs16(sb, inode->i_mode); + ufs_inode->ui_nlink = cpu_to_fs16(sb, inode->i_nlink); + + ufs_inode->ui_uid = cpu_to_fs32(sb, inode->i_uid); + ufs_inode->ui_gid = cpu_to_fs32(sb, inode->i_gid); + + ufs_inode->ui_size = cpu_to_fs64(sb, inode->i_size); + ufs_inode->ui_atime.tv_sec = cpu_to_fs32(sb, inode->i_atime.tv_sec); + ufs_inode->ui_atime.tv_usec = 0; + ufs_inode->ui_ctime.tv_sec = cpu_to_fs32(sb, inode->i_ctime.tv_sec); + ufs_inode->ui_ctime.tv_usec = 0; + ufs_inode->ui_mtime.tv_sec = cpu_to_fs32(sb, inode->i_mtime.tv_sec); + ufs_inode->ui_mtime.tv_usec = 0; + + ufs_inode->ui_blocks = cpu_to_fs64(sb, inode->i_blocks); + ufs_inode->ui_flags = cpu_to_fs32(sb, ufsi->i_flags); + ufs_inode->ui_gen = cpu_to_fs32(sb, inode->i_generation); + + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { + /* ufs_inode->ui_u2.ui_addr.ui_db[0] = cpu_to_fs32(sb, inode->i_rdev); */ + ufs_inode->ui_u2.ui_addr.ui_db[0] = ufsi->i_u1.u2_i_data[0]; + } else if (inode->i_blocks) { + for (i = 0; i < (UFS_NDADDR + UFS_NINDIR); i++) + ufs_inode->ui_u2.ui_addr.ui_db[i] = ufsi->i_u1.u2_i_data[i]; + } else { + for (i = 0; i < (UFS_NDADDR + UFS_NINDIR) * 4; i++) + ufs_inode->ui_u2.ui_symlink[i] = ufsi->i_u1.i_symlink[i]; + } + + if (!inode->i_nlink) + memset (ufs_inode, 0, sizeof(struct ufs2_inode)); + UFSD("EXIT\n"); +} + +static int ufs_update_inode(struct inode * inode, int do_sync) +{ + struct super_block *sb = inode->i_sb; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; + struct buffer_head * bh; + + UFSD("ENTER, ino %lu\n", inode->i_ino); + + if (inode->i_ino < UFS_ROOTINO || + inode->i_ino > (uspi->s_ncg * uspi->s_ipg)) { + ufs_warning (sb, "ufs_read_inode", "bad inode number (%lu)\n", inode->i_ino); + return -1; + } + + bh = sb_bread(sb, ufs_inotofsba(inode->i_ino)); + if (!bh) { + ufs_warning (sb, "ufs_read_inode", "unable to read inode %lu\n", inode->i_ino); + return -1; + } + if (uspi->fs_magic == UFS2_MAGIC) { + struct ufs2_inode *ufs2_inode = (struct ufs2_inode *)bh->b_data; + + ufs2_update_inode(inode, + ufs2_inode + ufs_inotofsbo(inode->i_ino)); + } else { + struct ufs_inode *ufs_inode = (struct ufs_inode *) bh->b_data; + + ufs1_update_inode(inode, ufs_inode + ufs_inotofsbo(inode->i_ino)); + } mark_buffer_dirty(bh); if (do_sync) diff --git a/fs/ufs/namei.c b/fs/ufs/namei.c index e84c0ecf073..a059ccd064e 100644 --- a/fs/ufs/namei.c +++ b/fs/ufs/namei.c @@ -355,7 +355,7 @@ out: return err; } -struct inode_operations ufs_dir_inode_operations = { +const struct inode_operations ufs_dir_inode_operations = { .create = ufs_create, .lookup = ufs_lookup, .link = ufs_link, diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 8a8e9382ec0..b5a6461ec66 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -61,6 +61,8 @@ * UFS2 (of FreeBSD 5.x) support added by * Niraj Kumar <niraj17@iitbombay.org>, Jan 2004 * + * UFS2 write support added by + * Evgeniy Dushistov <dushistov@mail.ru>, 2007 */ @@ -93,14 +95,16 @@ /* * Print contents of ufs_super_block, useful for debugging */ -static void ufs_print_super_stuff(struct super_block *sb, unsigned flags, +static void ufs_print_super_stuff(struct super_block *sb, struct ufs_super_block_first *usb1, struct ufs_super_block_second *usb2, struct ufs_super_block_third *usb3) { + u32 magic = fs32_to_cpu(sb, usb3->fs_magic); + printk("ufs_print_super_stuff\n"); - printk(" magic: 0x%x\n", fs32_to_cpu(sb, usb3->fs_magic)); - if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) { + printk(" magic: 0x%x\n", magic); + if (fs32_to_cpu(sb, usb3->fs_magic) == UFS2_MAGIC) { printk(" fs_size: %llu\n", (unsigned long long) fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_size)); printk(" fs_dsize: %llu\n", (unsigned long long) @@ -117,6 +121,12 @@ static void ufs_print_super_stuff(struct super_block *sb, unsigned flags, printk(" cs_nbfree(No of free blocks): %llu\n", (unsigned long long) fs64_to_cpu(sb, usb2->fs_un.fs_u2.cs_nbfree)); + printk(KERN_INFO" cs_nifree(Num of free inodes): %llu\n", + (unsigned long long) + fs64_to_cpu(sb, usb3->fs_un1.fs_u2.cs_nifree)); + printk(KERN_INFO" cs_nffree(Num of free frags): %llu\n", + (unsigned long long) + fs64_to_cpu(sb, usb3->fs_un1.fs_u2.cs_nffree)); } else { printk(" sblkno: %u\n", fs32_to_cpu(sb, usb1->fs_sblkno)); printk(" cblkno: %u\n", fs32_to_cpu(sb, usb1->fs_cblkno)); @@ -199,11 +209,11 @@ static void ufs_print_cylinder_stuff(struct super_block *sb, printk("\n"); } #else -# define ufs_print_super_stuff(sb, flags, usb1, usb2, usb3) /**/ +# define ufs_print_super_stuff(sb, usb1, usb2, usb3) /**/ # define ufs_print_cylinder_stuff(sb, cg) /**/ #endif /* CONFIG_UFS_DEBUG */ -static struct super_operations ufs_super_ops; +static const struct super_operations ufs_super_ops; static char error_buf[1024]; @@ -422,7 +432,6 @@ static int ufs_read_cylinder_structures(struct super_block *sb) { struct ufs_sb_info *sbi = UFS_SB(sb); struct ufs_sb_private_info *uspi = sbi->s_uspi; - unsigned flags = sbi->s_flags; struct ufs_buffer_head * ubh; unsigned char * base, * space; unsigned size, blks, i; @@ -446,11 +455,7 @@ static int ufs_read_cylinder_structures(struct super_block *sb) if (i + uspi->s_fpb > blks) size = (blks - i) * uspi->s_fsize; - if ((flags & UFS_TYPE_MASK) == UFS_TYPE_UFS2) - ubh = ubh_bread(sb, - fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_csaddr) + i, size); - else - ubh = ubh_bread(sb, uspi->s_csaddr + i, size); + ubh = ubh_bread(sb, uspi->s_csaddr + i, size); if (!ubh) goto failed; @@ -545,6 +550,7 @@ static void ufs_put_cstotal(struct super_block *sb) cpu_to_fs32(sb, uspi->cs_total.cs_nffree); } ubh_mark_buffer_dirty(USPI_UBH(uspi)); + ufs_print_super_stuff(sb, usb1, usb2, usb3); UFSD("EXIT\n"); } @@ -572,7 +578,9 @@ static void ufs_put_super_internal(struct super_block *sb) size = uspi->s_bsize; if (i + uspi->s_fpb > blks) size = (blks - i) * uspi->s_fsize; + ubh = ubh_bread(sb, uspi->s_csaddr + i, size); + ubh_memcpyubh (ubh, space, size); space += size; ubh_mark_buffer_uptodate (ubh, 1); @@ -649,7 +657,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) kmalloc (sizeof(struct ufs_sb_private_info), GFP_KERNEL); if (!uspi) goto failed; - + uspi->s_dirblksize = UFS_SECTOR_SIZE; super_block_offset=UFS_SBLOCK; /* Keep 2Gig file limit. Some UFS variants need to override @@ -674,10 +682,6 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) uspi->s_sbsize = super_block_size = 1536; uspi->s_sbbase = 0; flags |= UFS_TYPE_UFS2 | UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; - if (!(sb->s_flags & MS_RDONLY)) { - printk(KERN_INFO "ufstype=ufs2 is supported read-only\n"); - sb->s_flags |= MS_RDONLY; - } break; case UFS_MOUNT_UFSTYPE_SUN: @@ -718,6 +722,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_NEXTSTEP: + /*TODO: check may be we need set special dir block size?*/ UFSD("ufstype=nextstep\n"); uspi->s_fsize = block_size = 1024; uspi->s_fmask = ~(1024 - 1); @@ -733,6 +738,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) break; case UFS_MOUNT_UFSTYPE_NEXTSTEP_CD: + /*TODO: check may be we need set special dir block size?*/ UFSD("ufstype=nextstep-cd\n"); uspi->s_fsize = block_size = 2048; uspi->s_fmask = ~(2048 - 1); @@ -754,6 +760,7 @@ static int ufs_fill_super(struct super_block *sb, void *data, int silent) uspi->s_fshift = 10; uspi->s_sbsize = super_block_size = 2048; uspi->s_sbbase = 0; + uspi->s_dirblksize = 1024; flags |= UFS_DE_44BSD | UFS_UID_44BSD | UFS_ST_44BSD | UFS_CG_44BSD; if (!(sb->s_flags & MS_RDONLY)) { if (!silent) @@ -887,7 +894,7 @@ magic_found: } - ufs_print_super_stuff(sb, flags, usb1, usb2, usb3); + ufs_print_super_stuff(sb, usb1, usb2, usb3); /* * Check, if file system was correctly unmounted. @@ -970,7 +977,12 @@ magic_found: uspi->s_npsect = ufs_get_fs_npsect(sb, usb1, usb3); uspi->s_interleave = fs32_to_cpu(sb, usb1->fs_interleave); uspi->s_trackskew = fs32_to_cpu(sb, usb1->fs_trackskew); - uspi->s_csaddr = fs32_to_cpu(sb, usb1->fs_csaddr); + + if (uspi->fs_magic == UFS2_MAGIC) + uspi->s_csaddr = fs64_to_cpu(sb, usb3->fs_un1.fs_u2.fs_csaddr); + else + uspi->s_csaddr = fs32_to_cpu(sb, usb1->fs_csaddr); + uspi->s_cssize = fs32_to_cpu(sb, usb1->fs_cssize); uspi->s_cgsize = fs32_to_cpu(sb, usb1->fs_cgsize); uspi->s_ntrak = fs32_to_cpu(sb, usb1->fs_ntrak); @@ -1057,7 +1069,6 @@ static void ufs_write_super(struct super_block *sb) unsigned flags; lock_kernel(); - UFSD("ENTER\n"); flags = UFS_SB(sb)->s_flags; uspi = UFS_SB(sb)->s_uspi; @@ -1153,7 +1164,8 @@ static int ufs_remount (struct super_block *sb, int *mount_flags, char *data) #else if (ufstype != UFS_MOUNT_UFSTYPE_SUN && ufstype != UFS_MOUNT_UFSTYPE_44BSD && - ufstype != UFS_MOUNT_UFSTYPE_SUNx86) { + ufstype != UFS_MOUNT_UFSTYPE_SUNx86 && + ufstype != UFS_MOUNT_UFSTYPE_UFS2) { printk("this ufstype is read-only supported\n"); return -EINVAL; } @@ -1252,7 +1264,7 @@ static ssize_t ufs_quota_read(struct super_block *, int, char *,size_t, loff_t); static ssize_t ufs_quota_write(struct super_block *, int, const char *, size_t, loff_t); #endif -static struct super_operations ufs_super_ops = { +static const struct super_operations ufs_super_ops = { .alloc_inode = ufs_alloc_inode, .destroy_inode = ufs_destroy_inode, .read_inode = ufs_read_inode, diff --git a/fs/ufs/symlink.c b/fs/ufs/symlink.c index 337512ed578..d8549f807e8 100644 --- a/fs/ufs/symlink.c +++ b/fs/ufs/symlink.c @@ -36,7 +36,7 @@ static void *ufs_follow_link(struct dentry *dentry, struct nameidata *nd) return NULL; } -struct inode_operations ufs_fast_symlink_inode_operations = { +const struct inode_operations ufs_fast_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = ufs_follow_link, }; diff --git a/fs/ufs/truncate.c b/fs/ufs/truncate.c index 0437b0a6fe9..749581fa772 100644 --- a/fs/ufs/truncate.c +++ b/fs/ufs/truncate.c @@ -30,8 +30,8 @@ */ /* - * Modified to avoid infinite loop on 2006 by - * Evgeniy Dushistov <dushistov@mail.ru> + * Adoptation to use page cache and UFS2 write support by + * Evgeniy Dushistov <dushistov@mail.ru>, 2006-2007 */ #include <linux/errno.h> @@ -63,13 +63,13 @@ #define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize - 1) >> uspi->s_fshift) -static int ufs_trunc_direct (struct inode * inode) +static int ufs_trunc_direct(struct inode *inode) { struct ufs_inode_info *ufsi = UFS_I(inode); struct super_block * sb; struct ufs_sb_private_info * uspi; - __fs32 * p; - unsigned frag1, frag2, frag3, frag4, block1, block2; + void *p; + u64 frag1, frag2, frag3, frag4, block1, block2; unsigned frag_to_free, free_count; unsigned i, tmp; int retry; @@ -91,13 +91,16 @@ static int ufs_trunc_direct (struct inode * inode) if (frag2 > frag3) { frag2 = frag4; frag3 = frag4 = 0; - } - else if (frag2 < frag3) { + } else if (frag2 < frag3) { block1 = ufs_fragstoblks (frag2); block2 = ufs_fragstoblks (frag3); } - UFSD("frag1 %u, frag2 %u, block1 %u, block2 %u, frag3 %u, frag4 %u\n", frag1, frag2, block1, block2, frag3, frag4); + UFSD("frag1 %llu, frag2 %llu, block1 %llu, block2 %llu, frag3 %llu," + " frag4 %llu\n", + (unsigned long long)frag1, (unsigned long long)frag2, + (unsigned long long)block1, (unsigned long long)block2, + (unsigned long long)frag3, (unsigned long long)frag4); if (frag1 >= frag2) goto next1; @@ -105,8 +108,8 @@ static int ufs_trunc_direct (struct inode * inode) /* * Free first free fragments */ - p = ufsi->i_u1.i_data + ufs_fragstoblks (frag1); - tmp = fs32_to_cpu(sb, *p); + p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag1)); + tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp ) ufs_panic (sb, "ufs_trunc_direct", "internal error"); frag2 -= frag1; @@ -121,12 +124,11 @@ next1: * Free whole blocks */ for (i = block1 ; i < block2; i++) { - p = ufsi->i_u1.i_data + i; - tmp = fs32_to_cpu(sb, *p); + p = ufs_get_direct_data_ptr(uspi, ufsi, i); + tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp) continue; - - *p = 0; + ufs_data_ptr_clear(uspi, p); if (free_count == 0) { frag_to_free = tmp; @@ -150,13 +152,12 @@ next1: /* * Free last free fragments */ - p = ufsi->i_u1.i_data + ufs_fragstoblks (frag3); - tmp = fs32_to_cpu(sb, *p); + p = ufs_get_direct_data_ptr(uspi, ufsi, ufs_fragstoblks(frag3)); + tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp ) ufs_panic(sb, "ufs_truncate_direct", "internal error"); frag4 = ufs_fragnum (frag4); - - *p = 0; + ufs_data_ptr_clear(uspi, p); ufs_free_fragments (inode, tmp, frag4); mark_inode_dirty(inode); @@ -167,17 +168,20 @@ next1: } -static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p) +static int ufs_trunc_indirect(struct inode *inode, u64 offset, void *p) { struct super_block * sb; struct ufs_sb_private_info * uspi; struct ufs_buffer_head * ind_ubh; - __fs32 * ind; - unsigned indirect_block, i, tmp; - unsigned frag_to_free, free_count; + void *ind; + u64 tmp, indirect_block, i, frag_to_free; + unsigned free_count; int retry; - UFSD("ENTER\n"); + UFSD("ENTER: ino %lu, offset %llu, p: %p\n", + inode->i_ino, (unsigned long long)offset, p); + + BUG_ON(!p); sb = inode->i_sb; uspi = UFS_SB(sb)->s_uspi; @@ -186,27 +190,27 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p) free_count = 0; retry = 0; - tmp = fs32_to_cpu(sb, *p); + tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp) return 0; ind_ubh = ubh_bread(sb, tmp, uspi->s_bsize); - if (tmp != fs32_to_cpu(sb, *p)) { + if (tmp != ufs_data_ptr_to_cpu(sb, p)) { ubh_brelse (ind_ubh); return 1; } if (!ind_ubh) { - *p = 0; + ufs_data_ptr_clear(uspi, p); return 0; } indirect_block = (DIRECT_BLOCK > offset) ? (DIRECT_BLOCK - offset) : 0; for (i = indirect_block; i < uspi->s_apb; i++) { - ind = ubh_get_addr32 (ind_ubh, i); - tmp = fs32_to_cpu(sb, *ind); + ind = ubh_get_data_ptr(uspi, ind_ubh, i); + tmp = ufs_data_ptr_to_cpu(sb, ind); if (!tmp) continue; - *ind = 0; + ufs_data_ptr_clear(uspi, ind); ubh_mark_buffer_dirty(ind_ubh); if (free_count == 0) { frag_to_free = tmp; @@ -226,11 +230,12 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p) ufs_free_blocks (inode, frag_to_free, free_count); } for (i = 0; i < uspi->s_apb; i++) - if (*ubh_get_addr32(ind_ubh,i)) + if (!ufs_is_data_ptr_zero(uspi, + ubh_get_data_ptr(uspi, ind_ubh, i))) break; if (i >= uspi->s_apb) { - tmp = fs32_to_cpu(sb, *p); - *p = 0; + tmp = ufs_data_ptr_to_cpu(sb, p); + ufs_data_ptr_clear(uspi, p); ufs_free_blocks (inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); @@ -248,13 +253,13 @@ static int ufs_trunc_indirect (struct inode * inode, unsigned offset, __fs32 *p) return retry; } -static int ufs_trunc_dindirect (struct inode *inode, unsigned offset, __fs32 *p) +static int ufs_trunc_dindirect(struct inode *inode, u64 offset, void *p) { struct super_block * sb; struct ufs_sb_private_info * uspi; - struct ufs_buffer_head * dind_bh; - unsigned i, tmp, dindirect_block; - __fs32 * dind; + struct ufs_buffer_head *dind_bh; + u64 i, tmp, dindirect_block; + void *dind; int retry = 0; UFSD("ENTER\n"); @@ -266,22 +271,22 @@ static int ufs_trunc_dindirect (struct inode *inode, unsigned offset, __fs32 *p) ? ((DIRECT_BLOCK - offset) >> uspi->s_apbshift) : 0; retry = 0; - tmp = fs32_to_cpu(sb, *p); + tmp = ufs_data_ptr_to_cpu(sb, p); if (!tmp) return 0; dind_bh = ubh_bread(sb, tmp, uspi->s_bsize); - if (tmp != fs32_to_cpu(sb, *p)) { + if (tmp != ufs_data_ptr_to_cpu(sb, p)) { ubh_brelse (dind_bh); return 1; } if (!dind_bh) { - *p = 0; + ufs_data_ptr_clear(uspi, p); return 0; } for (i = dindirect_block ; i < uspi->s_apb ; i++) { - dind = ubh_get_addr32 (dind_bh, i); - tmp = fs32_to_cpu(sb, *dind); + dind = ubh_get_data_ptr(uspi, dind_bh, i); + tmp = ufs_data_ptr_to_cpu(sb, dind); if (!tmp) continue; retry |= ufs_trunc_indirect (inode, offset + (i << uspi->s_apbshift), dind); @@ -289,11 +294,12 @@ static int ufs_trunc_dindirect (struct inode *inode, unsigned offset, __fs32 *p) } for (i = 0; i < uspi->s_apb; i++) - if (*ubh_get_addr32 (dind_bh, i)) + if (!ufs_is_data_ptr_zero(uspi, + ubh_get_data_ptr(uspi, dind_bh, i))) break; if (i >= uspi->s_apb) { - tmp = fs32_to_cpu(sb, *p); - *p = 0; + tmp = ufs_data_ptr_to_cpu(sb, p); + ufs_data_ptr_clear(uspi, p); ufs_free_blocks(inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); @@ -311,34 +317,33 @@ static int ufs_trunc_dindirect (struct inode *inode, unsigned offset, __fs32 *p) return retry; } -static int ufs_trunc_tindirect (struct inode * inode) +static int ufs_trunc_tindirect(struct inode *inode) { + struct super_block *sb = inode->i_sb; + struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; struct ufs_inode_info *ufsi = UFS_I(inode); - struct super_block * sb; - struct ufs_sb_private_info * uspi; struct ufs_buffer_head * tind_bh; - unsigned tindirect_block, tmp, i; - __fs32 * tind, * p; + u64 tindirect_block, tmp, i; + void *tind, *p; int retry; UFSD("ENTER\n"); - sb = inode->i_sb; - uspi = UFS_SB(sb)->s_uspi; retry = 0; tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb)) ? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) >> uspi->s_2apbshift) : 0; - p = ufsi->i_u1.i_data + UFS_TIND_BLOCK; - if (!(tmp = fs32_to_cpu(sb, *p))) + + p = ufs_get_direct_data_ptr(uspi, ufsi, UFS_TIND_BLOCK); + if (!(tmp = ufs_data_ptr_to_cpu(sb, p))) return 0; tind_bh = ubh_bread (sb, tmp, uspi->s_bsize); - if (tmp != fs32_to_cpu(sb, *p)) { + if (tmp != ufs_data_ptr_to_cpu(sb, p)) { ubh_brelse (tind_bh); return 1; } if (!tind_bh) { - *p = 0; + ufs_data_ptr_clear(uspi, p); return 0; } @@ -349,11 +354,12 @@ static int ufs_trunc_tindirect (struct inode * inode) ubh_mark_buffer_dirty(tind_bh); } for (i = 0; i < uspi->s_apb; i++) - if (*ubh_get_addr32 (tind_bh, i)) + if (!ufs_is_data_ptr_zero(uspi, + ubh_get_data_ptr(uspi, tind_bh, i))) break; if (i >= uspi->s_apb) { - tmp = fs32_to_cpu(sb, *p); - *p = 0; + tmp = ufs_data_ptr_to_cpu(sb, p); + ufs_data_ptr_clear(uspi, p); ufs_free_blocks(inode, tmp, uspi->s_fpb); mark_inode_dirty(inode); @@ -375,7 +381,8 @@ static int ufs_alloc_lastblock(struct inode *inode) int err = 0; struct address_space *mapping = inode->i_mapping; struct ufs_sb_private_info *uspi = UFS_SB(inode->i_sb)->s_uspi; - unsigned lastfrag, i, end; + unsigned i, end; + sector_t lastfrag; struct page *lastpage; struct buffer_head *bh; @@ -430,7 +437,9 @@ int ufs_truncate(struct inode *inode, loff_t old_i_size) struct ufs_sb_private_info *uspi = UFS_SB(sb)->s_uspi; int retry, err = 0; - UFSD("ENTER\n"); + UFSD("ENTER: ino %lu, i_size: %llu, old_i_size: %llu\n", + inode->i_ino, (unsigned long long)i_size_read(inode), + (unsigned long long)old_i_size); if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode))) @@ -450,10 +459,12 @@ int ufs_truncate(struct inode *inode, loff_t old_i_size) lock_kernel(); while (1) { retry = ufs_trunc_direct(inode); - retry |= ufs_trunc_indirect (inode, UFS_IND_BLOCK, - (__fs32 *) &ufsi->i_u1.i_data[UFS_IND_BLOCK]); - retry |= ufs_trunc_dindirect (inode, UFS_IND_BLOCK + uspi->s_apb, - (__fs32 *) &ufsi->i_u1.i_data[UFS_DIND_BLOCK]); + retry |= ufs_trunc_indirect(inode, UFS_IND_BLOCK, + ufs_get_direct_data_ptr(uspi, ufsi, + UFS_IND_BLOCK)); + retry |= ufs_trunc_dindirect(inode, UFS_IND_BLOCK + uspi->s_apb, + ufs_get_direct_data_ptr(uspi, ufsi, + UFS_DIND_BLOCK)); retry |= ufs_trunc_tindirect (inode); if (!retry) break; @@ -502,6 +513,6 @@ static int ufs_setattr(struct dentry *dentry, struct iattr *attr) return inode_setattr(inode, attr); } -struct inode_operations ufs_file_inode_operations = { +const struct inode_operations ufs_file_inode_operations = { .setattr = ufs_setattr, }; diff --git a/fs/ufs/util.h b/fs/ufs/util.h index 7dd12bb1d62..06d344839c4 100644 --- a/fs/ufs/util.h +++ b/fs/ufs/util.h @@ -305,8 +305,22 @@ static inline void *get_usb_offset(struct ufs_sb_private_info *uspi, (((__fs32*)((ubh)->bh[(begin) >> (uspi->s_fshift-2)]->b_data)) + \ ((begin) & ((uspi->s_fsize>>2) - 1))) +#define ubh_get_addr64(ubh,begin) \ + (((__fs64*)((ubh)->bh[(begin) >> (uspi->s_fshift-3)]->b_data)) + \ + ((begin) & ((uspi->s_fsize>>3) - 1))) + #define ubh_get_addr ubh_get_addr8 +static inline void *ubh_get_data_ptr(struct ufs_sb_private_info *uspi, + struct ufs_buffer_head *ubh, + u64 blk) +{ + if (uspi->fs_magic == UFS2_MAGIC) + return ubh_get_addr64(ubh, blk); + else + return ubh_get_addr32(ubh, blk); +} + #define ubh_blkmap(ubh,begin,bit) \ ((*ubh_get_addr(ubh, (begin) + ((bit) >> 3)) >> ((bit) & 7)) & (0xff >> (UFS_MAXFRAG - uspi->s_fpb))) @@ -507,3 +521,46 @@ static inline void ufs_fragacct (struct super_block * sb, unsigned blockmap, if (fragsize > 0 && fragsize < uspi->s_fpb) fs32_add(sb, &fraglist[fragsize], cnt); } + +static inline void *ufs_get_direct_data_ptr(struct ufs_sb_private_info *uspi, + struct ufs_inode_info *ufsi, + unsigned blk) +{ + BUG_ON(blk > UFS_TIND_BLOCK); + return uspi->fs_magic == UFS2_MAGIC ? + (void *)&ufsi->i_u1.u2_i_data[blk] : + (void *)&ufsi->i_u1.i_data[blk]; +} + +static inline u64 ufs_data_ptr_to_cpu(struct super_block *sb, void *p) +{ + return UFS_SB(sb)->s_uspi->fs_magic == UFS2_MAGIC ? + fs64_to_cpu(sb, *(__fs64 *)p) : + fs32_to_cpu(sb, *(__fs32 *)p); +} + +static inline void ufs_cpu_to_data_ptr(struct super_block *sb, void *p, u64 val) +{ + if (UFS_SB(sb)->s_uspi->fs_magic == UFS2_MAGIC) + *(__fs64 *)p = cpu_to_fs64(sb, val); + else + *(__fs32 *)p = cpu_to_fs32(sb, val); +} + +static inline void ufs_data_ptr_clear(struct ufs_sb_private_info *uspi, + void *p) +{ + if (uspi->fs_magic == UFS2_MAGIC) + *(__fs64 *)p = 0; + else + *(__fs32 *)p = 0; +} + +static inline int ufs_is_data_ptr_zero(struct ufs_sb_private_info *uspi, + void *p) +{ + if (uspi->fs_magic == UFS2_MAGIC) + return *(__fs64 *)p == 0; + else + return *(__fs32 *)p == 0; +} diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index 0afd745a37c..c28add2fbe9 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c @@ -996,7 +996,7 @@ error_inode: goto out; } -static struct inode_operations vfat_dir_inode_operations = { +static const struct inode_operations vfat_dir_inode_operations = { .create = vfat_create, .lookup = vfat_lookup, .unlink = vfat_unlink, diff --git a/fs/xfs/linux-2.6/mrlock.h b/fs/xfs/linux-2.6/mrlock.h index 32e1ce0f04c..af168a1a98c 100644 --- a/fs/xfs/linux-2.6/mrlock.h +++ b/fs/xfs/linux-2.6/mrlock.h @@ -31,15 +31,13 @@ typedef struct { do { (mrp)->mr_writer = 0; init_rwsem(&(mrp)->mr_lock); } while (0) #define mrlock_init(mrp, t,n,s) mrinit(mrp, n) #define mrfree(mrp) do { } while (0) -#define mraccess(mrp) mraccessf(mrp, 0) -#define mrupdate(mrp) mrupdatef(mrp, 0) -static inline void mraccessf(mrlock_t *mrp, int flags) +static inline void mraccess(mrlock_t *mrp) { down_read(&mrp->mr_lock); } -static inline void mrupdatef(mrlock_t *mrp, int flags) +static inline void mrupdate(mrlock_t *mrp) { down_write(&mrp->mr_lock); mrp->mr_writer = 1; diff --git a/fs/xfs/linux-2.6/xfs_aops.c b/fs/xfs/linux-2.6/xfs_aops.c index 7b54461695e..143ffc851c9 100644 --- a/fs/xfs/linux-2.6/xfs_aops.c +++ b/fs/xfs/linux-2.6/xfs_aops.c @@ -56,8 +56,6 @@ xfs_count_page_state( do { if (buffer_uptodate(bh) && !buffer_mapped(bh)) (*unmapped) = 1; - else if (buffer_unwritten(bh) && !buffer_delay(bh)) - clear_buffer_unwritten(bh); else if (buffer_unwritten(bh)) (*unwritten) = 1; else if (buffer_delay(bh)) @@ -249,7 +247,7 @@ xfs_map_blocks( return -error; } -STATIC inline int +STATIC_INLINE int xfs_iomap_valid( xfs_iomap_t *iomapp, loff_t offset) @@ -1272,7 +1270,6 @@ __xfs_get_blocks( if (direct) bh_result->b_private = inode; set_buffer_unwritten(bh_result); - set_buffer_delay(bh_result); } } @@ -1283,13 +1280,18 @@ __xfs_get_blocks( bh_result->b_bdev = iomap.iomap_target->bt_bdev; /* - * If we previously allocated a block out beyond eof and we are - * now coming back to use it then we will need to flag it as new - * even if it has a disk address. + * If we previously allocated a block out beyond eof and we are now + * coming back to use it then we will need to flag it as new even if it + * has a disk address. + * + * With sub-block writes into unwritten extents we also need to mark + * the buffer as new so that the unwritten parts of the buffer gets + * correctly zeroed. */ if (create && ((!buffer_mapped(bh_result) && !buffer_uptodate(bh_result)) || - (offset >= i_size_read(inode)) || (iomap.iomap_flags & IOMAP_NEW))) + (offset >= i_size_read(inode)) || + (iomap.iomap_flags & (IOMAP_NEW|IOMAP_UNWRITTEN)))) set_buffer_new(bh_result); if (iomap.iomap_flags & IOMAP_DELAY) { diff --git a/fs/xfs/linux-2.6/xfs_buf.c b/fs/xfs/linux-2.6/xfs_buf.c index 4fb01ffdfd1..e2bea6a661f 100644 --- a/fs/xfs/linux-2.6/xfs_buf.c +++ b/fs/xfs/linux-2.6/xfs_buf.c @@ -34,13 +34,13 @@ #include <linux/backing-dev.h> #include <linux/freezer.h> -STATIC kmem_zone_t *xfs_buf_zone; -STATIC kmem_shaker_t xfs_buf_shake; +static kmem_zone_t *xfs_buf_zone; +static kmem_shaker_t xfs_buf_shake; STATIC int xfsbufd(void *); STATIC int xfsbufd_wakeup(int, gfp_t); STATIC void xfs_buf_delwri_queue(xfs_buf_t *, int); -STATIC struct workqueue_struct *xfslogd_workqueue; +static struct workqueue_struct *xfslogd_workqueue; struct workqueue_struct *xfsdatad_workqueue; #ifdef XFS_BUF_TRACE @@ -139,7 +139,7 @@ page_region_mask( return mask; } -STATIC inline void +STATIC_INLINE void set_page_region( struct page *page, size_t offset, @@ -151,7 +151,7 @@ set_page_region( SetPageUptodate(page); } -STATIC inline int +STATIC_INLINE int test_page_region( struct page *page, size_t offset, @@ -171,9 +171,9 @@ typedef struct a_list { struct a_list *next; } a_list_t; -STATIC a_list_t *as_free_head; -STATIC int as_list_len; -STATIC DEFINE_SPINLOCK(as_lock); +static a_list_t *as_free_head; +static int as_list_len; +static DEFINE_SPINLOCK(as_lock); /* * Try to batch vunmaps because they are costly. @@ -1085,7 +1085,7 @@ xfs_buf_iostart( return status; } -STATIC __inline__ int +STATIC_INLINE int _xfs_buf_iolocked( xfs_buf_t *bp) { @@ -1095,7 +1095,7 @@ _xfs_buf_iolocked( return 0; } -STATIC __inline__ void +STATIC_INLINE void _xfs_buf_ioend( xfs_buf_t *bp, int schedule) @@ -1426,8 +1426,8 @@ xfs_free_bufhash( /* * buftarg list for delwrite queue processing */ -STATIC LIST_HEAD(xfs_buftarg_list); -STATIC DEFINE_SPINLOCK(xfs_buftarg_lock); +LIST_HEAD(xfs_buftarg_list); +static DEFINE_SPINLOCK(xfs_buftarg_lock); STATIC void xfs_register_buftarg( @@ -1679,21 +1679,60 @@ xfsbufd_wakeup( return 0; } +/* + * Move as many buffers as specified to the supplied list + * idicating if we skipped any buffers to prevent deadlocks. + */ +STATIC int +xfs_buf_delwri_split( + xfs_buftarg_t *target, + struct list_head *list, + unsigned long age) +{ + xfs_buf_t *bp, *n; + struct list_head *dwq = &target->bt_delwrite_queue; + spinlock_t *dwlk = &target->bt_delwrite_lock; + int skipped = 0; + int force; + + force = test_and_clear_bit(XBT_FORCE_FLUSH, &target->bt_flags); + INIT_LIST_HEAD(list); + spin_lock(dwlk); + list_for_each_entry_safe(bp, n, dwq, b_list) { + XB_TRACE(bp, "walkq1", (long)xfs_buf_ispin(bp)); + ASSERT(bp->b_flags & XBF_DELWRI); + + if (!xfs_buf_ispin(bp) && !xfs_buf_cond_lock(bp)) { + if (!force && + time_before(jiffies, bp->b_queuetime + age)) { + xfs_buf_unlock(bp); + break; + } + + bp->b_flags &= ~(XBF_DELWRI|_XBF_DELWRI_Q| + _XBF_RUN_QUEUES); + bp->b_flags |= XBF_WRITE; + list_move_tail(&bp->b_list, list); + } else + skipped++; + } + spin_unlock(dwlk); + + return skipped; + +} + STATIC int xfsbufd( - void *data) + void *data) { - struct list_head tmp; - unsigned long age; - xfs_buftarg_t *target = (xfs_buftarg_t *)data; - xfs_buf_t *bp, *n; - struct list_head *dwq = &target->bt_delwrite_queue; - spinlock_t *dwlk = &target->bt_delwrite_lock; - int count; + struct list_head tmp; + xfs_buftarg_t *target = (xfs_buftarg_t *)data; + int count; + xfs_buf_t *bp; current->flags |= PF_MEMALLOC; - INIT_LIST_HEAD(&tmp); do { if (unlikely(freezing(current))) { set_bit(XBT_FORCE_SLEEP, &target->bt_flags); @@ -1705,37 +1744,17 @@ xfsbufd( schedule_timeout_interruptible( xfs_buf_timer_centisecs * msecs_to_jiffies(10)); - count = 0; - age = xfs_buf_age_centisecs * msecs_to_jiffies(10); - spin_lock(dwlk); - list_for_each_entry_safe(bp, n, dwq, b_list) { - XB_TRACE(bp, "walkq1", (long)xfs_buf_ispin(bp)); - ASSERT(bp->b_flags & XBF_DELWRI); - - if (!xfs_buf_ispin(bp) && !xfs_buf_cond_lock(bp)) { - if (!test_bit(XBT_FORCE_FLUSH, - &target->bt_flags) && - time_before(jiffies, - bp->b_queuetime + age)) { - xfs_buf_unlock(bp); - break; - } - - bp->b_flags &= ~(XBF_DELWRI|_XBF_DELWRI_Q| - _XBF_RUN_QUEUES); - bp->b_flags |= XBF_WRITE; - list_move_tail(&bp->b_list, &tmp); - count++; - } - } - spin_unlock(dwlk); + xfs_buf_delwri_split(target, &tmp, + xfs_buf_age_centisecs * msecs_to_jiffies(10)); + count = 0; while (!list_empty(&tmp)) { bp = list_entry(tmp.next, xfs_buf_t, b_list); ASSERT(target == bp->b_target); list_del_init(&bp->b_list); xfs_buf_iostrategy(bp); + count++; } if (as_list_len > 0) @@ -1743,7 +1762,6 @@ xfsbufd( if (count) blk_run_address_space(target->bt_mapping); - clear_bit(XBT_FORCE_FLUSH, &target->bt_flags); } while (!kthread_should_stop()); return 0; @@ -1756,40 +1774,24 @@ xfsbufd( */ int xfs_flush_buftarg( - xfs_buftarg_t *target, - int wait) + xfs_buftarg_t *target, + int wait) { - struct list_head tmp; - xfs_buf_t *bp, *n; - int pincount = 0; - struct list_head *dwq = &target->bt_delwrite_queue; - spinlock_t *dwlk = &target->bt_delwrite_lock; + struct list_head tmp; + xfs_buf_t *bp, *n; + int pincount = 0; xfs_buf_runall_queues(xfsdatad_workqueue); xfs_buf_runall_queues(xfslogd_workqueue); - INIT_LIST_HEAD(&tmp); - spin_lock(dwlk); - list_for_each_entry_safe(bp, n, dwq, b_list) { - ASSERT(bp->b_target == target); - ASSERT(bp->b_flags & (XBF_DELWRI | _XBF_DELWRI_Q)); - XB_TRACE(bp, "walkq2", (long)xfs_buf_ispin(bp)); - if (xfs_buf_ispin(bp)) { - pincount++; - continue; - } - - list_move_tail(&bp->b_list, &tmp); - } - spin_unlock(dwlk); + set_bit(XBT_FORCE_FLUSH, &target->bt_flags); + pincount = xfs_buf_delwri_split(target, &tmp, 0); /* * Dropped the delayed write list lock, now walk the temporary list */ list_for_each_entry_safe(bp, n, &tmp, b_list) { - xfs_buf_lock(bp); - bp->b_flags &= ~(XBF_DELWRI|_XBF_DELWRI_Q|_XBF_RUN_QUEUES); - bp->b_flags |= XBF_WRITE; + ASSERT(target == bp->b_target); if (wait) bp->b_flags &= ~XBF_ASYNC; else diff --git a/fs/xfs/linux-2.6/xfs_buf.h b/fs/xfs/linux-2.6/xfs_buf.h index 9dd235cb010..9e8ef8fef39 100644 --- a/fs/xfs/linux-2.6/xfs_buf.h +++ b/fs/xfs/linux-2.6/xfs_buf.h @@ -69,8 +69,8 @@ typedef enum { } xfs_buf_flags_t; typedef enum { - XBT_FORCE_SLEEP = (0 << 1), - XBT_FORCE_FLUSH = (1 << 1), + XBT_FORCE_SLEEP = 0, + XBT_FORCE_FLUSH = 1, } xfs_buftarg_flags_t; typedef struct xfs_bufhash { diff --git a/fs/xfs/linux-2.6/xfs_export.c b/fs/xfs/linux-2.6/xfs_export.c index 5fb75d9151f..e3a5fedac1b 100644 --- a/fs/xfs/linux-2.6/xfs_export.c +++ b/fs/xfs/linux-2.6/xfs_export.c @@ -24,7 +24,7 @@ #include "xfs_mount.h" #include "xfs_export.h" -STATIC struct dentry dotdot = { .d_name.name = "..", .d_name.len = 2, }; +static struct dentry dotdot = { .d_name.name = "..", .d_name.len = 2, }; /* * XFS encodes and decodes the fileid portion of NFS filehandles diff --git a/fs/xfs/linux-2.6/xfs_file.c b/fs/xfs/linux-2.6/xfs_file.c index d26f5cd2ba7..cb51dc96135 100644 --- a/fs/xfs/linux-2.6/xfs_file.c +++ b/fs/xfs/linux-2.6/xfs_file.c @@ -46,7 +46,7 @@ static struct vm_operations_struct xfs_file_vm_ops; static struct vm_operations_struct xfs_dmapi_file_vm_ops; #endif -STATIC inline ssize_t +STATIC_INLINE ssize_t __xfs_file_read( struct kiocb *iocb, const struct iovec *iov, @@ -84,7 +84,7 @@ xfs_file_aio_read_invis( return __xfs_file_read(iocb, iov, nr_segs, IO_ISAIO|IO_INVIS, pos); } -STATIC inline ssize_t +STATIC_INLINE ssize_t __xfs_file_write( struct kiocb *iocb, const struct iovec *iov, diff --git a/fs/xfs/linux-2.6/xfs_ioctl.c b/fs/xfs/linux-2.6/xfs_ioctl.c index f011c9cd0d6..ff5c41ff8d4 100644 --- a/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/fs/xfs/linux-2.6/xfs_ioctl.c @@ -41,8 +41,6 @@ #include "xfs_error.h" #include "xfs_rw.h" #include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" #include "xfs_attr.h" #include "xfs_bmap.h" #include "xfs_buf_item.h" @@ -355,7 +353,6 @@ STATIC int xfs_readlink_by_handle( xfs_mount_t *mp, void __user *arg, - struct file *parfilp, struct inode *parinode) { int error; @@ -388,7 +385,7 @@ xfs_readlink_by_handle( aiov.iov_len = olen; aiov.iov_base = hreq.ohandle; - auio.uio_iov = &aiov; + auio.uio_iov = (struct kvec *)&aiov; auio.uio_iovcnt = 1; auio.uio_offset = 0; auio.uio_segflg = UIO_USERSPACE; @@ -406,7 +403,6 @@ STATIC int xfs_fssetdm_by_handle( xfs_mount_t *mp, void __user *arg, - struct file *parfilp, struct inode *parinode) { int error; @@ -448,7 +444,6 @@ STATIC int xfs_attrlist_by_handle( xfs_mount_t *mp, void __user *arg, - struct file *parfilp, struct inode *parinode) { int error; @@ -569,7 +564,6 @@ STATIC int xfs_attrmulti_by_handle( xfs_mount_t *mp, void __user *arg, - struct file *parfilp, struct inode *parinode) { int error; @@ -689,7 +683,6 @@ xfs_ioc_xattr( STATIC int xfs_ioc_getbmap( bhv_desc_t *bdp, - struct file *filp, int flags, unsigned int cmd, void __user *arg); @@ -788,7 +781,7 @@ xfs_ioctl( case XFS_IOC_GETBMAP: case XFS_IOC_GETBMAPA: - return xfs_ioc_getbmap(bdp, filp, ioflags, cmd, arg); + return xfs_ioc_getbmap(bdp, ioflags, cmd, arg); case XFS_IOC_GETBMAPX: return xfs_ioc_getbmapx(bdp, arg); @@ -802,16 +795,16 @@ xfs_ioctl( return xfs_open_by_handle(mp, arg, filp, inode); case XFS_IOC_FSSETDM_BY_HANDLE: - return xfs_fssetdm_by_handle(mp, arg, filp, inode); + return xfs_fssetdm_by_handle(mp, arg, inode); case XFS_IOC_READLINK_BY_HANDLE: - return xfs_readlink_by_handle(mp, arg, filp, inode); + return xfs_readlink_by_handle(mp, arg, inode); case XFS_IOC_ATTRLIST_BY_HANDLE: - return xfs_attrlist_by_handle(mp, arg, filp, inode); + return xfs_attrlist_by_handle(mp, arg, inode); case XFS_IOC_ATTRMULTI_BY_HANDLE: - return xfs_attrmulti_by_handle(mp, arg, filp, inode); + return xfs_attrmulti_by_handle(mp, arg, inode); case XFS_IOC_SWAPEXT: { error = xfs_swapext((struct xfs_swapext __user *)arg); @@ -1095,11 +1088,6 @@ xfs_ioc_fsgeometry( /* * Linux extended inode flags interface. */ -#define LINUX_XFLAG_SYNC 0x00000008 /* Synchronous updates */ -#define LINUX_XFLAG_IMMUTABLE 0x00000010 /* Immutable file */ -#define LINUX_XFLAG_APPEND 0x00000020 /* writes to file may only append */ -#define LINUX_XFLAG_NODUMP 0x00000040 /* do not dump file */ -#define LINUX_XFLAG_NOATIME 0x00000080 /* do not update atime */ STATIC unsigned int xfs_merge_ioc_xflags( @@ -1108,23 +1096,23 @@ xfs_merge_ioc_xflags( { unsigned int xflags = start; - if (flags & LINUX_XFLAG_IMMUTABLE) + if (flags & FS_IMMUTABLE_FL) xflags |= XFS_XFLAG_IMMUTABLE; else xflags &= ~XFS_XFLAG_IMMUTABLE; - if (flags & LINUX_XFLAG_APPEND) + if (flags & FS_APPEND_FL) xflags |= XFS_XFLAG_APPEND; else xflags &= ~XFS_XFLAG_APPEND; - if (flags & LINUX_XFLAG_SYNC) + if (flags & FS_SYNC_FL) xflags |= XFS_XFLAG_SYNC; else xflags &= ~XFS_XFLAG_SYNC; - if (flags & LINUX_XFLAG_NOATIME) + if (flags & FS_NOATIME_FL) xflags |= XFS_XFLAG_NOATIME; else xflags &= ~XFS_XFLAG_NOATIME; - if (flags & LINUX_XFLAG_NODUMP) + if (flags & FS_NODUMP_FL) xflags |= XFS_XFLAG_NODUMP; else xflags &= ~XFS_XFLAG_NODUMP; @@ -1139,15 +1127,15 @@ xfs_di2lxflags( unsigned int flags = 0; if (di_flags & XFS_DIFLAG_IMMUTABLE) - flags |= LINUX_XFLAG_IMMUTABLE; + flags |= FS_IMMUTABLE_FL; if (di_flags & XFS_DIFLAG_APPEND) - flags |= LINUX_XFLAG_APPEND; + flags |= FS_APPEND_FL; if (di_flags & XFS_DIFLAG_SYNC) - flags |= LINUX_XFLAG_SYNC; + flags |= FS_SYNC_FL; if (di_flags & XFS_DIFLAG_NOATIME) - flags |= LINUX_XFLAG_NOATIME; + flags |= FS_NOATIME_FL; if (di_flags & XFS_DIFLAG_NODUMP) - flags |= LINUX_XFLAG_NODUMP; + flags |= FS_NODUMP_FL; return flags; } @@ -1247,9 +1235,9 @@ xfs_ioc_xattr( break; } - if (flags & ~(LINUX_XFLAG_IMMUTABLE | LINUX_XFLAG_APPEND | \ - LINUX_XFLAG_NOATIME | LINUX_XFLAG_NODUMP | \ - LINUX_XFLAG_SYNC)) { + if (flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL | \ + FS_NOATIME_FL | FS_NODUMP_FL | \ + FS_SYNC_FL)) { error = -EOPNOTSUPP; break; } @@ -1281,7 +1269,6 @@ xfs_ioc_xattr( STATIC int xfs_ioc_getbmap( bhv_desc_t *bdp, - struct file *filp, int ioflags, unsigned int cmd, void __user *arg) diff --git a/fs/xfs/linux-2.6/xfs_iops.c b/fs/xfs/linux-2.6/xfs_iops.c index 3ba814ae3bb..0b5fa124bef 100644 --- a/fs/xfs/linux-2.6/xfs_iops.c +++ b/fs/xfs/linux-2.6/xfs_iops.c @@ -43,8 +43,6 @@ #include "xfs_itable.h" #include "xfs_rw.h" #include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" #include "xfs_attr.h" #include "xfs_buf_item.h" #include "xfs_utils.h" @@ -250,13 +248,13 @@ xfs_init_security( * * XXX(hch): nfsd is broken, better fix it instead. */ -STATIC inline int +STATIC_INLINE int xfs_has_fs_struct(struct task_struct *task) { return (task->fs != init_task.fs); } -STATIC inline void +STATIC void xfs_cleanup_inode( bhv_vnode_t *dvp, bhv_vnode_t *vp, @@ -815,7 +813,7 @@ xfs_vn_removexattr( } -struct inode_operations xfs_inode_operations = { +const struct inode_operations xfs_inode_operations = { .permission = xfs_vn_permission, .truncate = xfs_vn_truncate, .getattr = xfs_vn_getattr, @@ -826,7 +824,7 @@ struct inode_operations xfs_inode_operations = { .removexattr = xfs_vn_removexattr, }; -struct inode_operations xfs_dir_inode_operations = { +const struct inode_operations xfs_dir_inode_operations = { .create = xfs_vn_create, .lookup = xfs_vn_lookup, .link = xfs_vn_link, @@ -845,7 +843,7 @@ struct inode_operations xfs_dir_inode_operations = { .removexattr = xfs_vn_removexattr, }; -struct inode_operations xfs_symlink_inode_operations = { +const struct inode_operations xfs_symlink_inode_operations = { .readlink = generic_readlink, .follow_link = xfs_vn_follow_link, .put_link = xfs_vn_put_link, diff --git a/fs/xfs/linux-2.6/xfs_iops.h b/fs/xfs/linux-2.6/xfs_iops.h index ad6173da567..95a69398fce 100644 --- a/fs/xfs/linux-2.6/xfs_iops.h +++ b/fs/xfs/linux-2.6/xfs_iops.h @@ -18,9 +18,9 @@ #ifndef __XFS_IOPS_H__ #define __XFS_IOPS_H__ -extern struct inode_operations xfs_inode_operations; -extern struct inode_operations xfs_dir_inode_operations; -extern struct inode_operations xfs_symlink_inode_operations; +extern const struct inode_operations xfs_inode_operations; +extern const struct inode_operations xfs_dir_inode_operations; +extern const struct inode_operations xfs_symlink_inode_operations; extern const struct file_operations xfs_file_operations; extern const struct file_operations xfs_dir_file_operations; diff --git a/fs/xfs/linux-2.6/xfs_linux.h b/fs/xfs/linux-2.6/xfs_linux.h index 2b0e0018738..715adad7dd4 100644 --- a/fs/xfs/linux-2.6/xfs_linux.h +++ b/fs/xfs/linux-2.6/xfs_linux.h @@ -109,16 +109,6 @@ #undef HAVE_PERCPU_SB /* per cpu superblock counters are a 2.6 feature */ #endif -/* - * State flag for unwritten extent buffers. - * - * We need to be able to distinguish between these and delayed - * allocate buffers within XFS. The generic IO path code does - * not need to distinguish - we use the BH_Delay flag for both - * delalloc and these ondisk-uninitialised buffers. - */ -BUFFER_FNS(PrivateStart, unwritten); - #define restricted_chown xfs_params.restrict_chown.val #define irix_sgid_inherit xfs_params.sgid_inherit.val #define irix_symlink_mode xfs_params.symlink_mode.val diff --git a/fs/xfs/linux-2.6/xfs_lrw.c b/fs/xfs/linux-2.6/xfs_lrw.c index 65e79b471d4..ff8d64eba9f 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.c +++ b/fs/xfs/linux-2.6/xfs_lrw.c @@ -43,8 +43,6 @@ #include "xfs_itable.h" #include "xfs_rw.h" #include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" #include "xfs_attr.h" #include "xfs_inode_item.h" #include "xfs_buf_item.h" @@ -134,13 +132,11 @@ STATIC int xfs_iozero( struct inode *ip, /* inode */ loff_t pos, /* offset in file */ - size_t count, /* size of data to zero */ - loff_t end_size) /* max file size to set */ + size_t count) /* size of data to zero */ { unsigned bytes; struct page *page; struct address_space *mapping; - char *kaddr; int status; mapping = ip->i_mapping; @@ -158,26 +154,21 @@ xfs_iozero( if (!page) break; - kaddr = kmap(page); status = mapping->a_ops->prepare_write(NULL, page, offset, offset + bytes); - if (status) { + if (status) goto unlock; - } - memset((void *) (kaddr + offset), 0, bytes); - flush_dcache_page(page); + memclear_highpage_flush(page, offset, bytes); + status = mapping->a_ops->commit_write(NULL, page, offset, offset + bytes); if (!status) { pos += bytes; count -= bytes; - if (pos > i_size_read(ip)) - i_size_write(ip, pos < end_size ? pos : end_size); } unlock: - kunmap(page); unlock_page(page); page_cache_release(page); if (status) @@ -449,8 +440,8 @@ STATIC int /* error (positive) */ xfs_zero_last_block( struct inode *ip, xfs_iocore_t *io, - xfs_fsize_t isize, - xfs_fsize_t end_size) + xfs_fsize_t offset, + xfs_fsize_t isize) { xfs_fileoff_t last_fsb; xfs_mount_t *mp = io->io_mount; @@ -459,7 +450,6 @@ xfs_zero_last_block( int zero_len; int error = 0; xfs_bmbt_irec_t imap; - loff_t loff; ASSERT(ismrlocked(io->io_lock, MR_UPDATE) != 0); @@ -494,9 +484,10 @@ xfs_zero_last_block( */ XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL| XFS_EXTSIZE_RD); - loff = XFS_FSB_TO_B(mp, last_fsb); zero_len = mp->m_sb.sb_blocksize - zero_offset; - error = xfs_iozero(ip, loff + zero_offset, zero_len, end_size); + if (isize + zero_len > offset) + zero_len = offset - isize; + error = xfs_iozero(ip, isize, zero_len); XFS_ILOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); ASSERT(error >= 0); @@ -519,14 +510,15 @@ xfs_zero_eof( bhv_vnode_t *vp, xfs_iocore_t *io, xfs_off_t offset, /* starting I/O offset */ - xfs_fsize_t isize, /* current inode size */ - xfs_fsize_t end_size) /* terminal inode size */ + xfs_fsize_t isize) /* current inode size */ { struct inode *ip = vn_to_inode(vp); xfs_fileoff_t start_zero_fsb; xfs_fileoff_t end_zero_fsb; xfs_fileoff_t zero_count_fsb; xfs_fileoff_t last_fsb; + xfs_fileoff_t zero_off; + xfs_fsize_t zero_len; xfs_mount_t *mp = io->io_mount; int nimaps; int error = 0; @@ -540,7 +532,7 @@ xfs_zero_eof( * First handle zeroing the block on which isize resides. * We only zero a part of that block so it is handled specially. */ - error = xfs_zero_last_block(ip, io, isize, end_size); + error = xfs_zero_last_block(ip, io, offset, isize); if (error) { ASSERT(ismrlocked(io->io_lock, MR_UPDATE)); ASSERT(ismrlocked(io->io_iolock, MR_UPDATE)); @@ -601,10 +593,13 @@ xfs_zero_eof( */ XFS_IUNLOCK(mp, io, XFS_ILOCK_EXCL|XFS_EXTSIZE_RD); - error = xfs_iozero(ip, - XFS_FSB_TO_B(mp, start_zero_fsb), - XFS_FSB_TO_B(mp, imap.br_blockcount), - end_size); + zero_off = XFS_FSB_TO_B(mp, start_zero_fsb); + zero_len = XFS_FSB_TO_B(mp, imap.br_blockcount); + + if ((zero_off + zero_len) > offset) + zero_len = offset - zero_off; + + error = xfs_iozero(ip, zero_off, zero_len); if (error) { goto out_lock; } @@ -783,8 +778,7 @@ start: */ if (pos > isize) { - error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, - isize, pos + count); + error = xfs_zero_eof(BHV_TO_VNODE(bdp), io, pos, isize); if (error) { xfs_iunlock(xip, XFS_ILOCK_EXCL|iolock); goto out_unlock_mutex; diff --git a/fs/xfs/linux-2.6/xfs_lrw.h b/fs/xfs/linux-2.6/xfs_lrw.h index c77e62efb74..7ac51b1d216 100644 --- a/fs/xfs/linux-2.6/xfs_lrw.h +++ b/fs/xfs/linux-2.6/xfs_lrw.h @@ -83,7 +83,7 @@ extern int xfs_bdstrat_cb(struct xfs_buf *); extern int xfs_dev_is_read_only(struct xfs_mount *, char *); extern int xfs_zero_eof(struct bhv_vnode *, struct xfs_iocore *, xfs_off_t, - xfs_fsize_t, xfs_fsize_t); + xfs_fsize_t); extern ssize_t xfs_read(struct bhv_desc *, struct kiocb *, const struct iovec *, unsigned int, loff_t *, int, struct cred *); diff --git a/fs/xfs/linux-2.6/xfs_super.c b/fs/xfs/linux-2.6/xfs_super.c index b93265b7c79..1a4103ca593 100644 --- a/fs/xfs/linux-2.6/xfs_super.c +++ b/fs/xfs/linux-2.6/xfs_super.c @@ -43,8 +43,6 @@ #include "xfs_itable.h" #include "xfs_rw.h" #include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" #include "xfs_attr.h" #include "xfs_buf_item.h" #include "xfs_utils.h" @@ -58,10 +56,10 @@ #include <linux/kthread.h> #include <linux/freezer.h> -STATIC struct quotactl_ops xfs_quotactl_operations; -STATIC struct super_operations xfs_super_operations; -STATIC kmem_zone_t *xfs_vnode_zone; -STATIC kmem_zone_t *xfs_ioend_zone; +static struct quotactl_ops xfs_quotactl_operations; +static struct super_operations xfs_super_operations; +static kmem_zone_t *xfs_vnode_zone; +static kmem_zone_t *xfs_ioend_zone; mempool_t *xfs_ioend_pool; STATIC struct xfs_mount_args * @@ -121,7 +119,7 @@ xfs_max_file_offset( return (((__uint64_t)pagefactor) << bitshift) - 1; } -STATIC __inline__ void +STATIC_INLINE void xfs_set_inodeops( struct inode *inode) { @@ -147,7 +145,7 @@ xfs_set_inodeops( } } -STATIC __inline__ void +STATIC_INLINE void xfs_revalidate_inode( xfs_mount_t *mp, bhv_vnode_t *vp, @@ -553,7 +551,6 @@ vfs_sync_worker( error = bhv_vfs_sync(vfsp, SYNC_FSDATA | SYNC_BDFLUSH | \ SYNC_ATTR | SYNC_REFCACHE, NULL); vfsp->vfs_sync_seq++; - wmb(); wake_up(&vfsp->vfs_wait_single_sync_task); } @@ -659,9 +656,17 @@ xfs_fs_sync_super( int error; int flags; - if (unlikely(sb->s_frozen == SB_FREEZE_WRITE)) - flags = SYNC_QUIESCE; - else + if (unlikely(sb->s_frozen == SB_FREEZE_WRITE)) { + /* + * First stage of freeze - no more writers will make progress + * now we are here, so we flush delwri and delalloc buffers + * here, then wait for all I/O to complete. Data is frozen at + * that point. Metadata is not frozen, transactions can still + * occur here so don't bother flushing the buftarg (i.e + * SYNC_QUIESCE) because it'll just get dirty again. + */ + flags = SYNC_FSDATA | SYNC_DELWRI | SYNC_WAIT | SYNC_IOWAIT; + } else flags = SYNC_FSDATA | (wait ? SYNC_WAIT : 0); error = bhv_vfs_sync(vfsp, flags, NULL); @@ -873,7 +878,7 @@ xfs_fs_get_sb( mnt); } -STATIC struct super_operations xfs_super_operations = { +static struct super_operations xfs_super_operations = { .alloc_inode = xfs_fs_alloc_inode, .destroy_inode = xfs_fs_destroy_inode, .write_inode = xfs_fs_write_inode, @@ -887,7 +892,7 @@ STATIC struct super_operations xfs_super_operations = { .show_options = xfs_fs_show_options, }; -STATIC struct quotactl_ops xfs_quotactl_operations = { +static struct quotactl_ops xfs_quotactl_operations = { .quota_sync = xfs_fs_quotasync, .get_xstate = xfs_fs_getxstate, .set_xstate = xfs_fs_setxstate, diff --git a/fs/xfs/linux-2.6/xfs_sysctl.c b/fs/xfs/linux-2.6/xfs_sysctl.c index af246532fbf..5c46c35a97a 100644 --- a/fs/xfs/linux-2.6/xfs_sysctl.c +++ b/fs/xfs/linux-2.6/xfs_sysctl.c @@ -54,102 +54,204 @@ xfs_stats_clear_proc_handler( } #endif /* CONFIG_PROC_FS */ -STATIC ctl_table xfs_table[] = { - {XFS_RESTRICT_CHOWN, "restrict_chown", &xfs_params.restrict_chown.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.restrict_chown.min, &xfs_params.restrict_chown.max}, - - {XFS_SGID_INHERIT, "irix_sgid_inherit", &xfs_params.sgid_inherit.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.sgid_inherit.min, &xfs_params.sgid_inherit.max}, - - {XFS_SYMLINK_MODE, "irix_symlink_mode", &xfs_params.symlink_mode.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.symlink_mode.min, &xfs_params.symlink_mode.max}, - - {XFS_PANIC_MASK, "panic_mask", &xfs_params.panic_mask.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.panic_mask.min, &xfs_params.panic_mask.max}, - - {XFS_ERRLEVEL, "error_level", &xfs_params.error_level.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.error_level.min, &xfs_params.error_level.max}, - - {XFS_SYNCD_TIMER, "xfssyncd_centisecs", &xfs_params.syncd_timer.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.syncd_timer.min, &xfs_params.syncd_timer.max}, - - {XFS_INHERIT_SYNC, "inherit_sync", &xfs_params.inherit_sync.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.inherit_sync.min, &xfs_params.inherit_sync.max}, - - {XFS_INHERIT_NODUMP, "inherit_nodump", &xfs_params.inherit_nodump.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.inherit_nodump.min, &xfs_params.inherit_nodump.max}, - - {XFS_INHERIT_NOATIME, "inherit_noatime", &xfs_params.inherit_noatim.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.inherit_noatim.min, &xfs_params.inherit_noatim.max}, - - {XFS_BUF_TIMER, "xfsbufd_centisecs", &xfs_params.xfs_buf_timer.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.xfs_buf_timer.min, &xfs_params.xfs_buf_timer.max}, - - {XFS_BUF_AGE, "age_buffer_centisecs", &xfs_params.xfs_buf_age.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.xfs_buf_age.min, &xfs_params.xfs_buf_age.max}, - - {XFS_INHERIT_NOSYM, "inherit_nosymlinks", &xfs_params.inherit_nosym.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.inherit_nosym.min, &xfs_params.inherit_nosym.max}, - - {XFS_ROTORSTEP, "rotorstep", &xfs_params.rotorstep.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.rotorstep.min, &xfs_params.rotorstep.max}, - - {XFS_INHERIT_NODFRG, "inherit_nodefrag", &xfs_params.inherit_nodfrg.val, - sizeof(int), 0644, NULL, &proc_dointvec_minmax, - &sysctl_intvec, NULL, - &xfs_params.inherit_nodfrg.min, &xfs_params.inherit_nodfrg.max}, +static ctl_table xfs_table[] = { + { + .ctl_name = XFS_RESTRICT_CHOWN, + .procname = "restrict_chown", + .data = &xfs_params.restrict_chown.val, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xfs_params.restrict_chown.min, + .extra2 = &xfs_params.restrict_chown.max + }, + { + .ctl_name = XFS_SGID_INHERIT, + .procname = "irix_sgid_inherit", + .data = &xfs_params.sgid_inherit.val, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xfs_params.sgid_inherit.min, + .extra2 = &xfs_params.sgid_inherit.max + }, + { + .ctl_name = XFS_SYMLINK_MODE, + .procname = "irix_symlink_mode", + .data = &xfs_params.symlink_mode.val, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xfs_params.symlink_mode.min, + .extra2 = &xfs_params.symlink_mode.max + }, + { + .ctl_name = XFS_PANIC_MASK, + .procname = "panic_mask", + .data = &xfs_params.panic_mask.val, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xfs_params.panic_mask.min, + .extra2 = &xfs_params.panic_mask.max + }, + { + .ctl_name = XFS_ERRLEVEL, + .procname = "error_level", + .data = &xfs_params.error_level.val, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xfs_params.error_level.min, + .extra2 = &xfs_params.error_level.max + }, + { + .ctl_name = XFS_SYNCD_TIMER, + .procname = "xfssyncd_centisecs", + .data = &xfs_params.syncd_timer.val, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xfs_params.syncd_timer.min, + .extra2 = &xfs_params.syncd_timer.max + }, + { + .ctl_name = XFS_INHERIT_SYNC, + .procname = "inherit_sync", + .data = &xfs_params.inherit_sync.val, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xfs_params.inherit_sync.min, + .extra2 = &xfs_params.inherit_sync.max + }, + { + .ctl_name = XFS_INHERIT_NODUMP, + .procname = "inherit_nodump", + .data = &xfs_params.inherit_nodump.val, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xfs_params.inherit_nodump.min, + .extra2 = &xfs_params.inherit_nodump.max + }, + { + .ctl_name = XFS_INHERIT_NOATIME, + .procname = "inherit_noatime", + .data = &xfs_params.inherit_noatim.val, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xfs_params.inherit_noatim.min, + .extra2 = &xfs_params.inherit_noatim.max + }, + { + .ctl_name = XFS_BUF_TIMER, + .procname = "xfsbufd_centisecs", + .data = &xfs_params.xfs_buf_timer.val, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xfs_params.xfs_buf_timer.min, + .extra2 = &xfs_params.xfs_buf_timer.max + }, + { + .ctl_name = XFS_BUF_AGE, + .procname = "age_buffer_centisecs", + .data = &xfs_params.xfs_buf_age.val, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xfs_params.xfs_buf_age.min, + .extra2 = &xfs_params.xfs_buf_age.max + }, + { + .ctl_name = XFS_INHERIT_NOSYM, + .procname = "inherit_nosymlinks", + .data = &xfs_params.inherit_nosym.val, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xfs_params.inherit_nosym.min, + .extra2 = &xfs_params.inherit_nosym.max + }, + { + .ctl_name = XFS_ROTORSTEP, + .procname = "rotorstep", + .data = &xfs_params.rotorstep.val, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xfs_params.rotorstep.min, + .extra2 = &xfs_params.rotorstep.max + }, + { + .ctl_name = XFS_INHERIT_NODFRG, + .procname = "inherit_nodefrag", + .data = &xfs_params.inherit_nodfrg.val, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &proc_dointvec_minmax, + .strategy = &sysctl_intvec, + .extra1 = &xfs_params.inherit_nodfrg.min, + .extra2 = &xfs_params.inherit_nodfrg.max + }, /* please keep this the last entry */ #ifdef CONFIG_PROC_FS - {XFS_STATS_CLEAR, "stats_clear", &xfs_params.stats_clear.val, - sizeof(int), 0644, NULL, &xfs_stats_clear_proc_handler, - &sysctl_intvec, NULL, - &xfs_params.stats_clear.min, &xfs_params.stats_clear.max}, + { + .ctl_name = XFS_STATS_CLEAR, + .procname = "stats_clear", + .data = &xfs_params.stats_clear.val, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = &xfs_stats_clear_proc_handler, + .strategy = &sysctl_intvec, + .extra1 = &xfs_params.stats_clear.min, + .extra2 = &xfs_params.stats_clear.max + }, #endif /* CONFIG_PROC_FS */ - {0} + {} }; -STATIC ctl_table xfs_dir_table[] = { - {FS_XFS, "xfs", NULL, 0, 0555, xfs_table}, - {0} +static ctl_table xfs_dir_table[] = { + { + .ctl_name = FS_XFS, + .procname = "xfs", + .mode = 0555, + .child = xfs_table + }, + {} }; -STATIC ctl_table xfs_root_table[] = { - {CTL_FS, "fs", NULL, 0, 0555, xfs_dir_table}, - {0} +static ctl_table xfs_root_table[] = { + { + .ctl_name = CTL_FS, + .procname = "fs", + .mode = 0555, + .child = xfs_dir_table + }, + {} }; void xfs_sysctl_register(void) { - xfs_table_header = register_sysctl_table(xfs_root_table, 1); + xfs_table_header = register_sysctl_table(xfs_root_table, 0); } void diff --git a/fs/xfs/linux-2.6/xfs_vfs.h b/fs/xfs/linux-2.6/xfs_vfs.h index da255bdf526..e2c2ce98ab5 100644 --- a/fs/xfs/linux-2.6/xfs_vfs.h +++ b/fs/xfs/linux-2.6/xfs_vfs.h @@ -91,7 +91,7 @@ typedef enum { #define SYNC_FSDATA 0x0020 /* flush fs data (e.g. superblocks) */ #define SYNC_REFCACHE 0x0040 /* prune some of the nfs ref cache */ #define SYNC_REMOUNT 0x0080 /* remount readonly, no dummy LRs */ -#define SYNC_QUIESCE 0x0100 /* quiesce fileystem for a snapshot */ +#define SYNC_IOWAIT 0x0100 /* wait for all I/O to complete */ #define SHUTDOWN_META_IO_ERROR 0x0001 /* write attempt to metadata failed */ #define SHUTDOWN_LOG_IO_ERROR 0x0002 /* write attempt to the log failed */ diff --git a/fs/xfs/linux-2.6/xfs_vnode.c b/fs/xfs/linux-2.6/xfs_vnode.c index 553fa731ade..ada24baf88d 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.c +++ b/fs/xfs/linux-2.6/xfs_vnode.c @@ -26,7 +26,7 @@ DEFINE_SPINLOCK(vnumber_lock); */ #define NVSYNC 37 #define vptosync(v) (&vsync[((unsigned long)v) % NVSYNC]) -STATIC wait_queue_head_t vsync[NVSYNC]; +static wait_queue_head_t vsync[NVSYNC]; void vn_init(void) diff --git a/fs/xfs/linux-2.6/xfs_vnode.h b/fs/xfs/linux-2.6/xfs_vnode.h index 515f5fdea57..b76118cf489 100644 --- a/fs/xfs/linux-2.6/xfs_vnode.h +++ b/fs/xfs/linux-2.6/xfs_vnode.h @@ -489,14 +489,14 @@ static inline struct bhv_vnode *vn_grab(struct bhv_vnode *vp) #define VN_LOCK(vp) mutex_spinlock(&(vp)->v_lock) #define VN_UNLOCK(vp, s) mutex_spinunlock(&(vp)->v_lock, s) -static __inline__ void vn_flagset(struct bhv_vnode *vp, uint flag) +STATIC_INLINE void vn_flagset(struct bhv_vnode *vp, uint flag) { spin_lock(&vp->v_lock); vp->v_flag |= flag; spin_unlock(&vp->v_lock); } -static __inline__ uint vn_flagclr(struct bhv_vnode *vp, uint flag) +STATIC_INLINE uint vn_flagclr(struct bhv_vnode *vp, uint flag) { uint cleared; diff --git a/fs/xfs/quota/xfs_dquot.c b/fs/xfs/quota/xfs_dquot.c index 3aa77153185..4adaf13aac6 100644 --- a/fs/xfs/quota/xfs_dquot.c +++ b/fs/xfs/quota/xfs_dquot.c @@ -43,8 +43,6 @@ #include "xfs_itable.h" #include "xfs_rw.h" #include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" #include "xfs_attr.h" #include "xfs_buf_item.h" #include "xfs_trans_space.h" @@ -484,7 +482,7 @@ xfs_qm_dqalloc( xfs_trans_bhold(tp, bp); - if ((error = xfs_bmap_finish(tpp, &flist, firstblock, &committed))) { + if ((error = xfs_bmap_finish(tpp, &flist, &committed))) { goto error1; } diff --git a/fs/xfs/quota/xfs_dquot_item.c b/fs/xfs/quota/xfs_dquot_item.c index 33ad5af386e..ddb61fe22a5 100644 --- a/fs/xfs/quota/xfs_dquot_item.c +++ b/fs/xfs/quota/xfs_dquot_item.c @@ -43,8 +43,6 @@ #include "xfs_itable.h" #include "xfs_rw.h" #include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" #include "xfs_attr.h" #include "xfs_buf_item.h" #include "xfs_trans_priv.h" @@ -399,7 +397,7 @@ xfs_qm_dquot_logitem_committing( /* * This is the ops vector for dquots */ -STATIC struct xfs_item_ops xfs_dquot_item_ops = { +static struct xfs_item_ops xfs_dquot_item_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_dquot_logitem_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_qm_dquot_logitem_format, @@ -606,7 +604,7 @@ xfs_qm_qoffend_logitem_committing(xfs_qoff_logitem_t *qip, xfs_lsn_t commit_lsn) return; } -STATIC struct xfs_item_ops xfs_qm_qoffend_logitem_ops = { +static struct xfs_item_ops xfs_qm_qoffend_logitem_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_qm_qoff_logitem_format, @@ -628,7 +626,7 @@ STATIC struct xfs_item_ops xfs_qm_qoffend_logitem_ops = { /* * This is the ops vector shared by all quotaoff-start log items. */ -STATIC struct xfs_item_ops xfs_qm_qoff_logitem_ops = { +static struct xfs_item_ops xfs_qm_qoff_logitem_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_qm_qoff_logitem_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_qm_qoff_logitem_format, diff --git a/fs/xfs/quota/xfs_qm.c b/fs/xfs/quota/xfs_qm.c index 7c6a3a50379..1de2acdc7f7 100644 --- a/fs/xfs/quota/xfs_qm.c +++ b/fs/xfs/quota/xfs_qm.c @@ -44,8 +44,6 @@ #include "xfs_bmap.h" #include "xfs_rw.h" #include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" #include "xfs_attr.h" #include "xfs_buf_item.h" #include "xfs_trans_space.h" @@ -64,10 +62,10 @@ uint ndquot; kmem_zone_t *qm_dqzone; kmem_zone_t *qm_dqtrxzone; -STATIC kmem_shaker_t xfs_qm_shaker; +static kmem_shaker_t xfs_qm_shaker; -STATIC cred_t xfs_zerocr; -STATIC xfs_inode_t xfs_zeroino; +static cred_t xfs_zerocr; +static xfs_inode_t xfs_zeroino; STATIC void xfs_qm_list_init(xfs_dqlist_t *, char *, int); STATIC void xfs_qm_list_destroy(xfs_dqlist_t *); diff --git a/fs/xfs/quota/xfs_qm_bhv.c b/fs/xfs/quota/xfs_qm_bhv.c index db8872be8c8..d2cdb8a2aad 100644 --- a/fs/xfs/quota/xfs_qm_bhv.c +++ b/fs/xfs/quota/xfs_qm_bhv.c @@ -44,8 +44,6 @@ #include "xfs_error.h" #include "xfs_rw.h" #include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" #include "xfs_attr.h" #include "xfs_buf_item.h" #include "xfs_qm.h" @@ -384,7 +382,7 @@ xfs_qm_dqrele_null( } -STATIC struct xfs_qmops xfs_qmcore_xfs = { +static struct xfs_qmops xfs_qmcore_xfs = { .xfs_qminit = xfs_qm_newmount, .xfs_qmdone = xfs_qm_unmount_quotadestroy, .xfs_qmmount = xfs_qm_endmount, diff --git a/fs/xfs/quota/xfs_qm_stats.c b/fs/xfs/quota/xfs_qm_stats.c index 6f858fb81a3..709f5f545cf 100644 --- a/fs/xfs/quota/xfs_qm_stats.c +++ b/fs/xfs/quota/xfs_qm_stats.c @@ -43,8 +43,6 @@ #include "xfs_error.h" #include "xfs_rw.h" #include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" #include "xfs_attr.h" #include "xfs_buf_item.h" #include "xfs_qm.h" diff --git a/fs/xfs/quota/xfs_qm_syscalls.c b/fs/xfs/quota/xfs_qm_syscalls.c index ed620c4d159..716f562aa8b 100644 --- a/fs/xfs/quota/xfs_qm_syscalls.c +++ b/fs/xfs/quota/xfs_qm_syscalls.c @@ -46,8 +46,6 @@ #include "xfs_error.h" #include "xfs_rw.h" #include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" #include "xfs_attr.h" #include "xfs_buf_item.h" #include "xfs_utils.h" @@ -134,7 +132,7 @@ xfs_qm_quotactl( break; case Q_XQUOTASYNC: - return (xfs_sync_inodes(mp, SYNC_DELWRI, 0, NULL)); + return (xfs_sync_inodes(mp, SYNC_DELWRI, NULL)); default: break; diff --git a/fs/xfs/quota/xfs_trans_dquot.c b/fs/xfs/quota/xfs_trans_dquot.c index 0242e9666e8..d7491e7b1f3 100644 --- a/fs/xfs/quota/xfs_trans_dquot.c +++ b/fs/xfs/quota/xfs_trans_dquot.c @@ -43,8 +43,6 @@ #include "xfs_error.h" #include "xfs_rw.h" #include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" #include "xfs_attr.h" #include "xfs_buf_item.h" #include "xfs_trans_priv.h" diff --git a/fs/xfs/support/debug.c b/fs/xfs/support/debug.c index 4363512d2f9..08bbd3cb87a 100644 --- a/fs/xfs/support/debug.c +++ b/fs/xfs/support/debug.c @@ -19,7 +19,7 @@ #include "debug.h" #include "spin.h" -static char message[256]; /* keep it off the stack */ +static char message[1024]; /* keep it off the stack */ static DEFINE_SPINLOCK(xfs_err_lock); /* Translate from CE_FOO to KERN_FOO, err_level(CE_FOO) == KERN_FOO */ @@ -44,13 +44,14 @@ cmn_err(register int level, char *fmt, ...) spin_lock_irqsave(&xfs_err_lock,flags); va_start(ap, fmt); if (*fmt == '!') fp++; - len = vsprintf(message, fp, ap); - if (level != CE_DEBUG && message[len-1] != '\n') - strcat(message, "\n"); - printk("%s%s", err_level[level], message); + len = vsnprintf(message, sizeof(message), fp, ap); + if (len >= sizeof(message)) + len = sizeof(message) - 1; + if (message[len-1] == '\n') + message[len-1] = 0; + printk("%s%s\n", err_level[level], message); va_end(ap); spin_unlock_irqrestore(&xfs_err_lock,flags); - BUG_ON(level == CE_PANIC); } @@ -64,11 +65,13 @@ icmn_err(register int level, char *fmt, va_list ap) if(level > XFS_MAX_ERR_LEVEL) level = XFS_MAX_ERR_LEVEL; spin_lock_irqsave(&xfs_err_lock,flags); - len = vsprintf(message, fmt, ap); - if (level != CE_DEBUG && message[len-1] != '\n') - strcat(message, "\n"); + len = vsnprintf(message, sizeof(message), fmt, ap); + if (len >= sizeof(message)) + len = sizeof(message) - 1; + if (message[len-1] == '\n') + message[len-1] = 0; + printk("%s%s\n", err_level[level], message); spin_unlock_irqrestore(&xfs_err_lock,flags); - printk("%s%s", err_level[level], message); BUG_ON(level == CE_PANIC); } diff --git a/fs/xfs/support/debug.h b/fs/xfs/support/debug.h index 4f54dca662a..2a70cc605ae 100644 --- a/fs/xfs/support/debug.h +++ b/fs/xfs/support/debug.h @@ -38,13 +38,37 @@ extern void assfail(char *expr, char *f, int l); #ifndef DEBUG # define ASSERT(expr) ((void)0) -#else + +#ifndef STATIC +# define STATIC static noinline +#endif + +#ifndef STATIC_INLINE +# define STATIC_INLINE static inline +#endif + +#else /* DEBUG */ + # define ASSERT(expr) ASSERT_ALWAYS(expr) extern unsigned long random(void); -#endif #ifndef STATIC -# define STATIC static +# define STATIC noinline #endif +/* + * We stop inlining of inline functions in debug mode. + * Unfortunately, this means static inline in header files + * get multiple definitions, so they need to remain static. + * This then gives tonnes of warnings about unused but defined + * functions, so we need to add the unused attribute to prevent + * these spurious warnings. + */ +#ifndef STATIC_INLINE +# define STATIC_INLINE static __attribute__ ((unused)) noinline +#endif + +#endif /* DEBUG */ + + #endif /* __XFS_SUPPORT_DEBUG_H__ */ diff --git a/fs/xfs/support/move.h b/fs/xfs/support/move.h index 977879c24ff..324e413dead 100644 --- a/fs/xfs/support/move.h +++ b/fs/xfs/support/move.h @@ -55,7 +55,7 @@ enum uio_seg { }; struct uio { - struct iovec *uio_iov; /* pointer to array of iovecs */ + struct kvec *uio_iov; /* pointer to array of iovecs */ int uio_iovcnt; /* number of iovecs in array */ xfs_off_t uio_offset; /* offset in file this uio corresponds to */ int uio_resid; /* residual i/o count */ @@ -63,7 +63,7 @@ struct uio { }; typedef struct uio uio_t; -typedef struct iovec iovec_t; +typedef struct kvec iovec_t; extern int xfs_uio_read (caddr_t, size_t, uio_t *); diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c index 4b0cb474be4..4ca4beb7bb5 100644 --- a/fs/xfs/xfs_acl.c +++ b/fs/xfs/xfs_acl.c @@ -31,7 +31,6 @@ #include "xfs_inode.h" #include "xfs_btree.h" #include "xfs_acl.h" -#include "xfs_mac.h" #include "xfs_attr.h" #include <linux/capability.h> diff --git a/fs/xfs/xfs_alloc_btree.h b/fs/xfs/xfs_alloc_btree.h index bce81c7a4fd..5bd1a2c8bd0 100644 --- a/fs/xfs/xfs_alloc_btree.h +++ b/fs/xfs/xfs_alloc_btree.h @@ -58,7 +58,6 @@ typedef struct xfs_btree_sblock xfs_alloc_block_t; /* * Real block structures have a size equal to the disk block size. */ -#define XFS_ALLOC_BLOCK_SIZE(lev,cur) (1 << (cur)->bc_blocklog) #define XFS_ALLOC_BLOCK_MAXRECS(lev,cur) ((cur)->bc_mp->m_alloc_mxr[lev != 0]) #define XFS_ALLOC_BLOCK_MINRECS(lev,cur) ((cur)->bc_mp->m_alloc_mnr[lev != 0]) @@ -87,16 +86,13 @@ typedef struct xfs_btree_sblock xfs_alloc_block_t; * Record, key, and pointer address macros for btree blocks. */ #define XFS_ALLOC_REC_ADDR(bb,i,cur) \ - XFS_BTREE_REC_ADDR(XFS_ALLOC_BLOCK_SIZE(0,cur), xfs_alloc, \ - bb, i, XFS_ALLOC_BLOCK_MAXRECS(0, cur)) + XFS_BTREE_REC_ADDR(xfs_alloc, bb, i) #define XFS_ALLOC_KEY_ADDR(bb,i,cur) \ - XFS_BTREE_KEY_ADDR(XFS_ALLOC_BLOCK_SIZE(1,cur), xfs_alloc, \ - bb, i, XFS_ALLOC_BLOCK_MAXRECS(1, cur)) + XFS_BTREE_KEY_ADDR(xfs_alloc, bb, i) #define XFS_ALLOC_PTR_ADDR(bb,i,cur) \ - XFS_BTREE_PTR_ADDR(XFS_ALLOC_BLOCK_SIZE(1,cur), xfs_alloc, \ - bb, i, XFS_ALLOC_BLOCK_MAXRECS(1, cur)) + XFS_BTREE_PTR_ADDR(xfs_alloc, bb, i, XFS_ALLOC_BLOCK_MAXRECS(1, cur)) /* * Decrement cursor by one record at the level. diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c index 9ada7bdbae5..9d358ffce4e 100644 --- a/fs/xfs/xfs_attr.c +++ b/fs/xfs/xfs_attr.c @@ -57,9 +57,9 @@ */ #define ATTR_SYSCOUNT 2 -STATIC struct attrnames posix_acl_access; -STATIC struct attrnames posix_acl_default; -STATIC struct attrnames *attr_system_names[ATTR_SYSCOUNT]; +static struct attrnames posix_acl_access; +static struct attrnames posix_acl_default; +static struct attrnames *attr_system_names[ATTR_SYSCOUNT]; /*======================================================================== * Function prototypes for the kernel. @@ -199,18 +199,14 @@ xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, return (error); /* - * Determine space new attribute will use, and if it would be - * "local" or "remote" (note: local != inline). - */ - size = xfs_attr_leaf_newentsize(namelen, valuelen, - mp->m_sb.sb_blocksize, &local); - - /* * If the inode doesn't have an attribute fork, add one. * (inode must not be locked when we call this routine) */ if (XFS_IFORK_Q(dp) == 0) { - if ((error = xfs_bmap_add_attrfork(dp, size, rsvd))) + int sf_size = sizeof(xfs_attr_sf_hdr_t) + + XFS_ATTR_SF_ENTSIZE_BYNAME(namelen, valuelen); + + if ((error = xfs_bmap_add_attrfork(dp, sf_size, rsvd))) return(error); } @@ -231,6 +227,13 @@ xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, args.addname = 1; args.oknoent = 1; + /* + * Determine space new attribute will use, and if it would be + * "local" or "remote" (note: local != inline). + */ + size = xfs_attr_leaf_newentsize(namelen, valuelen, + mp->m_sb.sb_blocksize, &local); + nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); if (local) { if (size > (mp->m_sb.sb_blocksize >> 1)) { @@ -346,7 +349,7 @@ xfs_attr_set_int(xfs_inode_t *dp, const char *name, int namelen, error = xfs_attr_shortform_to_leaf(&args); if (!error) { error = xfs_bmap_finish(&args.trans, args.flist, - *args.firstblock, &committed); + &committed); } if (error) { ASSERT(committed); @@ -973,7 +976,7 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) error = xfs_attr_leaf_to_node(args); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); + &committed); } if (error) { ASSERT(committed); @@ -1074,7 +1077,6 @@ xfs_attr_leaf_addname(xfs_da_args_t *args) if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); } if (error) { @@ -1152,7 +1154,7 @@ xfs_attr_leaf_removename(xfs_da_args_t *args) /* bp is gone due to xfs_da_shrink_inode */ if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); + &committed); } if (error) { ASSERT(committed); @@ -1307,7 +1309,6 @@ restart: if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); } if (error) { @@ -1347,7 +1348,7 @@ restart: error = xfs_da_split(state); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); + &committed); } if (error) { ASSERT(committed); @@ -1459,7 +1460,6 @@ restart: if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); } if (error) { @@ -1594,7 +1594,7 @@ xfs_attr_node_removename(xfs_da_args_t *args) error = xfs_da_join(state); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); + &committed); } if (error) { ASSERT(committed); @@ -1646,7 +1646,6 @@ xfs_attr_node_removename(xfs_da_args_t *args) if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); } if (error) { @@ -2090,7 +2089,7 @@ xfs_attr_rmtval_set(xfs_da_args_t *args) args->flist, NULL); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); + &committed); } if (error) { ASSERT(committed); @@ -2246,7 +2245,7 @@ xfs_attr_rmtval_remove(xfs_da_args_t *args) NULL, &done); if (!error) { error = xfs_bmap_finish(&args->trans, args->flist, - *args->firstblock, &committed); + &committed); } if (error) { ASSERT(committed); @@ -2477,7 +2476,7 @@ posix_acl_default_exists( return xfs_acl_vhasacl_default(vp); } -STATIC struct attrnames posix_acl_access = { +static struct attrnames posix_acl_access = { .attr_name = "posix_acl_access", .attr_namelen = sizeof("posix_acl_access") - 1, .attr_get = posix_acl_access_get, @@ -2486,7 +2485,7 @@ STATIC struct attrnames posix_acl_access = { .attr_exists = posix_acl_access_exists, }; -STATIC struct attrnames posix_acl_default = { +static struct attrnames posix_acl_default = { .attr_name = "posix_acl_default", .attr_namelen = sizeof("posix_acl_default") - 1, .attr_get = posix_acl_default_get, @@ -2495,7 +2494,7 @@ STATIC struct attrnames posix_acl_default = { .attr_exists = posix_acl_default_exists, }; -STATIC struct attrnames *attr_system_names[] = +static struct attrnames *attr_system_names[] = { &posix_acl_access, &posix_acl_default }; diff --git a/fs/xfs/xfs_attr_leaf.c b/fs/xfs/xfs_attr_leaf.c index 9719bbef122..8eab73e8340 100644 --- a/fs/xfs/xfs_attr_leaf.c +++ b/fs/xfs/xfs_attr_leaf.c @@ -94,7 +94,7 @@ STATIC int xfs_attr_leaf_entsize(xfs_attr_leafblock_t *leaf, int index); * Namespace helper routines *========================================================================*/ -STATIC inline attrnames_t * +STATIC_INLINE attrnames_t * xfs_attr_flags_namesp(int flags) { return ((flags & XFS_ATTR_SECURE) ? &attr_secure: @@ -105,7 +105,7 @@ xfs_attr_flags_namesp(int flags) * If namespace bits don't match return 0. * If all match then return 1. */ -STATIC inline int +STATIC_INLINE int xfs_attr_namesp_match(int arg_flags, int ondisk_flags) { return XFS_ATTR_NSP_ONDISK(ondisk_flags) == XFS_ATTR_NSP_ARGS_TO_ONDISK(arg_flags); @@ -116,7 +116,7 @@ xfs_attr_namesp_match(int arg_flags, int ondisk_flags) * then return 0. * If all match or are overridable then return 1. */ -STATIC inline int +STATIC_INLINE int xfs_attr_namesp_match_overrides(int arg_flags, int ondisk_flags) { if (((arg_flags & ATTR_SECURE) == 0) != @@ -150,6 +150,7 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes) int offset; int minforkoff; /* lower limit on valid forkoff locations */ int maxforkoff; /* upper limit on valid forkoff locations */ + int dsize; xfs_mount_t *mp = dp->i_mount; offset = (XFS_LITINO(mp) - bytes) >> 3; /* rounded down */ @@ -169,8 +170,43 @@ xfs_attr_shortform_bytesfit(xfs_inode_t *dp, int bytes) return 0; } - /* data fork btree root can have at least this many key/ptr pairs */ - minforkoff = MAX(dp->i_df.if_bytes, XFS_BMDR_SPACE_CALC(MINDBTPTRS)); + dsize = dp->i_df.if_bytes; + + switch (dp->i_d.di_format) { + case XFS_DINODE_FMT_EXTENTS: + /* + * If there is no attr fork and the data fork is extents, + * determine if creating the default attr fork will result + * in the extents form migrating to btree. If so, the + * minimum offset only needs to be the space required for + * the btree root. + */ + if (!dp->i_d.di_forkoff && dp->i_df.if_bytes > mp->m_attroffset) + dsize = XFS_BMDR_SPACE_CALC(MINDBTPTRS); + break; + + case XFS_DINODE_FMT_BTREE: + /* + * If have data btree then keep forkoff if we have one, + * otherwise we are adding a new attr, so then we set + * minforkoff to where the btree root can finish so we have + * plenty of room for attrs + */ + if (dp->i_d.di_forkoff) { + if (offset < dp->i_d.di_forkoff) + return 0; + else + return dp->i_d.di_forkoff; + } else + dsize = XFS_BMAP_BROOT_SPACE(dp->i_df.if_broot); + break; + } + + /* + * A data fork btree root must have space for at least + * MINDBTPTRS key/ptr pairs if the data fork is small or empty. + */ + minforkoff = MAX(dsize, XFS_BMDR_SPACE_CALC(MINDBTPTRS)); minforkoff = roundup(minforkoff, 8) >> 3; /* attr fork btree root can have at least this many key/ptr pairs */ @@ -336,7 +372,8 @@ xfs_attr_shortform_remove(xfs_da_args_t *args) */ totsize -= size; if (totsize == sizeof(xfs_attr_sf_hdr_t) && !args->addname && - (mp->m_flags & XFS_MOUNT_ATTR2)) { + (mp->m_flags & XFS_MOUNT_ATTR2) && + (dp->i_d.di_format != XFS_DINODE_FMT_BTREE)) { /* * Last attribute now removed, revert to original * inode format making all literal area available @@ -355,7 +392,8 @@ xfs_attr_shortform_remove(xfs_da_args_t *args) dp->i_d.di_forkoff = xfs_attr_shortform_bytesfit(dp, totsize); ASSERT(dp->i_d.di_forkoff); ASSERT(totsize > sizeof(xfs_attr_sf_hdr_t) || args->addname || - !(mp->m_flags & XFS_MOUNT_ATTR2)); + !(mp->m_flags & XFS_MOUNT_ATTR2) || + dp->i_d.di_format == XFS_DINODE_FMT_BTREE); dp->i_afp->if_ext_max = XFS_IFORK_ASIZE(dp) / (uint)sizeof(xfs_bmbt_rec_t); dp->i_df.if_ext_max = @@ -748,6 +786,7 @@ xfs_attr_shortform_allfit(xfs_dabuf_t *bp, xfs_inode_t *dp) + be16_to_cpu(name_loc->valuelen); } if ((dp->i_mount->m_flags & XFS_MOUNT_ATTR2) && + (dp->i_d.di_format != XFS_DINODE_FMT_BTREE) && (bytes == sizeof(struct xfs_attr_sf_hdr))) return(-1); return(xfs_attr_shortform_bytesfit(dp, bytes)); @@ -786,6 +825,7 @@ xfs_attr_leaf_to_shortform(xfs_dabuf_t *bp, xfs_da_args_t *args, int forkoff) if (forkoff == -1) { ASSERT(dp->i_mount->m_flags & XFS_MOUNT_ATTR2); + ASSERT(dp->i_d.di_format != XFS_DINODE_FMT_BTREE); /* * Last attribute was removed, revert to original diff --git a/fs/xfs/xfs_bit.c b/fs/xfs/xfs_bit.c index 43be6a7e47c..1afe07f67e3 100644 --- a/fs/xfs/xfs_bit.c +++ b/fs/xfs/xfs_bit.c @@ -29,7 +29,7 @@ /* * Index of high bit number in byte, -1 for none set, 0..7 otherwise. */ -STATIC const char xfs_highbit[256] = { +static const char xfs_highbit[256] = { -1, 0, 1, 1, 2, 2, 2, 2, /* 00 .. 07 */ 3, 3, 3, 3, 3, 3, 3, 3, /* 08 .. 0f */ 4, 4, 4, 4, 4, 4, 4, 4, /* 10 .. 17 */ diff --git a/fs/xfs/xfs_bmap.c b/fs/xfs/xfs_bmap.c index 498ad50d1f4..87795188ced 100644 --- a/fs/xfs/xfs_bmap.c +++ b/fs/xfs/xfs_bmap.c @@ -185,16 +185,6 @@ xfs_bmap_btree_to_extents( int *logflagsp, /* inode logging flags */ int whichfork); /* data or attr fork */ -#ifdef DEBUG -/* - * Check that the extents list for the inode ip is in the right order. - */ -STATIC void -xfs_bmap_check_extents( - xfs_inode_t *ip, /* incore inode pointer */ - int whichfork); /* data or attr fork */ -#endif - /* * Called by xfs_bmapi to update file extent records and the btree * after removing space (or undoing a delayed allocation). @@ -410,7 +400,6 @@ xfs_bmap_count_leaves( STATIC int xfs_bmap_disk_count_leaves( xfs_ifork_t *ifp, - xfs_mount_t *mp, xfs_extnum_t idx, xfs_bmbt_block_t *block, int numrecs, @@ -684,7 +673,7 @@ xfs_bmap_add_extent( ASSERT(nblks <= da_old); if (nblks < da_old) xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS, - (int)(da_old - nblks), rsvd); + (int64_t)(da_old - nblks), rsvd); } /* * Clear out the allocated field, done with it now in any case. @@ -1209,7 +1198,7 @@ xfs_bmap_add_extent_delay_real( diff = (int)(temp + temp2 - STARTBLOCKVAL(PREV.br_startblock) - (cur ? cur->bc_private.b.allocated : 0)); if (diff > 0 && - xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS, -diff, rsvd)) { + xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS, -((int64_t)diff), rsvd)) { /* * Ick gross gag me with a spoon. */ @@ -1220,7 +1209,7 @@ xfs_bmap_add_extent_delay_real( diff--; if (!diff || !xfs_mod_incore_sb(ip->i_mount, - XFS_SBS_FDBLOCKS, -diff, rsvd)) + XFS_SBS_FDBLOCKS, -((int64_t)diff), rsvd)) break; } if (temp2) { @@ -1228,7 +1217,7 @@ xfs_bmap_add_extent_delay_real( diff--; if (!diff || !xfs_mod_incore_sb(ip->i_mount, - XFS_SBS_FDBLOCKS, -diff, rsvd)) + XFS_SBS_FDBLOCKS, -((int64_t)diff), rsvd)) break; } } @@ -2015,7 +2004,7 @@ xfs_bmap_add_extent_hole_delay( if (oldlen != newlen) { ASSERT(oldlen > newlen); xfs_mod_incore_sb(ip->i_mount, XFS_SBS_FDBLOCKS, - (int)(oldlen - newlen), rsvd); + (int64_t)(oldlen - newlen), rsvd); /* * Nothing to do for disk quota accounting here. */ @@ -3359,7 +3348,7 @@ xfs_bmap_del_extent( */ ASSERT(da_old >= da_new); if (da_old > da_new) - xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, (int)(da_old - da_new), + xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, (int64_t)(da_old - da_new), rsvd); if (delta) { /* DELTA: report the original extent. */ @@ -3543,6 +3532,7 @@ xfs_bmap_forkoff_reset( if (whichfork == XFS_ATTR_FORK && (ip->i_d.di_format != XFS_DINODE_FMT_DEV) && (ip->i_d.di_format != XFS_DINODE_FMT_UUID) && + (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) && ((mp->m_attroffset >> 3) > ip->i_d.di_forkoff)) { ip->i_d.di_forkoff = mp->m_attroffset >> 3; ip->i_df.if_ext_max = XFS_IFORK_DSIZE(ip) / @@ -4079,7 +4069,7 @@ xfs_bmap_add_attrfork( } else XFS_SB_UNLOCK(mp, s); } - if ((error = xfs_bmap_finish(&tp, &flist, firstblock, &committed))) + if ((error = xfs_bmap_finish(&tp, &flist, &committed))) goto error2; error = xfs_trans_commit(tp, XFS_TRANS_PERM_LOG_RES, NULL); ASSERT(ip->i_df.if_ext_max == @@ -4212,7 +4202,6 @@ int /* error */ xfs_bmap_finish( xfs_trans_t **tp, /* transaction pointer addr */ xfs_bmap_free_t *flist, /* i/o: list extents to free */ - xfs_fsblock_t firstblock, /* controlled ag for allocs */ int *committed) /* xact committed or not */ { xfs_efd_log_item_t *efd; /* extent free data */ @@ -4533,8 +4522,7 @@ xfs_bmap_read_extents( error0); if (level == 0) break; - pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, - 1, mp->m_bmap_dmxr[1]); + pp = XFS_BTREE_PTR_ADDR(xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]); bno = be64_to_cpu(*pp); XFS_WANT_CORRUPTED_GOTO(XFS_FSB_SANITY_CHECK(mp, bno), error0); xfs_trans_brelse(tp, bp); @@ -4577,8 +4565,7 @@ xfs_bmap_read_extents( /* * Copy records into the extent records. */ - frp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, - block, 1, mp->m_bmap_dmxr[0]); + frp = XFS_BTREE_REC_ADDR(xfs_bmbt, block, 1); start = i; for (j = 0; j < num_recs; j++, i++, frp++) { trp = xfs_iext_get_ext(ifp, i); @@ -4929,28 +4916,28 @@ xfs_bmapi( if (rt) { error = xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS, - -(extsz), (flags & + -((int64_t)extsz), (flags & XFS_BMAPI_RSVBLOCKS)); } else { error = xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, - -(alen), (flags & + -((int64_t)alen), (flags & XFS_BMAPI_RSVBLOCKS)); } if (!error) { error = xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, - -(indlen), (flags & + -((int64_t)indlen), (flags & XFS_BMAPI_RSVBLOCKS)); if (error && rt) xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS, - extsz, (flags & + (int64_t)extsz, (flags & XFS_BMAPI_RSVBLOCKS)); else if (error) xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, - alen, (flags & + (int64_t)alen, (flags & XFS_BMAPI_RSVBLOCKS)); } @@ -5616,13 +5603,13 @@ xfs_bunmapi( rtexts = XFS_FSB_TO_B(mp, del.br_blockcount); do_div(rtexts, mp->m_sb.sb_rextsize); xfs_mod_incore_sb(mp, XFS_SBS_FREXTENTS, - (int)rtexts, rsvd); + (int64_t)rtexts, rsvd); (void)XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, NULL, ip, -((long)del.br_blockcount), 0, XFS_QMOPT_RES_RTBLKS); } else { xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, - (int)del.br_blockcount, rsvd); + (int64_t)del.br_blockcount, rsvd); (void)XFS_TRANS_RESERVE_QUOTA_NBLKS(mp, NULL, ip, -((long)del.br_blockcount), 0, XFS_QMOPT_RES_REGBLKS); @@ -6048,32 +6035,6 @@ xfs_bmap_eof( } #ifdef DEBUG -/* - * Check that the extents list for the inode ip is in the right order. - */ -STATIC void -xfs_bmap_check_extents( - xfs_inode_t *ip, /* incore inode pointer */ - int whichfork) /* data or attr fork */ -{ - xfs_bmbt_rec_t *ep; /* current extent entry */ - xfs_extnum_t idx; /* extent record index */ - xfs_ifork_t *ifp; /* inode fork pointer */ - xfs_extnum_t nextents; /* number of extents in list */ - xfs_bmbt_rec_t *nextp; /* next extent entry */ - - ifp = XFS_IFORK_PTR(ip, whichfork); - ASSERT(ifp->if_flags & XFS_IFEXTENTS); - nextents = ifp->if_bytes / (uint)sizeof(xfs_bmbt_rec_t); - ep = xfs_iext_get_ext(ifp, 0); - for (idx = 0; idx < nextents - 1; idx++) { - nextp = xfs_iext_get_ext(ifp, idx + 1); - xfs_btree_check_rec(XFS_BTNUM_BMAP, (void *)ep, - (void *)(nextp)); - ep = nextp; - } -} - STATIC xfs_buf_t * xfs_bmap_get_bp( @@ -6156,8 +6117,7 @@ xfs_check_block( if (root) { keyp = XFS_BMAP_BROOT_KEY_ADDR(block, i, sz); } else { - keyp = XFS_BTREE_KEY_ADDR(mp->m_sb.sb_blocksize, - xfs_bmbt, block, i, dmxr); + keyp = XFS_BTREE_KEY_ADDR(xfs_bmbt, block, i); } if (prevp) { @@ -6172,15 +6132,14 @@ xfs_check_block( if (root) { pp = XFS_BMAP_BROOT_PTR_ADDR(block, i, sz); } else { - pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, - xfs_bmbt, block, i, dmxr); + pp = XFS_BTREE_PTR_ADDR(xfs_bmbt, block, i, dmxr); } for (j = i+1; j <= be16_to_cpu(block->bb_numrecs); j++) { if (root) { thispa = XFS_BMAP_BROOT_PTR_ADDR(block, j, sz); } else { - thispa = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, - xfs_bmbt, block, j, dmxr); + thispa = XFS_BTREE_PTR_ADDR(xfs_bmbt, block, j, + dmxr); } if (*thispa == *pp) { cmn_err(CE_WARN, "%s: thispa(%d) == pp(%d) %Ld", @@ -6267,8 +6226,7 @@ xfs_bmap_check_leaf_extents( */ xfs_check_block(block, mp, 0, 0); - pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, block, - 1, mp->m_bmap_dmxr[1]); + pp = XFS_BTREE_PTR_ADDR(xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]); bno = be64_to_cpu(*pp); XFS_WANT_CORRUPTED_GOTO(XFS_FSB_SANITY_CHECK(mp, bno), error0); if (bp_release) { @@ -6305,11 +6263,9 @@ xfs_bmap_check_leaf_extents( * conform with the first entry in this one. */ - ep = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, - block, 1, mp->m_bmap_dmxr[0]); + ep = XFS_BTREE_REC_ADDR(xfs_bmbt, block, 1); for (j = 1; j < num_recs; j++) { - nextp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_bmbt, - block, j + 1, mp->m_bmap_dmxr[0]); + nextp = XFS_BTREE_REC_ADDR(xfs_bmbt, block, j + 1); if (lastp) { xfs_btree_check_rec(XFS_BTNUM_BMAP, (void *)lastp, (void *)ep); @@ -6454,8 +6410,7 @@ xfs_bmap_count_tree( } /* Dive to the next level */ - pp = XFS_BTREE_PTR_ADDR(mp->m_sb.sb_blocksize, - xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]); + pp = XFS_BTREE_PTR_ADDR(xfs_bmbt, block, 1, mp->m_bmap_dmxr[1]); bno = be64_to_cpu(*pp); if (unlikely((error = xfs_bmap_count_tree(mp, tp, ifp, bno, level, count)) < 0)) { @@ -6470,7 +6425,7 @@ xfs_bmap_count_tree( for (;;) { nextbno = be64_to_cpu(block->bb_rightsib); numrecs = be16_to_cpu(block->bb_numrecs); - if (unlikely(xfs_bmap_disk_count_leaves(ifp, mp, + if (unlikely(xfs_bmap_disk_count_leaves(ifp, 0, block, numrecs, count) < 0)) { xfs_trans_brelse(tp, bp); XFS_ERROR_REPORT("xfs_bmap_count_tree(2)", @@ -6518,7 +6473,6 @@ xfs_bmap_count_leaves( int xfs_bmap_disk_count_leaves( xfs_ifork_t *ifp, - xfs_mount_t *mp, xfs_extnum_t idx, xfs_bmbt_block_t *block, int numrecs, @@ -6528,8 +6482,7 @@ xfs_bmap_disk_count_leaves( xfs_bmbt_rec_t *frp; for (b = 1; b <= numrecs; b++) { - frp = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, - xfs_bmbt, block, idx + b, mp->m_bmap_dmxr[0]); + frp = XFS_BTREE_REC_ADDR(xfs_bmbt, block, idx + b); *count += xfs_bmbt_disk_get_blockcount(frp); } return 0; diff --git a/fs/xfs/xfs_bmap.h b/fs/xfs/xfs_bmap.h index 80e93409b78..4f24c7e39b3 100644 --- a/fs/xfs/xfs_bmap.h +++ b/fs/xfs/xfs_bmap.h @@ -202,7 +202,6 @@ int /* error */ xfs_bmap_finish( struct xfs_trans **tp, /* transaction pointer addr */ xfs_bmap_free_t *flist, /* i/o: list extents to free */ - xfs_fsblock_t firstblock, /* controlled a.g. for allocs */ int *committed); /* xact committed or not */ /* diff --git a/fs/xfs/xfs_bmap_btree.c b/fs/xfs/xfs_bmap_btree.c index a7b835bf870..0bf192fea3e 100644 --- a/fs/xfs/xfs_bmap_btree.c +++ b/fs/xfs/xfs_bmap_btree.c @@ -678,47 +678,6 @@ error0: return error; } -#ifdef DEBUG -/* - * Get the data from the pointed-to record. - */ -int -xfs_bmbt_get_rec( - xfs_btree_cur_t *cur, - xfs_fileoff_t *off, - xfs_fsblock_t *bno, - xfs_filblks_t *len, - xfs_exntst_t *state, - int *stat) -{ - xfs_bmbt_block_t *block; - xfs_buf_t *bp; -#ifdef DEBUG - int error; -#endif - int ptr; - xfs_bmbt_rec_t *rp; - - block = xfs_bmbt_get_block(cur, 0, &bp); - ptr = cur->bc_ptrs[0]; -#ifdef DEBUG - if ((error = xfs_btree_check_lblock(cur, block, 0, bp))) - return error; -#endif - if (ptr > be16_to_cpu(block->bb_numrecs) || ptr <= 0) { - *stat = 0; - return 0; - } - rp = XFS_BMAP_REC_IADDR(block, ptr, cur); - *off = xfs_bmbt_disk_get_startoff(rp); - *bno = xfs_bmbt_disk_get_startblock(rp); - *len = xfs_bmbt_disk_get_blockcount(rp); - *state = xfs_bmbt_disk_get_state(rp); - *stat = 1; - return 0; -} -#endif - /* * Insert one record/level. Return information to the caller * allowing the next level up to proceed if necessary. @@ -1731,9 +1690,9 @@ xfs_bmdr_to_bmbt( rblock->bb_leftsib = cpu_to_be64(NULLDFSBNO); rblock->bb_rightsib = cpu_to_be64(NULLDFSBNO); dmxr = (int)XFS_BTREE_BLOCK_MAXRECS(dblocklen, xfs_bmdr, 0); - fkp = XFS_BTREE_KEY_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + fkp = XFS_BTREE_KEY_ADDR(xfs_bmdr, dblock, 1); tkp = XFS_BMAP_BROOT_KEY_ADDR(rblock, 1, rblocklen); - fpp = XFS_BTREE_PTR_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + fpp = XFS_BTREE_PTR_ADDR(xfs_bmdr, dblock, 1, dmxr); tpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen); dmxr = be16_to_cpu(dblock->bb_numrecs); memcpy(tkp, fkp, sizeof(*fkp) * dmxr); @@ -1862,7 +1821,7 @@ xfs_bmbt_delete( * xfs_bmbt_get_startblock, xfs_bmbt_get_blockcount and xfs_bmbt_get_state. */ -STATIC __inline__ void +STATIC_INLINE void __xfs_bmbt_get_all( __uint64_t l0, __uint64_t l1, @@ -2016,30 +1975,6 @@ xfs_bmbt_disk_get_blockcount( } /* - * Extract the startblock field from an on disk bmap extent record. - */ -xfs_fsblock_t -xfs_bmbt_disk_get_startblock( - xfs_bmbt_rec_t *r) -{ -#if XFS_BIG_BLKNOS - return (((xfs_fsblock_t)INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(9)) << 43) | - (((xfs_fsblock_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); -#else -#ifdef DEBUG - xfs_dfsbno_t b; - - b = (((xfs_dfsbno_t)INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(9)) << 43) | - (((xfs_dfsbno_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); - ASSERT((b >> 32) == 0 || ISNULLDSTARTBLOCK(b)); - return (xfs_fsblock_t)b; -#else /* !DEBUG */ - return (xfs_fsblock_t)(((xfs_dfsbno_t)INT_GET(r->l1, ARCH_CONVERT)) >> 21); -#endif /* DEBUG */ -#endif /* XFS_BIG_BLKNOS */ -} - -/* * Extract the startoff field from a disk format bmap extent record. */ xfs_fileoff_t @@ -2049,17 +1984,6 @@ xfs_bmbt_disk_get_startoff( return ((xfs_fileoff_t)INT_GET(r->l0, ARCH_CONVERT) & XFS_MASK64LO(64 - BMBT_EXNTFLAG_BITLEN)) >> 9; } - -xfs_exntst_t -xfs_bmbt_disk_get_state( - xfs_bmbt_rec_t *r) -{ - int ext_flag; - - ext_flag = (int)((INT_GET(r->l0, ARCH_CONVERT)) >> (64 - BMBT_EXNTFLAG_BITLEN)); - return xfs_extent_state(xfs_bmbt_disk_get_blockcount(r), - ext_flag); -} #endif /* XFS_NATIVE_HOST */ @@ -2684,9 +2608,9 @@ xfs_bmbt_to_bmdr( dblock->bb_numrecs = rblock->bb_numrecs; dmxr = (int)XFS_BTREE_BLOCK_MAXRECS(dblocklen, xfs_bmdr, 0); fkp = XFS_BMAP_BROOT_KEY_ADDR(rblock, 1, rblocklen); - tkp = XFS_BTREE_KEY_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + tkp = XFS_BTREE_KEY_ADDR(xfs_bmdr, dblock, 1); fpp = XFS_BMAP_BROOT_PTR_ADDR(rblock, 1, rblocklen); - tpp = XFS_BTREE_PTR_ADDR(dblocklen, xfs_bmdr, dblock, 1, dmxr); + tpp = XFS_BTREE_PTR_ADDR(xfs_bmdr, dblock, 1, dmxr); dmxr = be16_to_cpu(dblock->bb_numrecs); memcpy(tkp, fkp, sizeof(*fkp) * dmxr); memcpy(tpp, fpp, sizeof(*fpp) * dmxr); diff --git a/fs/xfs/xfs_bmap_btree.h b/fs/xfs/xfs_bmap_btree.h index 49539de9525..a77b1b753d0 100644 --- a/fs/xfs/xfs_bmap_btree.h +++ b/fs/xfs/xfs_bmap_btree.h @@ -175,19 +175,11 @@ typedef struct xfs_btree_lblock xfs_bmbt_block_t; #define XFS_BUF_TO_BMBT_BLOCK(bp) ((xfs_bmbt_block_t *)XFS_BUF_PTR(bp)) -#define XFS_BMAP_IBLOCK_SIZE(lev,cur) (1 << (cur)->bc_blocklog) #define XFS_BMAP_RBLOCK_DSIZE(lev,cur) ((cur)->bc_private.b.forksize) #define XFS_BMAP_RBLOCK_ISIZE(lev,cur) \ ((int)XFS_IFORK_PTR((cur)->bc_private.b.ip, \ (cur)->bc_private.b.whichfork)->if_broot_bytes) -#define XFS_BMAP_BLOCK_DSIZE(lev,cur) \ - (((lev) == (cur)->bc_nlevels - 1 ? \ - XFS_BMAP_RBLOCK_DSIZE(lev,cur) : XFS_BMAP_IBLOCK_SIZE(lev,cur))) -#define XFS_BMAP_BLOCK_ISIZE(lev,cur) \ - (((lev) == (cur)->bc_nlevels - 1 ? \ - XFS_BMAP_RBLOCK_ISIZE(lev,cur) : XFS_BMAP_IBLOCK_SIZE(lev,cur))) - #define XFS_BMAP_BLOCK_DMAXRECS(lev,cur) \ (((lev) == (cur)->bc_nlevels - 1 ? \ XFS_BTREE_BLOCK_MAXRECS(XFS_BMAP_RBLOCK_DSIZE(lev,cur), \ @@ -210,37 +202,21 @@ typedef struct xfs_btree_lblock xfs_bmbt_block_t; xfs_bmbt, (lev) == 0) : \ ((cur)->bc_mp->m_bmap_dmnr[(lev) != 0]))) -#define XFS_BMAP_REC_DADDR(bb,i,cur) \ - (XFS_BTREE_REC_ADDR(XFS_BMAP_BLOCK_DSIZE( \ - be16_to_cpu((bb)->bb_level), cur), \ - xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \ - be16_to_cpu((bb)->bb_level), cur))) -#define XFS_BMAP_REC_IADDR(bb,i,cur) \ - (XFS_BTREE_REC_ADDR(XFS_BMAP_BLOCK_ISIZE( \ - be16_to_cpu((bb)->bb_level), cur), \ - xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \ - be16_to_cpu((bb)->bb_level), cur))) +#define XFS_BMAP_REC_DADDR(bb,i,cur) (XFS_BTREE_REC_ADDR(xfs_bmbt, bb, i)) + +#define XFS_BMAP_REC_IADDR(bb,i,cur) (XFS_BTREE_REC_ADDR(xfs_bmbt, bb, i)) #define XFS_BMAP_KEY_DADDR(bb,i,cur) \ - (XFS_BTREE_KEY_ADDR(XFS_BMAP_BLOCK_DSIZE( \ - be16_to_cpu((bb)->bb_level), cur), \ - xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \ - be16_to_cpu((bb)->bb_level), cur))) + (XFS_BTREE_KEY_ADDR(xfs_bmbt, bb, i)) + #define XFS_BMAP_KEY_IADDR(bb,i,cur) \ - (XFS_BTREE_KEY_ADDR(XFS_BMAP_BLOCK_ISIZE( \ - be16_to_cpu((bb)->bb_level), cur), \ - xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \ - be16_to_cpu((bb)->bb_level), cur))) + (XFS_BTREE_KEY_ADDR(xfs_bmbt, bb, i)) #define XFS_BMAP_PTR_DADDR(bb,i,cur) \ - (XFS_BTREE_PTR_ADDR(XFS_BMAP_BLOCK_DSIZE( \ - be16_to_cpu((bb)->bb_level), cur), \ - xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \ + (XFS_BTREE_PTR_ADDR(xfs_bmbt, bb, i, XFS_BMAP_BLOCK_DMAXRECS( \ be16_to_cpu((bb)->bb_level), cur))) #define XFS_BMAP_PTR_IADDR(bb,i,cur) \ - (XFS_BTREE_PTR_ADDR(XFS_BMAP_BLOCK_ISIZE( \ - be16_to_cpu((bb)->bb_level), cur), \ - xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \ + (XFS_BTREE_PTR_ADDR(xfs_bmbt, bb, i, XFS_BMAP_BLOCK_IMAXRECS( \ be16_to_cpu((bb)->bb_level), cur))) /* @@ -248,11 +224,11 @@ typedef struct xfs_btree_lblock xfs_bmbt_block_t; * we don't have a cursor. */ #define XFS_BMAP_BROOT_REC_ADDR(bb,i,sz) \ - (XFS_BTREE_REC_ADDR(sz,xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz))) + (XFS_BTREE_REC_ADDR(xfs_bmbt,bb,i)) #define XFS_BMAP_BROOT_KEY_ADDR(bb,i,sz) \ - (XFS_BTREE_KEY_ADDR(sz,xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz))) + (XFS_BTREE_KEY_ADDR(xfs_bmbt,bb,i)) #define XFS_BMAP_BROOT_PTR_ADDR(bb,i,sz) \ - (XFS_BTREE_PTR_ADDR(sz,xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz))) + (XFS_BTREE_PTR_ADDR(xfs_bmbt,bb,i,XFS_BMAP_BROOT_MAXRECS(sz))) #define XFS_BMAP_BROOT_NUMRECS(bb) be16_to_cpu((bb)->bb_numrecs) #define XFS_BMAP_BROOT_MAXRECS(sz) XFS_BTREE_BLOCK_MAXRECS(sz,xfs_bmbt,0) @@ -315,15 +291,11 @@ extern xfs_exntst_t xfs_bmbt_get_state(xfs_bmbt_rec_t *r); #ifndef XFS_NATIVE_HOST extern void xfs_bmbt_disk_get_all(xfs_bmbt_rec_t *r, xfs_bmbt_irec_t *s); -extern xfs_exntst_t xfs_bmbt_disk_get_state(xfs_bmbt_rec_t *r); extern xfs_filblks_t xfs_bmbt_disk_get_blockcount(xfs_bmbt_rec_t *r); -extern xfs_fsblock_t xfs_bmbt_disk_get_startblock(xfs_bmbt_rec_t *r); extern xfs_fileoff_t xfs_bmbt_disk_get_startoff(xfs_bmbt_rec_t *r); #else #define xfs_bmbt_disk_get_all(r, s) xfs_bmbt_get_all(r, s) -#define xfs_bmbt_disk_get_state(r) xfs_bmbt_get_state(r) #define xfs_bmbt_disk_get_blockcount(r) xfs_bmbt_get_blockcount(r) -#define xfs_bmbt_disk_get_startblock(r) xfs_bmbt_get_blockcount(r) #define xfs_bmbt_disk_get_startoff(r) xfs_bmbt_get_startoff(r) #endif /* XFS_NATIVE_HOST */ @@ -364,15 +336,6 @@ extern void xfs_bmbt_to_bmdr(xfs_bmbt_block_t *, int, xfs_bmdr_block_t *, int); extern int xfs_bmbt_update(struct xfs_btree_cur *, xfs_fileoff_t, xfs_fsblock_t, xfs_filblks_t, xfs_exntst_t); -#ifdef DEBUG -/* - * Get the data from the pointed-to record. - */ -extern int xfs_bmbt_get_rec(struct xfs_btree_cur *, xfs_fileoff_t *, - xfs_fsblock_t *, xfs_filblks_t *, - xfs_exntst_t *, int *); -#endif - #endif /* __KERNEL__ */ #endif /* __XFS_BMAP_BTREE_H__ */ diff --git a/fs/xfs/xfs_btree.h b/fs/xfs/xfs_btree.h index 892b06c5426..4e27d55a1e7 100644 --- a/fs/xfs/xfs_btree.h +++ b/fs/xfs/xfs_btree.h @@ -122,13 +122,13 @@ extern const __uint32_t xfs_magics[]; * Given block size, type prefix, block pointer, and index of requested entry * (first entry numbered 1). */ -#define XFS_BTREE_REC_ADDR(bsz,t,bb,i,mxr) \ +#define XFS_BTREE_REC_ADDR(t,bb,i) \ ((t ## _rec_t *)((char *)(bb) + sizeof(t ## _block_t) + \ ((i) - 1) * sizeof(t ## _rec_t))) -#define XFS_BTREE_KEY_ADDR(bsz,t,bb,i,mxr) \ +#define XFS_BTREE_KEY_ADDR(t,bb,i) \ ((t ## _key_t *)((char *)(bb) + sizeof(t ## _block_t) + \ ((i) - 1) * sizeof(t ## _key_t))) -#define XFS_BTREE_PTR_ADDR(bsz,t,bb,i,mxr) \ +#define XFS_BTREE_PTR_ADDR(t,bb,i,mxr) \ ((t ## _ptr_t *)((char *)(bb) + sizeof(t ## _block_t) + \ (mxr) * sizeof(t ## _key_t) + ((i) - 1) * sizeof(t ## _ptr_t))) diff --git a/fs/xfs/xfs_buf_item.c b/fs/xfs/xfs_buf_item.c index 7a55c248ea7..6c1bddc04e3 100644 --- a/fs/xfs/xfs_buf_item.c +++ b/fs/xfs/xfs_buf_item.c @@ -660,7 +660,7 @@ xfs_buf_item_committing(xfs_buf_log_item_t *bip, xfs_lsn_t commit_lsn) /* * This is the ops vector shared by all buf log items. */ -STATIC struct xfs_item_ops xfs_buf_item_ops = { +static struct xfs_item_ops xfs_buf_item_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_buf_item_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_buf_item_format, diff --git a/fs/xfs/xfs_buf_item.h b/fs/xfs/xfs_buf_item.h index 07c708c2b52..d7e13614306 100644 --- a/fs/xfs/xfs_buf_item.h +++ b/fs/xfs/xfs_buf_item.h @@ -21,23 +21,7 @@ /* * This is the structure used to lay out a buf log item in the * log. The data map describes which 128 byte chunks of the buffer - * have been logged. This structure works only on buffers that - * reside up to the first TB in the filesystem. These buffers are - * generated only by pre-6.2 systems and are known as XFS_LI_6_1_BUF. - */ -typedef struct xfs_buf_log_format_v1 { - unsigned short blf_type; /* buf log item type indicator */ - unsigned short blf_size; /* size of this item */ - __int32_t blf_blkno; /* starting blkno of this buf */ - ushort blf_flags; /* misc state */ - ushort blf_len; /* number of blocks in this buf */ - unsigned int blf_map_size; /* size of data bitmap in words */ - unsigned int blf_data_map[1];/* variable size bitmap of */ - /* regions of buffer in this item */ -} xfs_buf_log_format_v1_t; - -/* - * This is a form of the above structure with a 64 bit blkno field. + * have been logged. * For 6.2 and beyond, this is XFS_LI_BUF. We use this to log everything. */ typedef struct xfs_buf_log_format_t { diff --git a/fs/xfs/xfs_cap.h b/fs/xfs/xfs_cap.h deleted file mode 100644 index 7a0e482dd43..00000000000 --- a/fs/xfs/xfs_cap.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_CAP_H__ -#define __XFS_CAP_H__ - -/* - * Capabilities - */ -typedef __uint64_t xfs_cap_value_t; - -typedef struct xfs_cap_set { - xfs_cap_value_t cap_effective; /* use in capability checks */ - xfs_cap_value_t cap_permitted; /* combined with file attrs */ - xfs_cap_value_t cap_inheritable;/* pass through exec */ -} xfs_cap_set_t; - -/* On-disk XFS extended attribute names */ -#define SGI_CAP_FILE "SGI_CAP_FILE" -#define SGI_CAP_FILE_SIZE (sizeof(SGI_CAP_FILE)-1) -#define SGI_CAP_LINUX "SGI_CAP_LINUX" -#define SGI_CAP_LINUX_SIZE (sizeof(SGI_CAP_LINUX)-1) - -/* - * For Linux, we take the bitfields directly from capability.h - * and no longer attempt to keep this attribute ondisk compatible - * with IRIX. Since this attribute is only set on executables, - * it just doesn't make much sense to try. We do use a different - * named attribute though, to avoid confusion. - */ - -#ifdef __KERNEL__ - -#ifdef CONFIG_FS_POSIX_CAP - -#include <linux/posix_cap_xattr.h> - -struct bhv_vnode; - -extern int xfs_cap_vhascap(struct bhv_vnode *); -extern int xfs_cap_vset(struct bhv_vnode *, void *, size_t); -extern int xfs_cap_vget(struct bhv_vnode *, void *, size_t); -extern int xfs_cap_vremove(struct bhv_vnode *); - -#define _CAP_EXISTS xfs_cap_vhascap - -#else -#define xfs_cap_vset(v,p,sz) (-EOPNOTSUPP) -#define xfs_cap_vget(v,p,sz) (-EOPNOTSUPP) -#define xfs_cap_vremove(v) (-EOPNOTSUPP) -#define _CAP_EXISTS (NULL) -#endif - -#endif /* __KERNEL__ */ - -#endif /* __XFS_CAP_H__ */ diff --git a/fs/xfs/xfs_da_btree.c b/fs/xfs/xfs_da_btree.c index a68bc1f1a31..aea37df4aa6 100644 --- a/fs/xfs/xfs_da_btree.c +++ b/fs/xfs/xfs_da_btree.c @@ -1090,8 +1090,7 @@ xfs_da_node_lookup_int(xfs_da_state_t *state, int *result) if (blk->magic == XFS_DA_NODE_MAGIC) { node = blk->bp->data; max = be16_to_cpu(node->hdr.count); - btreehashval = node->btree[max-1].hashval; - blk->hashval = be32_to_cpu(btreehashval); + blk->hashval = be32_to_cpu(node->btree[max-1].hashval); /* * Binary search. (note: small blocks will skip loop) @@ -2166,21 +2165,6 @@ xfs_da_reada_buf( return rval; } -/* - * Calculate the number of bits needed to hold i different values. - */ -uint -xfs_da_log2_roundup(uint i) -{ - uint rval; - - for (rval = 0; rval < NBBY * sizeof(i); rval++) { - if ((1 << rval) >= i) - break; - } - return(rval); -} - kmem_zone_t *xfs_da_state_zone; /* anchor for state struct zone */ kmem_zone_t *xfs_dabuf_zone; /* dabuf zone */ diff --git a/fs/xfs/xfs_da_btree.h b/fs/xfs/xfs_da_btree.h index 4ab865ec8b8..44dabf02f2a 100644 --- a/fs/xfs/xfs_da_btree.h +++ b/fs/xfs/xfs_da_btree.h @@ -249,7 +249,6 @@ int xfs_da_shrink_inode(xfs_da_args_t *args, xfs_dablk_t dead_blkno, xfs_dabuf_t *dead_buf); uint xfs_da_hashname(const uchar_t *name_string, int name_length); -uint xfs_da_log2_roundup(uint i); xfs_da_state_t *xfs_da_state_alloc(void); void xfs_da_state_free(xfs_da_state_t *state); diff --git a/fs/xfs/xfs_dfrag.c b/fs/xfs/xfs_dfrag.c index 50d0faea371..b847e6a7a3f 100644 --- a/fs/xfs/xfs_dfrag.c +++ b/fs/xfs/xfs_dfrag.c @@ -41,7 +41,6 @@ #include "xfs_itable.h" #include "xfs_dfrag.h" #include "xfs_error.h" -#include "xfs_mac.h" #include "xfs_rw.h" /* diff --git a/fs/xfs/xfs_error.c b/fs/xfs/xfs_error.c index b95681b03d8..b1af54464f0 100644 --- a/fs/xfs/xfs_error.c +++ b/fs/xfs/xfs_error.c @@ -132,32 +132,6 @@ xfs_errortag_add(int error_tag, xfs_mount_t *mp) } int -xfs_errortag_clear(int error_tag, xfs_mount_t *mp) -{ - int i; - int64_t fsid; - - memcpy(&fsid, mp->m_fixedfsid, sizeof(xfs_fsid_t)); - - for (i = 0; i < XFS_NUM_INJECT_ERROR; i++) { - if (xfs_etest_fsid[i] == fsid && xfs_etest[i] == error_tag) { - xfs_etest[i] = 0; - xfs_etest_fsid[i] = 0LL; - kmem_free(xfs_etest_fsname[i], - strlen(xfs_etest_fsname[i]) + 1); - xfs_etest_fsname[i] = NULL; - cmn_err(CE_WARN, "Cleared XFS error tag #%d", - error_tag); - return 0; - } - } - - cmn_err(CE_WARN, "XFS error tag %d not on", error_tag); - - return 1; -} - -int xfs_errortag_clearall_umount(int64_t fsid, char *fsname, int loud) { int i; diff --git a/fs/xfs/xfs_error.h b/fs/xfs/xfs_error.h index 0893e16b7d8..5599ada456a 100644 --- a/fs/xfs/xfs_error.h +++ b/fs/xfs/xfs_error.h @@ -144,7 +144,6 @@ extern void xfs_error_test_init(void); #endif /* __ANSI_CPP__ */ extern int xfs_errortag_add(int error_tag, xfs_mount_t *mp); -extern int xfs_errortag_clear(int error_tag, xfs_mount_t *mp); extern int xfs_errortag_clearall(xfs_mount_t *mp); extern int xfs_errortag_clearall_umount(int64_t fsid, char *fsname, int loud); #else @@ -180,6 +179,6 @@ extern void xfs_fs_cmn_err(int level, struct xfs_mount *mp, char *fmt, ...); xfs_fs_cmn_err(level, mp, fmt " Unmount and run xfs_repair.", ## args) #define xfs_fs_mount_cmn_err(f, fmt, args...) \ - ((f & XFS_MFSI_QUIET)? cmn_err(CE_WARN, "XFS: " fmt, ## args) : (void)0) + ((f & XFS_MFSI_QUIET)? (void)0 : cmn_err(CE_WARN, "XFS: " fmt, ## args)) #endif /* __XFS_ERROR_H__ */ diff --git a/fs/xfs/xfs_extfree_item.c b/fs/xfs/xfs_extfree_item.c index 6dba78199fa..3b14427ee12 100644 --- a/fs/xfs/xfs_extfree_item.c +++ b/fs/xfs/xfs_extfree_item.c @@ -227,7 +227,7 @@ xfs_efi_item_committing(xfs_efi_log_item_t *efip, xfs_lsn_t lsn) /* * This is the ops vector shared by all efi log items. */ -STATIC struct xfs_item_ops xfs_efi_item_ops = { +static struct xfs_item_ops xfs_efi_item_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_efi_item_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_efi_item_format, @@ -525,7 +525,7 @@ xfs_efd_item_committing(xfs_efd_log_item_t *efip, xfs_lsn_t lsn) /* * This is the ops vector shared by all efd log items. */ -STATIC struct xfs_item_ops xfs_efd_item_ops = { +static struct xfs_item_ops xfs_efd_item_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_efd_item_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_efd_item_format, diff --git a/fs/xfs/xfs_fsops.c b/fs/xfs/xfs_fsops.c index c064e72ada9..32c37c1c47a 100644 --- a/fs/xfs/xfs_fsops.c +++ b/fs/xfs/xfs_fsops.c @@ -250,8 +250,7 @@ xfs_growfs_data_private( block->bb_numrecs = cpu_to_be16(1); block->bb_leftsib = cpu_to_be32(NULLAGBLOCK); block->bb_rightsib = cpu_to_be32(NULLAGBLOCK); - arec = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, - block, 1, mp->m_alloc_mxr[0]); + arec = XFS_BTREE_REC_ADDR(xfs_alloc, block, 1); arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp)); arec->ar_blockcount = cpu_to_be32( agsize - be32_to_cpu(arec->ar_startblock)); @@ -272,8 +271,7 @@ xfs_growfs_data_private( block->bb_numrecs = cpu_to_be16(1); block->bb_leftsib = cpu_to_be32(NULLAGBLOCK); block->bb_rightsib = cpu_to_be32(NULLAGBLOCK); - arec = XFS_BTREE_REC_ADDR(mp->m_sb.sb_blocksize, xfs_alloc, - block, 1, mp->m_alloc_mxr[0]); + arec = XFS_BTREE_REC_ADDR(xfs_alloc, block, 1); arec->ar_startblock = cpu_to_be32(XFS_PREALLOC_BLOCKS(mp)); arec->ar_blockcount = cpu_to_be32( agsize - be32_to_cpu(arec->ar_startblock)); @@ -460,7 +458,7 @@ xfs_fs_counts( { unsigned long s; - xfs_icsb_sync_counters_lazy(mp); + xfs_icsb_sync_counters_flags(mp, XFS_ICSB_LAZY_COUNT); s = XFS_SB_LOCK(mp); cnt->freedata = mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); cnt->freertx = mp->m_sb.sb_frextents; @@ -491,7 +489,7 @@ xfs_reserve_blocks( __uint64_t *inval, xfs_fsop_resblks_t *outval) { - __int64_t lcounter, delta; + __int64_t lcounter, delta, fdblks_delta; __uint64_t request; unsigned long s; @@ -504,17 +502,35 @@ xfs_reserve_blocks( } request = *inval; + + /* + * With per-cpu counters, this becomes an interesting + * problem. we needto work out if we are freeing or allocation + * blocks first, then we can do the modification as necessary. + * + * We do this under the XFS_SB_LOCK so that if we are near + * ENOSPC, we will hold out any changes while we work out + * what to do. This means that the amount of free space can + * change while we do this, so we need to retry if we end up + * trying to reserve more space than is available. + * + * We also use the xfs_mod_incore_sb() interface so that we + * don't have to care about whether per cpu counter are + * enabled, disabled or even compiled in.... + */ +retry: s = XFS_SB_LOCK(mp); + xfs_icsb_sync_counters_flags(mp, XFS_ICSB_SB_LOCKED); /* * If our previous reservation was larger than the current value, * then move any unused blocks back to the free pool. */ - + fdblks_delta = 0; if (mp->m_resblks > request) { lcounter = mp->m_resblks_avail - request; if (lcounter > 0) { /* release unused blocks */ - mp->m_sb.sb_fdblocks += lcounter; + fdblks_delta = lcounter; mp->m_resblks_avail -= lcounter; } mp->m_resblks = request; @@ -522,24 +538,50 @@ xfs_reserve_blocks( __int64_t free; free = mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); + if (!free) + goto out; /* ENOSPC and fdblks_delta = 0 */ + delta = request - mp->m_resblks; lcounter = free - delta; if (lcounter < 0) { /* We can't satisfy the request, just get what we can */ mp->m_resblks += free; mp->m_resblks_avail += free; + fdblks_delta = -free; mp->m_sb.sb_fdblocks = XFS_ALLOC_SET_ASIDE(mp); } else { + fdblks_delta = -delta; mp->m_sb.sb_fdblocks = lcounter + XFS_ALLOC_SET_ASIDE(mp); mp->m_resblks = request; mp->m_resblks_avail += delta; } } - +out: outval->resblks = mp->m_resblks; outval->resblks_avail = mp->m_resblks_avail; XFS_SB_UNLOCK(mp, s); + + if (fdblks_delta) { + /* + * If we are putting blocks back here, m_resblks_avail is + * already at it's max so this will put it in the free pool. + * + * If we need space, we'll either succeed in getting it + * from the free block count or we'll get an enospc. If + * we get a ENOSPC, it means things changed while we were + * calculating fdblks_delta and so we should try again to + * see if there is anything left to reserve. + * + * Don't set the reserved flag here - we don't want to reserve + * the extra reserve blocks from the reserve..... + */ + int error; + error = xfs_mod_incore_sb(mp, XFS_SBS_FDBLOCKS, fdblks_delta, 0); + if (error == ENOSPC) + goto retry; + } + return 0; } diff --git a/fs/xfs/xfs_ialloc.c b/fs/xfs/xfs_ialloc.c index a446e5a115c..b5feb3e7711 100644 --- a/fs/xfs/xfs_ialloc.c +++ b/fs/xfs/xfs_ialloc.c @@ -342,7 +342,7 @@ xfs_ialloc_ag_alloc( return 0; } -STATIC __inline xfs_agnumber_t +STATIC_INLINE xfs_agnumber_t xfs_ialloc_next_ag( xfs_mount_t *mp) { diff --git a/fs/xfs/xfs_ialloc_btree.h b/fs/xfs/xfs_ialloc_btree.h index 2c0e49893ff..bf8e9aff272 100644 --- a/fs/xfs/xfs_ialloc_btree.h +++ b/fs/xfs/xfs_ialloc_btree.h @@ -89,7 +89,6 @@ typedef struct xfs_btree_sblock xfs_inobt_block_t; /* * Real block structures have a size equal to the disk block size. */ -#define XFS_INOBT_BLOCK_SIZE(lev,cur) (1 << (cur)->bc_blocklog) #define XFS_INOBT_BLOCK_MAXRECS(lev,cur) ((cur)->bc_mp->m_inobt_mxr[lev != 0]) #define XFS_INOBT_BLOCK_MINRECS(lev,cur) ((cur)->bc_mp->m_inobt_mnr[lev != 0]) #define XFS_INOBT_IS_LAST_REC(cur) \ @@ -110,14 +109,13 @@ typedef struct xfs_btree_sblock xfs_inobt_block_t; * Record, key, and pointer address macros for btree blocks. */ #define XFS_INOBT_REC_ADDR(bb,i,cur) \ - (XFS_BTREE_REC_ADDR(XFS_INOBT_BLOCK_SIZE(0,cur), xfs_inobt, bb, \ - i, XFS_INOBT_BLOCK_MAXRECS(0, cur))) + (XFS_BTREE_REC_ADDR(xfs_inobt, bb, i)) + #define XFS_INOBT_KEY_ADDR(bb,i,cur) \ - (XFS_BTREE_KEY_ADDR(XFS_INOBT_BLOCK_SIZE(1,cur), xfs_inobt, bb, \ - i, XFS_INOBT_BLOCK_MAXRECS(1, cur))) + (XFS_BTREE_KEY_ADDR(xfs_inobt, bb, i)) #define XFS_INOBT_PTR_ADDR(bb,i,cur) \ - (XFS_BTREE_PTR_ADDR(XFS_INOBT_BLOCK_SIZE(1,cur), xfs_inobt, bb, \ + (XFS_BTREE_PTR_ADDR(xfs_inobt, bb, \ i, XFS_INOBT_BLOCK_MAXRECS(1, cur))) /* diff --git a/fs/xfs/xfs_inode.c b/fs/xfs/xfs_inode.c index 44dfac52128..3da9829c19d 100644 --- a/fs/xfs/xfs_inode.c +++ b/fs/xfs/xfs_inode.c @@ -47,7 +47,6 @@ #include "xfs_utils.h" #include "xfs_dir2_trace.h" #include "xfs_quota.h" -#include "xfs_mac.h" #include "xfs_acl.h" @@ -1699,8 +1698,7 @@ xfs_itruncate_finish( * Duplicate the transaction that has the permanent * reservation and commit the old transaction. */ - error = xfs_bmap_finish(tp, &free_list, first_block, - &committed); + error = xfs_bmap_finish(tp, &free_list, &committed); ntp = *tp; if (error) { /* @@ -1810,7 +1808,7 @@ xfs_igrow_start( * and any blocks between the old and new file sizes. */ error = xfs_zero_eof(XFS_ITOV(ip), &ip->i_iocore, new_size, - ip->i_d.di_size, new_size); + ip->i_d.di_size); return error; } @@ -2125,7 +2123,7 @@ xfs_iunlink_remove( return 0; } -static __inline__ int xfs_inode_clean(xfs_inode_t *ip) +STATIC_INLINE int xfs_inode_clean(xfs_inode_t *ip) { return (((ip->i_itemp == NULL) || !(ip->i_itemp->ili_format.ilf_fields & XFS_ILOG_ALL)) && @@ -2707,10 +2705,24 @@ xfs_idestroy( ktrace_free(ip->i_dir_trace); #endif if (ip->i_itemp) { - /* XXXdpd should be able to assert this but shutdown - * is leaving the AIL behind. */ - ASSERT(((ip->i_itemp->ili_item.li_flags & XFS_LI_IN_AIL) == 0) || - XFS_FORCED_SHUTDOWN(ip->i_mount)); + /* + * Only if we are shutting down the fs will we see an + * inode still in the AIL. If it is there, we should remove + * it to prevent a use-after-free from occurring. + */ + xfs_mount_t *mp = ip->i_mount; + xfs_log_item_t *lip = &ip->i_itemp->ili_item; + int s; + + ASSERT(((lip->li_flags & XFS_LI_IN_AIL) == 0) || + XFS_FORCED_SHUTDOWN(ip->i_mount)); + if (lip->li_flags & XFS_LI_IN_AIL) { + AIL_LOCK(mp, s); + if (lip->li_flags & XFS_LI_IN_AIL) + xfs_trans_delete_ail(mp, lip, s); + else + AIL_UNLOCK(mp, s); + } xfs_inode_item_destroy(ip); } kmem_zone_free(xfs_inode_zone, ip); diff --git a/fs/xfs/xfs_inode_item.c b/fs/xfs/xfs_inode_item.c index a7a92251eb5..565d470a6b4 100644 --- a/fs/xfs/xfs_inode_item.c +++ b/fs/xfs/xfs_inode_item.c @@ -887,7 +887,7 @@ xfs_inode_item_committing( /* * This is the ops vector shared by all buf log items. */ -STATIC struct xfs_item_ops xfs_inode_item_ops = { +static struct xfs_item_ops xfs_inode_item_ops = { .iop_size = (uint(*)(xfs_log_item_t*))xfs_inode_item_size, .iop_format = (void(*)(xfs_log_item_t*, xfs_log_iovec_t*)) xfs_inode_item_format, diff --git a/fs/xfs/xfs_iomap.c b/fs/xfs/xfs_iomap.c index 19655124da7..cc6a7b5a991 100644 --- a/fs/xfs/xfs_iomap.c +++ b/fs/xfs/xfs_iomap.c @@ -43,8 +43,6 @@ #include "xfs_itable.h" #include "xfs_rw.h" #include "xfs_acl.h" -#include "xfs_cap.h" -#include "xfs_mac.h" #include "xfs_attr.h" #include "xfs_buf_item.h" #include "xfs_trans_space.h" @@ -542,7 +540,7 @@ xfs_iomap_write_direct( /* * Complete the transaction */ - error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed); + error = xfs_bmap_finish(&tp, &free_list, &committed); if (error) goto error0; error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); @@ -838,8 +836,7 @@ xfs_iomap_write_allocate( if (error) goto trans_cancel; - error = xfs_bmap_finish(&tp, &free_list, - first_block, &committed); + error = xfs_bmap_finish(&tp, &free_list, &committed); if (error) goto trans_cancel; @@ -947,8 +944,7 @@ xfs_iomap_write_unwritten( if (error) goto error_on_bmapi_transaction; - error = xfs_bmap_finish(&(tp), &(free_list), - firstfsb, &committed); + error = xfs_bmap_finish(&(tp), &(free_list), &committed); if (error) goto error_on_bmapi_transaction; diff --git a/fs/xfs/xfs_log_recover.c b/fs/xfs/xfs_log_recover.c index 3cb678e3a13..ca74d3f5910 100644 --- a/fs/xfs/xfs_log_recover.c +++ b/fs/xfs/xfs_log_recover.c @@ -1514,7 +1514,6 @@ xlog_recover_reorder_trans( { xlog_recover_item_t *first_item, *itemq, *itemq_next; xfs_buf_log_format_t *buf_f; - xfs_buf_log_format_v1_t *obuf_f; ushort flags = 0; first_item = itemq = trans->r_itemq; @@ -1522,29 +1521,16 @@ xlog_recover_reorder_trans( do { itemq_next = itemq->ri_next; buf_f = (xfs_buf_log_format_t *)itemq->ri_buf[0].i_addr; - switch (ITEM_TYPE(itemq)) { - case XFS_LI_BUF: - flags = buf_f->blf_flags; - break; - case XFS_LI_6_1_BUF: - case XFS_LI_5_3_BUF: - obuf_f = (xfs_buf_log_format_v1_t*)buf_f; - flags = obuf_f->blf_flags; - break; - } switch (ITEM_TYPE(itemq)) { case XFS_LI_BUF: - case XFS_LI_6_1_BUF: - case XFS_LI_5_3_BUF: + flags = buf_f->blf_flags; if (!(flags & XFS_BLI_CANCEL)) { xlog_recover_insert_item_frontq(&trans->r_itemq, itemq); break; } case XFS_LI_INODE: - case XFS_LI_6_1_INODE: - case XFS_LI_5_3_INODE: case XFS_LI_DQUOT: case XFS_LI_QUOTAOFF: case XFS_LI_EFD: @@ -1583,7 +1569,6 @@ xlog_recover_do_buffer_pass1( xfs_buf_cancel_t *nextp; xfs_buf_cancel_t *prevp; xfs_buf_cancel_t **bucket; - xfs_buf_log_format_v1_t *obuf_f; xfs_daddr_t blkno = 0; uint len = 0; ushort flags = 0; @@ -1594,13 +1579,6 @@ xlog_recover_do_buffer_pass1( len = buf_f->blf_len; flags = buf_f->blf_flags; break; - case XFS_LI_6_1_BUF: - case XFS_LI_5_3_BUF: - obuf_f = (xfs_buf_log_format_v1_t*)buf_f; - blkno = (xfs_daddr_t) obuf_f->blf_blkno; - len = obuf_f->blf_len; - flags = obuf_f->blf_flags; - break; } /* @@ -1746,7 +1724,6 @@ xlog_recover_do_buffer_pass2( xlog_t *log, xfs_buf_log_format_t *buf_f) { - xfs_buf_log_format_v1_t *obuf_f; xfs_daddr_t blkno = 0; ushort flags = 0; uint len = 0; @@ -1757,13 +1734,6 @@ xlog_recover_do_buffer_pass2( flags = buf_f->blf_flags; len = buf_f->blf_len; break; - case XFS_LI_6_1_BUF: - case XFS_LI_5_3_BUF: - obuf_f = (xfs_buf_log_format_v1_t*)buf_f; - blkno = (xfs_daddr_t) obuf_f->blf_blkno; - flags = obuf_f->blf_flags; - len = (xfs_daddr_t) obuf_f->blf_len; - break; } return xlog_check_buffer_cancelled(log, blkno, len, flags); @@ -1799,7 +1769,6 @@ xlog_recover_do_inode_buffer( int inodes_per_buf; xfs_agino_t *logged_nextp; xfs_agino_t *buffer_nextp; - xfs_buf_log_format_v1_t *obuf_f; unsigned int *data_map = NULL; unsigned int map_size = 0; @@ -1808,12 +1777,6 @@ xlog_recover_do_inode_buffer( data_map = buf_f->blf_data_map; map_size = buf_f->blf_map_size; break; - case XFS_LI_6_1_BUF: - case XFS_LI_5_3_BUF: - obuf_f = (xfs_buf_log_format_v1_t*)buf_f; - data_map = obuf_f->blf_data_map; - map_size = obuf_f->blf_map_size; - break; } /* * Set the variables corresponding to the current region to @@ -1912,7 +1875,6 @@ xlog_recover_do_reg_buffer( int i; int bit; int nbits; - xfs_buf_log_format_v1_t *obuf_f; unsigned int *data_map = NULL; unsigned int map_size = 0; int error; @@ -1922,12 +1884,6 @@ xlog_recover_do_reg_buffer( data_map = buf_f->blf_data_map; map_size = buf_f->blf_map_size; break; - case XFS_LI_6_1_BUF: - case XFS_LI_5_3_BUF: - obuf_f = (xfs_buf_log_format_v1_t*)buf_f; - data_map = obuf_f->blf_data_map; - map_size = obuf_f->blf_map_size; - break; } bit = 0; i = 1; /* 0 is the buf format structure */ @@ -2160,7 +2116,6 @@ xlog_recover_do_buffer_trans( int pass) { xfs_buf_log_format_t *buf_f; - xfs_buf_log_format_v1_t *obuf_f; xfs_mount_t *mp; xfs_buf_t *bp; int error; @@ -2197,13 +2152,6 @@ xlog_recover_do_buffer_trans( len = buf_f->blf_len; flags = buf_f->blf_flags; break; - case XFS_LI_6_1_BUF: - case XFS_LI_5_3_BUF: - obuf_f = (xfs_buf_log_format_v1_t*)buf_f; - blkno = obuf_f->blf_blkno; - len = obuf_f->blf_len; - flags = obuf_f->blf_flags; - break; default: xfs_fs_cmn_err(CE_ALERT, log->l_mp, "xfs_log_recover: unknown buffer type 0x%x, logdev %s", @@ -2830,9 +2778,7 @@ xlog_recover_do_trans( * where xfs_daddr_t is 32-bits but mount will warn us * off a > 1 TB filesystem before we get here. */ - if ((ITEM_TYPE(item) == XFS_LI_BUF) || - (ITEM_TYPE(item) == XFS_LI_6_1_BUF) || - (ITEM_TYPE(item) == XFS_LI_5_3_BUF)) { + if ((ITEM_TYPE(item) == XFS_LI_BUF)) { if ((error = xlog_recover_do_buffer_trans(log, item, pass))) break; @@ -3902,6 +3848,9 @@ xlog_do_recover( ASSERT(XFS_SB_GOOD_VERSION(sbp)); xfs_buf_relse(bp); + /* We've re-read the superblock so re-initialize per-cpu counters */ + xfs_icsb_reinit_counters(log->l_mp); + xlog_recover_check_summary(log); /* Normal transactions can now occur */ diff --git a/fs/xfs/xfs_mac.h b/fs/xfs/xfs_mac.h deleted file mode 100644 index 18e0e98e03d..00000000000 --- a/fs/xfs/xfs_mac.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright (c) 2001-2002,2005 Silicon Graphics, Inc. - * All Rights Reserved. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it would be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA - */ -#ifndef __XFS_MAC_H__ -#define __XFS_MAC_H__ - -/* - * Mandatory Access Control - * - * Layout of a composite MAC label: - * ml_list contains the list of categories (MSEN) followed by the list of - * divisions (MINT). This is actually a header for the data structure which - * will have an ml_list with more than one element. - * - * ------------------------------- - * | ml_msen_type | ml_mint_type | - * ------------------------------- - * | ml_level | ml_grade | - * ------------------------------- - * | ml_catcount | - * ------------------------------- - * | ml_divcount | - * ------------------------------- - * | category 1 | - * | . . . | - * | category N | (where N = ml_catcount) - * ------------------------------- - * | division 1 | - * | . . . | - * | division M | (where M = ml_divcount) - * ------------------------------- - */ -#define XFS_MAC_MAX_SETS 250 -typedef struct xfs_mac_label { - __uint8_t ml_msen_type; /* MSEN label type */ - __uint8_t ml_mint_type; /* MINT label type */ - __uint8_t ml_level; /* Hierarchical level */ - __uint8_t ml_grade; /* Hierarchical grade */ - __uint16_t ml_catcount; /* Category count */ - __uint16_t ml_divcount; /* Division count */ - /* Category set, then Division set */ - __uint16_t ml_list[XFS_MAC_MAX_SETS]; -} xfs_mac_label_t; - -/* MSEN label type names. Choose an upper case ASCII character. */ -#define XFS_MSEN_ADMIN_LABEL 'A' /* Admin: low<admin != tcsec<high */ -#define XFS_MSEN_EQUAL_LABEL 'E' /* Wildcard - always equal */ -#define XFS_MSEN_HIGH_LABEL 'H' /* System High - always dominates */ -#define XFS_MSEN_MLD_HIGH_LABEL 'I' /* System High, multi-level dir */ -#define XFS_MSEN_LOW_LABEL 'L' /* System Low - always dominated */ -#define XFS_MSEN_MLD_LABEL 'M' /* TCSEC label on a multi-level dir */ -#define XFS_MSEN_MLD_LOW_LABEL 'N' /* System Low, multi-level dir */ -#define XFS_MSEN_TCSEC_LABEL 'T' /* TCSEC label */ -#define XFS_MSEN_UNKNOWN_LABEL 'U' /* unknown label */ - -/* MINT label type names. Choose a lower case ASCII character. */ -#define XFS_MINT_BIBA_LABEL 'b' /* Dual of a TCSEC label */ -#define XFS_MINT_EQUAL_LABEL 'e' /* Wildcard - always equal */ -#define XFS_MINT_HIGH_LABEL 'h' /* High Grade - always dominates */ -#define XFS_MINT_LOW_LABEL 'l' /* Low Grade - always dominated */ - -/* On-disk XFS extended attribute names */ -#define SGI_MAC_FILE "SGI_MAC_FILE" -#define SGI_MAC_FILE_SIZE (sizeof(SGI_MAC_FILE)-1) - - -#ifdef __KERNEL__ - -#ifdef CONFIG_FS_POSIX_MAC - -/* NOT YET IMPLEMENTED */ - -#define MACEXEC 00100 -#define MACWRITE 00200 -#define MACREAD 00400 - -struct xfs_inode; -extern int xfs_mac_iaccess(struct xfs_inode *, mode_t, cred_t *); - -#define _MAC_XFS_IACCESS(i,m,c) (xfs_mac_iaccess(i,m,c)) -#define _MAC_VACCESS(v,c,m) (xfs_mac_vaccess(v,c,m)) -#define _MAC_EXISTS xfs_mac_vhaslabel - -#else -#define _MAC_XFS_IACCESS(i,m,c) (0) -#define _MAC_VACCESS(v,c,m) (0) -#define _MAC_EXISTS (NULL) -#endif - -#endif /* __KERNEL__ */ - -#endif /* __XFS_MAC_H__ */ diff --git a/fs/xfs/xfs_mount.c b/fs/xfs/xfs_mount.c index 9dfae18d995..3bed0cf0d8a 100644 --- a/fs/xfs/xfs_mount.c +++ b/fs/xfs/xfs_mount.c @@ -52,21 +52,19 @@ STATIC void xfs_unmountfs_wait(xfs_mount_t *); #ifdef HAVE_PERCPU_SB STATIC void xfs_icsb_destroy_counters(xfs_mount_t *); -STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t, int); +STATIC void xfs_icsb_balance_counter(xfs_mount_t *, xfs_sb_field_t, + int, int); STATIC void xfs_icsb_sync_counters(xfs_mount_t *); STATIC int xfs_icsb_modify_counters(xfs_mount_t *, xfs_sb_field_t, - int, int); -STATIC int xfs_icsb_modify_counters_locked(xfs_mount_t *, xfs_sb_field_t, - int, int); + int64_t, int); STATIC int xfs_icsb_disable_counter(xfs_mount_t *, xfs_sb_field_t); #else #define xfs_icsb_destroy_counters(mp) do { } while (0) -#define xfs_icsb_balance_counter(mp, a, b) do { } while (0) +#define xfs_icsb_balance_counter(mp, a, b, c) do { } while (0) #define xfs_icsb_sync_counters(mp) do { } while (0) #define xfs_icsb_modify_counters(mp, a, b, c) do { } while (0) -#define xfs_icsb_modify_counters_locked(mp, a, b, c) do { } while (0) #endif @@ -545,9 +543,8 @@ xfs_readsb(xfs_mount_t *mp, int flags) ASSERT(XFS_BUF_VALUSEMA(bp) <= 0); } - xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0); - xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0); - xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0); + /* Initialize per-cpu counters */ + xfs_icsb_reinit_counters(mp); mp->m_sb_bp = bp; xfs_buf_relse(bp); @@ -1254,8 +1251,11 @@ xfs_mod_sb(xfs_trans_t *tp, __int64_t fields) * The SB_LOCK must be held when this routine is called. */ int -xfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field, - int delta, int rsvd) +xfs_mod_incore_sb_unlocked( + xfs_mount_t *mp, + xfs_sb_field_t field, + int64_t delta, + int rsvd) { int scounter; /* short counter for 32 bit fields */ long long lcounter; /* long counter for 64 bit fields */ @@ -1287,7 +1287,6 @@ xfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field, mp->m_sb.sb_ifree = lcounter; return 0; case XFS_SBS_FDBLOCKS: - lcounter = (long long) mp->m_sb.sb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); res_used = (long long)(mp->m_resblks - mp->m_resblks_avail); @@ -1418,7 +1417,11 @@ xfs_mod_incore_sb_unlocked(xfs_mount_t *mp, xfs_sb_field_t field, * routine to do the work. */ int -xfs_mod_incore_sb(xfs_mount_t *mp, xfs_sb_field_t field, int delta, int rsvd) +xfs_mod_incore_sb( + xfs_mount_t *mp, + xfs_sb_field_t field, + int64_t delta, + int rsvd) { unsigned long s; int status; @@ -1485,9 +1488,11 @@ xfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd) case XFS_SBS_IFREE: case XFS_SBS_FDBLOCKS: if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) { - status = xfs_icsb_modify_counters_locked(mp, + XFS_SB_UNLOCK(mp, s); + status = xfs_icsb_modify_counters(mp, msbp->msb_field, msbp->msb_delta, rsvd); + s = XFS_SB_LOCK(mp); break; } /* FALLTHROUGH */ @@ -1521,11 +1526,12 @@ xfs_mod_incore_sb_batch(xfs_mount_t *mp, xfs_mod_sb_t *msb, uint nmsb, int rsvd) case XFS_SBS_IFREE: case XFS_SBS_FDBLOCKS: if (!(mp->m_flags & XFS_MOUNT_NO_PERCPU_SB)) { - status = - xfs_icsb_modify_counters_locked(mp, + XFS_SB_UNLOCK(mp, s); + status = xfs_icsb_modify_counters(mp, msbp->msb_field, -(msbp->msb_delta), rsvd); + s = XFS_SB_LOCK(mp); break; } /* FALLTHROUGH */ @@ -1733,14 +1739,17 @@ xfs_icsb_cpu_notify( memset(cntp, 0, sizeof(xfs_icsb_cnts_t)); break; case CPU_ONLINE: - xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0); - xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0); - xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0); + xfs_icsb_lock(mp); + xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0, 0); + xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0, 0); + xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0, 0); + xfs_icsb_unlock(mp); break; case CPU_DEAD: /* Disable all the counters, then fold the dead cpu's * count into the total on the global superblock and * re-enable the counters. */ + xfs_icsb_lock(mp); s = XFS_SB_LOCK(mp); xfs_icsb_disable_counter(mp, XFS_SBS_ICOUNT); xfs_icsb_disable_counter(mp, XFS_SBS_IFREE); @@ -1752,10 +1761,14 @@ xfs_icsb_cpu_notify( memset(cntp, 0, sizeof(xfs_icsb_cnts_t)); - xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, XFS_ICSB_SB_LOCKED); - xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, XFS_ICSB_SB_LOCKED); - xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, XFS_ICSB_SB_LOCKED); + xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, + XFS_ICSB_SB_LOCKED, 0); + xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, + XFS_ICSB_SB_LOCKED, 0); + xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, + XFS_ICSB_SB_LOCKED, 0); XFS_SB_UNLOCK(mp, s); + xfs_icsb_unlock(mp); break; } @@ -1784,6 +1797,9 @@ xfs_icsb_init_counters( cntp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, i); memset(cntp, 0, sizeof(xfs_icsb_cnts_t)); } + + mutex_init(&mp->m_icsb_mutex); + /* * start with all counters disabled so that the * initial balance kicks us off correctly @@ -1792,6 +1808,22 @@ xfs_icsb_init_counters( return 0; } +void +xfs_icsb_reinit_counters( + xfs_mount_t *mp) +{ + xfs_icsb_lock(mp); + /* + * start with all counters disabled so that the + * initial balance kicks us off correctly + */ + mp->m_icsb_counters = -1; + xfs_icsb_balance_counter(mp, XFS_SBS_ICOUNT, 0, 0); + xfs_icsb_balance_counter(mp, XFS_SBS_IFREE, 0, 0); + xfs_icsb_balance_counter(mp, XFS_SBS_FDBLOCKS, 0, 0); + xfs_icsb_unlock(mp); +} + STATIC void xfs_icsb_destroy_counters( xfs_mount_t *mp) @@ -1800,9 +1832,10 @@ xfs_icsb_destroy_counters( unregister_hotcpu_notifier(&mp->m_icsb_notifier); free_percpu(mp->m_sb_cnts); } + mutex_destroy(&mp->m_icsb_mutex); } -STATIC inline void +STATIC_INLINE void xfs_icsb_lock_cntr( xfs_icsb_cnts_t *icsbp) { @@ -1811,7 +1844,7 @@ xfs_icsb_lock_cntr( } } -STATIC inline void +STATIC_INLINE void xfs_icsb_unlock_cntr( xfs_icsb_cnts_t *icsbp) { @@ -1819,7 +1852,7 @@ xfs_icsb_unlock_cntr( } -STATIC inline void +STATIC_INLINE void xfs_icsb_lock_all_counters( xfs_mount_t *mp) { @@ -1832,7 +1865,7 @@ xfs_icsb_lock_all_counters( } } -STATIC inline void +STATIC_INLINE void xfs_icsb_unlock_all_counters( xfs_mount_t *mp) { @@ -1888,6 +1921,17 @@ xfs_icsb_disable_counter( ASSERT((field >= XFS_SBS_ICOUNT) && (field <= XFS_SBS_FDBLOCKS)); + /* + * If we are already disabled, then there is nothing to do + * here. We check before locking all the counters to avoid + * the expensive lock operation when being called in the + * slow path and the counter is already disabled. This is + * safe because the only time we set or clear this state is under + * the m_icsb_mutex. + */ + if (xfs_icsb_counter_disabled(mp, field)) + return 0; + xfs_icsb_lock_all_counters(mp); if (!test_and_set_bit(field, &mp->m_icsb_counters)) { /* drain back to superblock */ @@ -1948,8 +1992,8 @@ xfs_icsb_enable_counter( xfs_icsb_unlock_all_counters(mp); } -STATIC void -xfs_icsb_sync_counters_int( +void +xfs_icsb_sync_counters_flags( xfs_mount_t *mp, int flags) { @@ -1981,40 +2025,39 @@ STATIC void xfs_icsb_sync_counters( xfs_mount_t *mp) { - xfs_icsb_sync_counters_int(mp, 0); -} - -/* - * lazy addition used for things like df, background sb syncs, etc - */ -void -xfs_icsb_sync_counters_lazy( - xfs_mount_t *mp) -{ - xfs_icsb_sync_counters_int(mp, XFS_ICSB_LAZY_COUNT); + xfs_icsb_sync_counters_flags(mp, 0); } /* * Balance and enable/disable counters as necessary. * - * Thresholds for re-enabling counters are somewhat magic. - * inode counts are chosen to be the same number as single - * on disk allocation chunk per CPU, and free blocks is - * something far enough zero that we aren't going thrash - * when we get near ENOSPC. + * Thresholds for re-enabling counters are somewhat magic. inode counts are + * chosen to be the same number as single on disk allocation chunk per CPU, and + * free blocks is something far enough zero that we aren't going thrash when we + * get near ENOSPC. We also need to supply a minimum we require per cpu to + * prevent looping endlessly when xfs_alloc_space asks for more than will + * be distributed to a single CPU but each CPU has enough blocks to be + * reenabled. + * + * Note that we can be called when counters are already disabled. + * xfs_icsb_disable_counter() optimises the counter locking in this case to + * prevent locking every per-cpu counter needlessly. */ -#define XFS_ICSB_INO_CNTR_REENABLE 64 + +#define XFS_ICSB_INO_CNTR_REENABLE (uint64_t)64 #define XFS_ICSB_FDBLK_CNTR_REENABLE(mp) \ - (512 + XFS_ALLOC_SET_ASIDE(mp)) + (uint64_t)(512 + XFS_ALLOC_SET_ASIDE(mp)) STATIC void xfs_icsb_balance_counter( xfs_mount_t *mp, xfs_sb_field_t field, - int flags) + int flags, + int min_per_cpu) { uint64_t count, resid; int weight = num_online_cpus(); int s; + uint64_t min = (uint64_t)min_per_cpu; if (!(flags & XFS_ICSB_SB_LOCKED)) s = XFS_SB_LOCK(mp); @@ -2027,19 +2070,19 @@ xfs_icsb_balance_counter( case XFS_SBS_ICOUNT: count = mp->m_sb.sb_icount; resid = do_div(count, weight); - if (count < XFS_ICSB_INO_CNTR_REENABLE) + if (count < max(min, XFS_ICSB_INO_CNTR_REENABLE)) goto out; break; case XFS_SBS_IFREE: count = mp->m_sb.sb_ifree; resid = do_div(count, weight); - if (count < XFS_ICSB_INO_CNTR_REENABLE) + if (count < max(min, XFS_ICSB_INO_CNTR_REENABLE)) goto out; break; case XFS_SBS_FDBLOCKS: count = mp->m_sb.sb_fdblocks; resid = do_div(count, weight); - if (count < XFS_ICSB_FDBLK_CNTR_REENABLE(mp)) + if (count < max(min, XFS_ICSB_FDBLK_CNTR_REENABLE(mp))) goto out; break; default: @@ -2054,32 +2097,39 @@ out: XFS_SB_UNLOCK(mp, s); } -STATIC int -xfs_icsb_modify_counters_int( +int +xfs_icsb_modify_counters( xfs_mount_t *mp, xfs_sb_field_t field, - int delta, - int rsvd, - int flags) + int64_t delta, + int rsvd) { xfs_icsb_cnts_t *icsbp; long long lcounter; /* long counter for 64 bit fields */ - int cpu, s, locked = 0; - int ret = 0, balance_done = 0; + int cpu, ret = 0, s; + might_sleep(); again: cpu = get_cpu(); - icsbp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, cpu), - xfs_icsb_lock_cntr(icsbp); + icsbp = (xfs_icsb_cnts_t *)per_cpu_ptr(mp->m_sb_cnts, cpu); + + /* + * if the counter is disabled, go to slow path + */ if (unlikely(xfs_icsb_counter_disabled(mp, field))) goto slow_path; + xfs_icsb_lock_cntr(icsbp); + if (unlikely(xfs_icsb_counter_disabled(mp, field))) { + xfs_icsb_unlock_cntr(icsbp); + goto slow_path; + } switch (field) { case XFS_SBS_ICOUNT: lcounter = icsbp->icsb_icount; lcounter += delta; if (unlikely(lcounter < 0)) - goto slow_path; + goto balance_counter; icsbp->icsb_icount = lcounter; break; @@ -2087,7 +2137,7 @@ again: lcounter = icsbp->icsb_ifree; lcounter += delta; if (unlikely(lcounter < 0)) - goto slow_path; + goto balance_counter; icsbp->icsb_ifree = lcounter; break; @@ -2097,7 +2147,7 @@ again: lcounter = icsbp->icsb_fdblocks - XFS_ALLOC_SET_ASIDE(mp); lcounter += delta; if (unlikely(lcounter < 0)) - goto slow_path; + goto balance_counter; icsbp->icsb_fdblocks = lcounter + XFS_ALLOC_SET_ASIDE(mp); break; default: @@ -2106,72 +2156,78 @@ again: } xfs_icsb_unlock_cntr(icsbp); put_cpu(); - if (locked) - XFS_SB_UNLOCK(mp, s); return 0; - /* - * The slow path needs to be run with the SBLOCK - * held so that we prevent other threads from - * attempting to run this path at the same time. - * this provides exclusion for the balancing code, - * and exclusive fallback if the balance does not - * provide enough resources to continue in an unlocked - * manner. - */ slow_path: - xfs_icsb_unlock_cntr(icsbp); put_cpu(); - /* need to hold superblock incase we need - * to disable a counter */ - if (!(flags & XFS_ICSB_SB_LOCKED)) { - s = XFS_SB_LOCK(mp); - locked = 1; - flags |= XFS_ICSB_SB_LOCKED; - } - if (!balance_done) { - xfs_icsb_balance_counter(mp, field, flags); - balance_done = 1; + /* + * serialise with a mutex so we don't burn lots of cpu on + * the superblock lock. We still need to hold the superblock + * lock, however, when we modify the global structures. + */ + xfs_icsb_lock(mp); + + /* + * Now running atomically. + * + * If the counter is enabled, someone has beaten us to rebalancing. + * Drop the lock and try again in the fast path.... + */ + if (!(xfs_icsb_counter_disabled(mp, field))) { + xfs_icsb_unlock(mp); goto again; - } else { - /* - * we might not have enough on this local - * cpu to allocate for a bulk request. - * We need to drain this field from all CPUs - * and disable the counter fastpath - */ - xfs_icsb_disable_counter(mp, field); } + /* + * The counter is currently disabled. Because we are + * running atomically here, we know a rebalance cannot + * be in progress. Hence we can go straight to operating + * on the global superblock. We do not call xfs_mod_incore_sb() + * here even though we need to get the SB_LOCK. Doing so + * will cause us to re-enter this function and deadlock. + * Hence we get the SB_LOCK ourselves and then call + * xfs_mod_incore_sb_unlocked() as the unlocked path operates + * directly on the global counters. + */ + s = XFS_SB_LOCK(mp); ret = xfs_mod_incore_sb_unlocked(mp, field, delta, rsvd); + XFS_SB_UNLOCK(mp, s); - if (locked) - XFS_SB_UNLOCK(mp, s); + /* + * Now that we've modified the global superblock, we + * may be able to re-enable the distributed counters + * (e.g. lots of space just got freed). After that + * we are done. + */ + if (ret != ENOSPC) + xfs_icsb_balance_counter(mp, field, 0, 0); + xfs_icsb_unlock(mp); return ret; -} -STATIC int -xfs_icsb_modify_counters( - xfs_mount_t *mp, - xfs_sb_field_t field, - int delta, - int rsvd) -{ - return xfs_icsb_modify_counters_int(mp, field, delta, rsvd, 0); -} +balance_counter: + xfs_icsb_unlock_cntr(icsbp); + put_cpu(); -/* - * Called when superblock is already locked - */ -STATIC int -xfs_icsb_modify_counters_locked( - xfs_mount_t *mp, - xfs_sb_field_t field, - int delta, - int rsvd) -{ - return xfs_icsb_modify_counters_int(mp, field, delta, - rsvd, XFS_ICSB_SB_LOCKED); + /* + * We may have multiple threads here if multiple per-cpu + * counters run dry at the same time. This will mean we can + * do more balances than strictly necessary but it is not + * the common slowpath case. + */ + xfs_icsb_lock(mp); + + /* + * running atomically. + * + * This will leave the counter in the correct state for future + * accesses. After the rebalance, we simply try again and our retry + * will either succeed through the fast path or slow path without + * another balance operation being required. + */ + xfs_icsb_balance_counter(mp, field, 0, delta); + xfs_icsb_unlock(mp); + goto again; } + #endif diff --git a/fs/xfs/xfs_mount.h b/fs/xfs/xfs_mount.h index e5f396ff9a3..82304b94646 100644 --- a/fs/xfs/xfs_mount.h +++ b/fs/xfs/xfs_mount.h @@ -18,6 +18,7 @@ #ifndef __XFS_MOUNT_H__ #define __XFS_MOUNT_H__ + typedef struct xfs_trans_reservations { uint tr_write; /* extent alloc trans */ uint tr_itruncate; /* truncate trans */ @@ -306,11 +307,13 @@ typedef struct xfs_icsb_cnts { #define XFS_ICSB_LAZY_COUNT (1 << 1) /* accuracy not needed */ extern int xfs_icsb_init_counters(struct xfs_mount *); -extern void xfs_icsb_sync_counters_lazy(struct xfs_mount *); +extern void xfs_icsb_reinit_counters(struct xfs_mount *); +extern void xfs_icsb_sync_counters_flags(struct xfs_mount *, int); #else #define xfs_icsb_init_counters(mp) (0) -#define xfs_icsb_sync_counters_lazy(mp) do { } while (0) +#define xfs_icsb_reinit_counters(mp) do { } while (0) +#define xfs_icsb_sync_counters_flags(mp, flags) do { } while (0) #endif typedef struct xfs_mount { @@ -419,6 +422,7 @@ typedef struct xfs_mount { xfs_icsb_cnts_t *m_sb_cnts; /* per-cpu superblock counters */ unsigned long m_icsb_counters; /* disabled per-cpu counters */ struct notifier_block m_icsb_notifier; /* hotplug cpu notifier */ + struct mutex m_icsb_mutex; /* balancer sync lock */ #endif } xfs_mount_t; @@ -563,11 +567,32 @@ xfs_daddr_to_agbno(struct xfs_mount *mp, xfs_daddr_t d) } /* + * Per-cpu superblock locking functions + */ +#ifdef HAVE_PERCPU_SB +STATIC_INLINE void +xfs_icsb_lock(xfs_mount_t *mp) +{ + mutex_lock(&mp->m_icsb_mutex); +} + +STATIC_INLINE void +xfs_icsb_unlock(xfs_mount_t *mp) +{ + mutex_unlock(&mp->m_icsb_mutex); +} +#else +#define xfs_icsb_lock(mp) +#define xfs_icsb_unlock(mp) +#endif + +/* * This structure is for use by the xfs_mod_incore_sb_batch() routine. + * xfs_growfs can specify a few fields which are more than int limit */ typedef struct xfs_mod_sb { xfs_sb_field_t msb_field; /* Field to modify, see below */ - int msb_delta; /* Change to make to specified field */ + int64_t msb_delta; /* Change to make to specified field */ } xfs_mod_sb_t; #define XFS_MOUNT_ILOCK(mp) mutex_lock(&((mp)->m_ilock)) @@ -585,17 +610,17 @@ extern int xfs_unmountfs(xfs_mount_t *, struct cred *); extern void xfs_unmountfs_close(xfs_mount_t *, struct cred *); extern int xfs_unmountfs_writesb(xfs_mount_t *); extern int xfs_unmount_flush(xfs_mount_t *, int); -extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int, int); +extern int xfs_mod_incore_sb(xfs_mount_t *, xfs_sb_field_t, int64_t, int); extern int xfs_mod_incore_sb_unlocked(xfs_mount_t *, xfs_sb_field_t, - int, int); + int64_t, int); extern int xfs_mod_incore_sb_batch(xfs_mount_t *, xfs_mod_sb_t *, uint, int); extern struct xfs_buf *xfs_getsb(xfs_mount_t *, int); extern int xfs_readsb(xfs_mount_t *, int); extern void xfs_freesb(xfs_mount_t *); extern void xfs_do_force_shutdown(bhv_desc_t *, int, char *, int); -extern int xfs_syncsub(xfs_mount_t *, int, int, int *); -extern int xfs_sync_inodes(xfs_mount_t *, int, int, int *); +extern int xfs_syncsub(xfs_mount_t *, int, int *); +extern int xfs_sync_inodes(xfs_mount_t *, int, int *); extern xfs_agnumber_t xfs_initialize_perag(struct bhv_vfs *, xfs_mount_t *, xfs_agnumber_t); extern void xfs_xlatesb(void *, struct xfs_sb *, int, __int64_t); diff --git a/fs/xfs/xfs_rename.c b/fs/xfs/xfs_rename.c index d98171deaa1..4c6573d784c 100644 --- a/fs/xfs/xfs_rename.c +++ b/fs/xfs/xfs_rename.c @@ -565,7 +565,7 @@ xfs_rename( IHOLD(target_ip); IHOLD(src_ip); - error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); + error = xfs_bmap_finish(&tp, &free_list, &committed); if (error) { xfs_bmap_cancel(&free_list); xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | diff --git a/fs/xfs/xfs_rtalloc.c b/fs/xfs/xfs_rtalloc.c index 880c73271c0..6fff19dc3cf 100644 --- a/fs/xfs/xfs_rtalloc.c +++ b/fs/xfs/xfs_rtalloc.c @@ -147,7 +147,7 @@ xfs_growfs_rt_alloc( /* * Free any blocks freed up in the transaction, then commit. */ - error = xfs_bmap_finish(&tp, &flist, firstblock, &committed); + error = xfs_bmap_finish(&tp, &flist, &committed); if (error) goto error_exit; xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); @@ -913,57 +913,6 @@ xfs_rtcheck_alloc_range( } #endif -#ifdef DEBUG -/* - * Check whether the given block in the bitmap has the given value. - */ -STATIC int /* 1 for matches, 0 for not */ -xfs_rtcheck_bit( - xfs_mount_t *mp, /* file system mount structure */ - xfs_trans_t *tp, /* transaction pointer */ - xfs_rtblock_t start, /* bit (block) to check */ - int val) /* 1 for free, 0 for allocated */ -{ - int bit; /* bit number in the word */ - xfs_rtblock_t block; /* bitmap block number */ - xfs_buf_t *bp; /* buf for the block */ - xfs_rtword_t *bufp; /* pointer into the buffer */ - /* REFERENCED */ - int error; /* error value */ - xfs_rtword_t wdiff; /* difference between bit & expected */ - int word; /* word number in the buffer */ - xfs_rtword_t wval; /* word value from buffer */ - - block = XFS_BITTOBLOCK(mp, start); - error = xfs_rtbuf_get(mp, tp, block, 0, &bp); - bufp = (xfs_rtword_t *)XFS_BUF_PTR(bp); - word = XFS_BITTOWORD(mp, start); - bit = (int)(start & (XFS_NBWORD - 1)); - wval = bufp[word]; - xfs_trans_brelse(tp, bp); - wdiff = (wval ^ -val) & ((xfs_rtword_t)1 << bit); - return !wdiff; -} -#endif /* DEBUG */ - -#if 0 -/* - * Check that the given extent (block range) is free already. - */ -STATIC int /* error */ -xfs_rtcheck_free_range( - xfs_mount_t *mp, /* file system mount point */ - xfs_trans_t *tp, /* transaction pointer */ - xfs_rtblock_t bno, /* starting block number of extent */ - xfs_extlen_t len, /* length of extent */ - int *stat) /* out: 1 for free, 0 for not */ -{ - xfs_rtblock_t new; /* dummy for xfs_rtcheck_range */ - - return xfs_rtcheck_range(mp, tp, bno, len, 1, &new, stat); -} -#endif - /* * Check that the given range is either all allocated (val = 0) or * all free (val = 1). @@ -2382,60 +2331,3 @@ xfs_rtpick_extent( *pick = b; return 0; } - -#ifdef DEBUG -/* - * Debug code: print out the value of a range in the bitmap. - */ -void -xfs_rtprint_range( - xfs_mount_t *mp, /* file system mount structure */ - xfs_trans_t *tp, /* transaction pointer */ - xfs_rtblock_t start, /* starting block to print */ - xfs_extlen_t len) /* length to print */ -{ - xfs_extlen_t i; /* block number in the extent */ - - cmn_err(CE_DEBUG, "%Ld: ", (long long)start); - for (i = 0; i < len; i++) - cmn_err(CE_DEBUG, "%d", xfs_rtcheck_bit(mp, tp, start + i, 1)); - cmn_err(CE_DEBUG, "\n"); -} - -/* - * Debug code: print the summary file. - */ -void -xfs_rtprint_summary( - xfs_mount_t *mp, /* file system mount structure */ - xfs_trans_t *tp) /* transaction pointer */ -{ - xfs_suminfo_t c; /* summary data */ - xfs_rtblock_t i; /* bitmap block number */ - int l; /* summary information level */ - int p; /* flag for printed anything */ - xfs_fsblock_t sb; /* summary block number */ - xfs_buf_t *sumbp; /* summary block buffer */ - - sumbp = NULL; - for (l = 0; l < mp->m_rsumlevels; l++) { - for (p = 0, i = 0; i < mp->m_sb.sb_rbmblocks; i++) { - (void)xfs_rtget_summary(mp, tp, l, i, &sumbp, &sb, &c); - if (c) { - if (!p) { - cmn_err(CE_DEBUG, "%Ld-%Ld:", 1LL << l, - XFS_RTMIN((1LL << l) + - ((1LL << l) - 1LL), - mp->m_sb.sb_rextents)); - p = 1; - } - cmn_err(CE_DEBUG, " %Ld:%d", (long long)i, c); - } - } - if (p) - cmn_err(CE_DEBUG, "\n"); - } - if (sumbp) - xfs_trans_brelse(tp, sumbp); -} -#endif /* DEBUG */ diff --git a/fs/xfs/xfs_rtalloc.h b/fs/xfs/xfs_rtalloc.h index 0e0b4d2ec20..799c1f87126 100644 --- a/fs/xfs/xfs_rtalloc.h +++ b/fs/xfs/xfs_rtalloc.h @@ -134,24 +134,6 @@ xfs_rtpick_extent( xfs_rtblock_t *pick); /* result rt extent */ /* - * Debug code: print out the value of a range in the bitmap. - */ -void -xfs_rtprint_range( - struct xfs_mount *mp, /* file system mount structure */ - struct xfs_trans *tp, /* transaction pointer */ - xfs_rtblock_t start, /* starting block to print */ - xfs_extlen_t len); /* length to print */ - -/* - * Debug code: print the summary file. - */ -void -xfs_rtprint_summary( - struct xfs_mount *mp, /* file system mount structure */ - struct xfs_trans *tp); /* transaction pointer */ - -/* * Grow the realtime area of the filesystem. */ int diff --git a/fs/xfs/xfs_rw.c b/fs/xfs/xfs_rw.c index defb2febaaf..1ea7c0ca6ae 100644 --- a/fs/xfs/xfs_rw.c +++ b/fs/xfs/xfs_rw.c @@ -42,7 +42,6 @@ #include "xfs_attr.h" #include "xfs_bmap.h" #include "xfs_acl.h" -#include "xfs_mac.h" #include "xfs_error.h" #include "xfs_buf_item.h" #include "xfs_rw.h" diff --git a/fs/xfs/xfs_trans.c b/fs/xfs/xfs_trans.c index ee2721e0de4..301ff9445b6 100644 --- a/fs/xfs/xfs_trans.c +++ b/fs/xfs/xfs_trans.c @@ -339,7 +339,7 @@ xfs_trans_reserve( */ if (blocks > 0) { error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS, - -blocks, rsvd); + -((int64_t)blocks), rsvd); if (error != 0) { current_restore_flags_nested(&tp->t_pflags, PF_FSTRANS); return (XFS_ERROR(ENOSPC)); @@ -380,7 +380,7 @@ xfs_trans_reserve( */ if (rtextents > 0) { error = xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FREXTENTS, - -rtextents, rsvd); + -((int64_t)rtextents), rsvd); if (error) { error = XFS_ERROR(ENOSPC); goto undo_log; @@ -410,7 +410,7 @@ undo_log: undo_blocks: if (blocks > 0) { (void) xfs_mod_incore_sb(tp->t_mountp, XFS_SBS_FDBLOCKS, - blocks, rsvd); + (int64_t)blocks, rsvd); tp->t_blk_res = 0; } @@ -432,7 +432,7 @@ void xfs_trans_mod_sb( xfs_trans_t *tp, uint field, - long delta) + int64_t delta) { switch (field) { @@ -663,62 +663,62 @@ xfs_trans_unreserve_and_mod_sb( if (tp->t_flags & XFS_TRANS_SB_DIRTY) { if (tp->t_icount_delta != 0) { msbp->msb_field = XFS_SBS_ICOUNT; - msbp->msb_delta = (int)tp->t_icount_delta; + msbp->msb_delta = tp->t_icount_delta; msbp++; } if (tp->t_ifree_delta != 0) { msbp->msb_field = XFS_SBS_IFREE; - msbp->msb_delta = (int)tp->t_ifree_delta; + msbp->msb_delta = tp->t_ifree_delta; msbp++; } if (tp->t_fdblocks_delta != 0) { msbp->msb_field = XFS_SBS_FDBLOCKS; - msbp->msb_delta = (int)tp->t_fdblocks_delta; + msbp->msb_delta = tp->t_fdblocks_delta; msbp++; } if (tp->t_frextents_delta != 0) { msbp->msb_field = XFS_SBS_FREXTENTS; - msbp->msb_delta = (int)tp->t_frextents_delta; + msbp->msb_delta = tp->t_frextents_delta; msbp++; } if (tp->t_dblocks_delta != 0) { msbp->msb_field = XFS_SBS_DBLOCKS; - msbp->msb_delta = (int)tp->t_dblocks_delta; + msbp->msb_delta = tp->t_dblocks_delta; msbp++; } if (tp->t_agcount_delta != 0) { msbp->msb_field = XFS_SBS_AGCOUNT; - msbp->msb_delta = (int)tp->t_agcount_delta; + msbp->msb_delta = tp->t_agcount_delta; msbp++; } if (tp->t_imaxpct_delta != 0) { msbp->msb_field = XFS_SBS_IMAX_PCT; - msbp->msb_delta = (int)tp->t_imaxpct_delta; + msbp->msb_delta = tp->t_imaxpct_delta; msbp++; } if (tp->t_rextsize_delta != 0) { msbp->msb_field = XFS_SBS_REXTSIZE; - msbp->msb_delta = (int)tp->t_rextsize_delta; + msbp->msb_delta = tp->t_rextsize_delta; msbp++; } if (tp->t_rbmblocks_delta != 0) { msbp->msb_field = XFS_SBS_RBMBLOCKS; - msbp->msb_delta = (int)tp->t_rbmblocks_delta; + msbp->msb_delta = tp->t_rbmblocks_delta; msbp++; } if (tp->t_rblocks_delta != 0) { msbp->msb_field = XFS_SBS_RBLOCKS; - msbp->msb_delta = (int)tp->t_rblocks_delta; + msbp->msb_delta = tp->t_rblocks_delta; msbp++; } if (tp->t_rextents_delta != 0) { msbp->msb_field = XFS_SBS_REXTENTS; - msbp->msb_delta = (int)tp->t_rextents_delta; + msbp->msb_delta = tp->t_rextents_delta; msbp++; } if (tp->t_rextslog_delta != 0) { msbp->msb_field = XFS_SBS_REXTSLOG; - msbp->msb_delta = (int)tp->t_rextslog_delta; + msbp->msb_delta = tp->t_rextslog_delta; msbp++; } } diff --git a/fs/xfs/xfs_trans.h b/fs/xfs/xfs_trans.h index c68e00105d2..f1d7ab23672 100644 --- a/fs/xfs/xfs_trans.h +++ b/fs/xfs/xfs_trans.h @@ -39,13 +39,9 @@ typedef struct xfs_trans_header { /* * Log item types. */ -#define XFS_LI_5_3_BUF 0x1234 /* v1 bufs, 1-block inode buffers */ -#define XFS_LI_5_3_INODE 0x1235 /* 1-block inode buffers */ #define XFS_LI_EFI 0x1236 #define XFS_LI_EFD 0x1237 #define XFS_LI_IUNLINK 0x1238 -#define XFS_LI_6_1_INODE 0x1239 /* 4K non-aligned inode bufs */ -#define XFS_LI_6_1_BUF 0x123a /* v1, 4K inode buffers */ #define XFS_LI_INODE 0x123b /* aligned ino chunks, var-size ibufs */ #define XFS_LI_BUF 0x123c /* v2 bufs, variable sized inode bufs */ #define XFS_LI_DQUOT 0x123d @@ -354,25 +350,25 @@ typedef struct xfs_trans { xfs_trans_callback_t t_callback; /* transaction callback */ void *t_callarg; /* callback arg */ unsigned int t_flags; /* misc flags */ - long t_icount_delta; /* superblock icount change */ - long t_ifree_delta; /* superblock ifree change */ - long t_fdblocks_delta; /* superblock fdblocks chg */ - long t_res_fdblocks_delta; /* on-disk only chg */ - long t_frextents_delta;/* superblock freextents chg*/ - long t_res_frextents_delta; /* on-disk only chg */ + int64_t t_icount_delta; /* superblock icount change */ + int64_t t_ifree_delta; /* superblock ifree change */ + int64_t t_fdblocks_delta; /* superblock fdblocks chg */ + int64_t t_res_fdblocks_delta; /* on-disk only chg */ + int64_t t_frextents_delta;/* superblock freextents chg*/ + int64_t t_res_frextents_delta; /* on-disk only chg */ #ifdef DEBUG - long t_ag_freeblks_delta; /* debugging counter */ - long t_ag_flist_delta; /* debugging counter */ - long t_ag_btree_delta; /* debugging counter */ + int64_t t_ag_freeblks_delta; /* debugging counter */ + int64_t t_ag_flist_delta; /* debugging counter */ + int64_t t_ag_btree_delta; /* debugging counter */ #endif - long t_dblocks_delta;/* superblock dblocks change */ - long t_agcount_delta;/* superblock agcount change */ - long t_imaxpct_delta;/* superblock imaxpct change */ - long t_rextsize_delta;/* superblock rextsize chg */ - long t_rbmblocks_delta;/* superblock rbmblocks chg */ - long t_rblocks_delta;/* superblock rblocks change */ - long t_rextents_delta;/* superblocks rextents chg */ - long t_rextslog_delta;/* superblocks rextslog chg */ + int64_t t_dblocks_delta;/* superblock dblocks change */ + int64_t t_agcount_delta;/* superblock agcount change */ + int64_t t_imaxpct_delta;/* superblock imaxpct change */ + int64_t t_rextsize_delta;/* superblock rextsize chg */ + int64_t t_rbmblocks_delta;/* superblock rbmblocks chg */ + int64_t t_rblocks_delta;/* superblock rblocks change */ + int64_t t_rextents_delta;/* superblocks rextents chg */ + int64_t t_rextslog_delta;/* superblocks rextslog chg */ unsigned int t_items_free; /* log item descs free */ xfs_log_item_chunk_t t_items; /* first log item desc chunk */ xfs_trans_header_t t_header; /* header for in-log trans */ @@ -936,9 +932,9 @@ typedef struct xfs_trans { #define xfs_trans_set_sync(tp) ((tp)->t_flags |= XFS_TRANS_SYNC) #ifdef DEBUG -#define xfs_trans_agblocks_delta(tp, d) ((tp)->t_ag_freeblks_delta += (long)d) -#define xfs_trans_agflist_delta(tp, d) ((tp)->t_ag_flist_delta += (long)d) -#define xfs_trans_agbtree_delta(tp, d) ((tp)->t_ag_btree_delta += (long)d) +#define xfs_trans_agblocks_delta(tp, d) ((tp)->t_ag_freeblks_delta += (int64_t)d) +#define xfs_trans_agflist_delta(tp, d) ((tp)->t_ag_flist_delta += (int64_t)d) +#define xfs_trans_agbtree_delta(tp, d) ((tp)->t_ag_btree_delta += (int64_t)d) #else #define xfs_trans_agblocks_delta(tp, d) #define xfs_trans_agflist_delta(tp, d) @@ -954,7 +950,7 @@ xfs_trans_t *_xfs_trans_alloc(struct xfs_mount *, uint); xfs_trans_t *xfs_trans_dup(xfs_trans_t *); int xfs_trans_reserve(xfs_trans_t *, uint, uint, uint, uint, uint); -void xfs_trans_mod_sb(xfs_trans_t *, uint, long); +void xfs_trans_mod_sb(xfs_trans_t *, uint, int64_t); struct xfs_buf *xfs_trans_get_buf(xfs_trans_t *, struct xfs_buftarg *, xfs_daddr_t, int, uint); int xfs_trans_read_buf(struct xfs_mount *, xfs_trans_t *, diff --git a/fs/xfs/xfs_trans_ail.c b/fs/xfs/xfs_trans_ail.c index fc39b166d40..ceb4f6e9996 100644 --- a/fs/xfs/xfs_trans_ail.c +++ b/fs/xfs/xfs_trans_ail.c @@ -90,7 +90,7 @@ xfs_trans_push_ail( int flush_log; SPLDECL(s); -#define XFS_TRANS_PUSH_AIL_RESTARTS 10 +#define XFS_TRANS_PUSH_AIL_RESTARTS 1000 AIL_LOCK(mp,s); lip = xfs_trans_first_ail(mp, &gen); diff --git a/fs/xfs/xfs_vfsops.c b/fs/xfs/xfs_vfsops.c index 62336a4cc5a..29f72f61378 100644 --- a/fs/xfs/xfs_vfsops.c +++ b/fs/xfs/xfs_vfsops.c @@ -640,7 +640,7 @@ xfs_quiesce_fs( * we can write the unmount record. */ do { - xfs_syncsub(mp, SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT, 0, NULL); + xfs_syncsub(mp, SYNC_REMOUNT|SYNC_ATTR|SYNC_WAIT, NULL); pincount = xfs_flush_buftarg(mp->m_ddev_targp, 1); if (!pincount) { delay(50); @@ -806,7 +806,7 @@ xfs_statvfs( statp->f_type = XFS_SB_MAGIC; - xfs_icsb_sync_counters_lazy(mp); + xfs_icsb_sync_counters_flags(mp, XFS_ICSB_LAZY_COUNT); s = XFS_SB_LOCK(mp); statp->f_bsize = sbp->sb_blocksize; lsize = sbp->sb_logstart ? sbp->sb_logblocks : 0; @@ -872,6 +872,10 @@ xfs_statvfs( * this by simply making sure the log gets flushed * if SYNC_BDFLUSH is set, and by actually writing it * out otherwise. + * SYNC_IOWAIT - The caller wants us to wait for all data I/O to complete + * before we return (including direct I/O). Forms the drain + * side of the write barrier needed to safely quiesce the + * filesystem. * */ /*ARGSUSED*/ @@ -883,27 +887,20 @@ xfs_sync( { xfs_mount_t *mp = XFS_BHVTOM(bdp); - if (unlikely(flags == SYNC_QUIESCE)) - return xfs_quiesce_fs(mp); - else - return xfs_syncsub(mp, flags, 0, NULL); + return xfs_syncsub(mp, flags, NULL); } /* * xfs sync routine for internal use * * This routine supports all of the flags defined for the generic vfs_sync - * interface as explained above under xfs_sync. In the interests of not - * changing interfaces within the 6.5 family, additional internally- - * required functions are specified within a separate xflags parameter, - * only available by calling this routine. + * interface as explained above under xfs_sync. * */ int xfs_sync_inodes( xfs_mount_t *mp, int flags, - int xflags, int *bypassed) { xfs_inode_t *ip = NULL; @@ -1176,6 +1173,13 @@ xfs_sync_inodes( } } + /* + * When freezing, we need to wait ensure all I/O (including direct + * I/O) is complete to ensure no further data modification can take + * place after this point + */ + if (flags & SYNC_IOWAIT) + vn_iowait(vp); if (flags & SYNC_BDFLUSH) { if ((flags & SYNC_ATTR) && @@ -1412,17 +1416,13 @@ xfs_sync_inodes( * xfs sync routine for internal use * * This routine supports all of the flags defined for the generic vfs_sync - * interface as explained above under xfs_sync. In the interests of not - * changing interfaces within the 6.5 family, additional internally- - * required functions are specified within a separate xflags parameter, - * only available by calling this routine. + * interface as explained above under xfs_sync. * */ int xfs_syncsub( xfs_mount_t *mp, int flags, - int xflags, int *bypassed) { int error = 0; @@ -1444,7 +1444,7 @@ xfs_syncsub( if (flags & SYNC_BDFLUSH) xfs_finish_reclaim_all(mp, 1); else - error = xfs_sync_inodes(mp, flags, xflags, bypassed); + error = xfs_sync_inodes(mp, flags, bypassed); } /* @@ -1958,15 +1958,26 @@ xfs_showargs( return 0; } +/* + * Second stage of a freeze. The data is already frozen, now we have to take + * care of the metadata. New transactions are already blocked, so we need to + * wait for any remaining transactions to drain out before proceding. + */ STATIC void xfs_freeze( bhv_desc_t *bdp) { xfs_mount_t *mp = XFS_BHVTOM(bdp); + /* wait for all modifications to complete */ while (atomic_read(&mp->m_active_trans) > 0) delay(100); + /* flush inodes and push all remaining buffers out to disk */ + xfs_quiesce_fs(mp); + + ASSERT_ALWAYS(atomic_read(&mp->m_active_trans) == 0); + /* Push the superblock and write an unmount record */ xfs_log_unmount_write(mp); xfs_unmountfs_writesb(mp); diff --git a/fs/xfs/xfs_vnodeops.c b/fs/xfs/xfs_vnodeops.c index bda774a04b8..52c41714ec5 100644 --- a/fs/xfs/xfs_vnodeops.c +++ b/fs/xfs/xfs_vnodeops.c @@ -51,7 +51,6 @@ #include "xfs_refcache.h" #include "xfs_trans_space.h" #include "xfs_log_priv.h" -#include "xfs_mac.h" STATIC int xfs_open( @@ -1381,7 +1380,7 @@ xfs_inactive_symlink_rmt( /* * Commit the first transaction. This logs the EFI and the inode. */ - if ((error = xfs_bmap_finish(&tp, &free_list, first_block, &committed))) + if ((error = xfs_bmap_finish(&tp, &free_list, &committed))) goto error1; /* * The transaction must have been committed, since there were @@ -1790,8 +1789,7 @@ xfs_inactive( * Just ignore errors at this point. There is * nothing we can do except to try to keep going. */ - (void) xfs_bmap_finish(&tp, &free_list, first_block, - &committed); + (void) xfs_bmap_finish(&tp, &free_list, &committed); (void) xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL); } /* @@ -2022,7 +2020,7 @@ xfs_create( IHOLD(ip); vp = XFS_ITOV(ip); - error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); + error = xfs_bmap_finish(&tp, &free_list, &committed); if (error) { xfs_bmap_cancel(&free_list); goto abort_rele; @@ -2507,7 +2505,7 @@ xfs_remove( xfs_trans_set_sync(tp); } - error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); + error = xfs_bmap_finish(&tp, &free_list, &committed); if (error) { REMOVE_DEBUG_TRACE(__LINE__); goto error_rele; @@ -2715,7 +2713,7 @@ xfs_link( xfs_trans_set_sync(tp); } - error = xfs_bmap_finish (&tp, &free_list, first_block, &committed); + error = xfs_bmap_finish (&tp, &free_list, &committed); if (error) { xfs_bmap_cancel(&free_list); goto abort_return; @@ -2932,7 +2930,7 @@ xfs_mkdir( xfs_trans_set_sync(tp); } - error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); + error = xfs_bmap_finish(&tp, &free_list, &committed); if (error) { IRELE(cdp); goto error2; @@ -3183,7 +3181,7 @@ xfs_rmdir( xfs_trans_set_sync(tp); } - error = xfs_bmap_finish (&tp, &free_list, first_block, &committed); + error = xfs_bmap_finish (&tp, &free_list, &committed); if (error) { xfs_bmap_cancel(&free_list); xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES | @@ -3533,7 +3531,7 @@ xfs_symlink( */ IHOLD(ip); - error = xfs_bmap_finish(&tp, &free_list, first_block, &committed); + error = xfs_bmap_finish(&tp, &free_list, &committed); if (error) { goto error2; } @@ -4145,7 +4143,7 @@ retry: /* * Complete the transaction */ - error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed); + error = xfs_bmap_finish(&tp, &free_list, &committed); if (error) { goto error0; } @@ -4452,7 +4450,7 @@ xfs_free_file_space( /* * complete the transaction */ - error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed); + error = xfs_bmap_finish(&tp, &free_list, &committed); if (error) { goto error0; } |