GIT d0cfa0bdce7e095c0cb684cf46e4829cf7490718 git+ssh://master.kernel.org/pub/scm/linux/kernel/git/mfasheh/ocfs2.git#ALL commit 978fa098e5c0c5cc0b70423ce6a200e0647a1ea7 Author: Tiger Yang Date: Mon Nov 27 09:59:21 2006 +0800 ocfs2: implement i_op->permission Implement .permission() in ocfs2_file_iops, ocfs2_special_file_iops and ocfs2_dir_iops. This helps us avoid some multi-node races with mode change and vfs operations. Signed-off-by: Tiger Yang Signed-off-by: Mark Fasheh commit 55f78b3f161901becd22b1f3905d3202ff9f8723 Author: Adrian Bunk Date: Mon Nov 20 03:24:28 2006 +0100 [2.6 patch] make ocfs2_create_new_lock() static This patch makes the needlessly global ocfs2_create_new_lock() static. Signed-off-by: Adrian Bunk Signed-off-by: Mark Fasheh commit 823373ea9350b7edf4542c57d8de1fed83f0297e Author: Adrian Bunk Date: Mon Nov 20 03:24:00 2006 +0100 configfs: make configfs_dirent_exists() static This patch makes the needlessly global configfs_dirent_exists() static. Signed-off-by: Adrian Bunk Signed-off-by: Joel Becker commit 58025587325855791865b1b879416d65e1ca7df4 Author: Tiger Yang Date: Wed Nov 15 15:49:02 2006 +0800 ocfs2: update file system paths to set atime Conditionally update atime in ocfs2_file_aio_read(), ocfs2_readdir() and ocfs2_mmap(). Signed-off-by: Tiger Yang Signed-off-by: Mark Fasheh commit f095676d130f3b397f3b3f59a03ecad606eaa57c Author: Tiger Yang Date: Wed Nov 15 15:48:42 2006 +0800 ocfs2: core atime update functions This patch adds the core routines for updating atime in ocfs2. Signed-off-by: Tiger Yang Signed-off-by: Mark Fasheh commit 2baf43aef484ea431cbd4afd7b7d994841ca3329 Author: Randy.Dunlap Date: Mon Oct 23 15:01:55 2006 -0700 [patch] ocfs2: fix printk warning Fix printk format warning: build1.out:fs/ocfs2/dlm/dlmdomain.c:70: warning: long unsigned int format, different type arg (arg 7) Signed-off-by: Randy Dunlap Signed-off-by: Mark Fasheh commit 9861ae0bbb9267a4634511ab9d346114f1076d95 Author: Tiger Yang Date: Tue Oct 17 18:29:52 2006 -0700 ocfs2: Add splice support Add splice read/write support in ocfs2. ocfs2_file_splice_read/write are very similar to ocfs2_file_aio_read/write. Signed-off-by: Tiger Yang Signed-off-by: Mark Fasheh commit 181d22e5e5e16ab5ac76dd3fce9a46eba0920091 Author: Mark Fasheh Date: Tue Oct 17 17:06:53 2006 -0700 ocfs2: Remove ocfs2_write_should_remove_suid() Use should_remove_suid() instead. Signed-off-by: Mark Fasheh commit 3c93d5fc630116c3ee474897b6cf0cd6f503c06c Author: Mark Fasheh Date: Tue Oct 17 17:05:18 2006 -0700 [PATCH] Export should_remove_suid() This helps us avoid replicating the same logic within file system drivers. Signed-off-by: Mark Fasheh commit 3bcc276af214fc384c059713f9b5ef7a55bdbfab Author: Mark Fasheh Date: Fri Oct 20 14:55:54 2006 -0700 configfs: mutex_lock_nested() fix configfs_unregister_subsystem() nests a pair of inode i_mutex acquisitions, and thus needs annotation via mutex_lock_nested(). Signed-off-by: Mark Fasheh commit 904abcf24caa9bd4c9183c1d23c52e7185f17f38 Author: Mark Fasheh Date: Mon Oct 9 18:11:45 2006 -0700 ocfs2: Remove struct ocfs2_journal_handle in favor of handle_t This is mostly a search and replace as ocfs2_journal_handle is now no more than a container for a handle_t pointer. ocfs2_commit_trans() becomes very straight forward, and we remove some out of date comments / code. Signed-off-by: Mark Fasheh commit 5fa7a0fc3d2dea4fd84cafceacbfb8e57ecd4521 Author: Mark Fasheh Date: Mon Oct 9 17:26:22 2006 -0700 ocfs2: remove handle argument to ocfs2_start_trans() All callers either pass in NULL directly, or a local variable that is already set to NULL. The internals of ocfs2_start_trans() get a nice cleanup as a result. Signed-off-by: Mark Fasheh commit df7701797bb51c3d20206cb2144a339a4c0acd79 Author: Mark Fasheh Date: Mon Oct 9 16:50:32 2006 -0700 ocfs2: remove ocfs2_journal_handle journal field It is no longer used. Signed-off-by: Mark Fasheh commit c78ec2a5e296f790bcbeae445771c52f1fa88c8b Author: Mark Fasheh Date: Mon Oct 9 16:48:10 2006 -0700 ocfs2: pass ocfs2_super * into ocfs2_commit_trans() This sets us up to remove handle->journal. Signed-off-by: Mark Fasheh commit 74ff071d918e2e4aea2abcd6ef6c842e3a6b9d68 Author: Mark Fasheh Date: Mon Oct 9 16:02:40 2006 -0700 ocfs2: remove unused handle argument from ocfs2_meta_lock_full() Now that this is unused and all callers pass NULL, we can safely remove it. Signed-off-by: Mark Fasheh commit 971cb1831ea030b9dee558a66bb5177ccbebd214 Author: Mark Fasheh Date: Fri Oct 6 19:07:43 2006 -0700 ocfs2: make ocfs2_alloc_handle() static This is no longer used outside of journal.c Signed-off-by: Mark Fasheh commit 5c3d17fbdecf472617115af5218c1f0b08a2cf04 Author: Mark Fasheh Date: Fri Oct 6 19:05:31 2006 -0700 ocfs2: remove unused ocfs2_handle_add_lock() This gets us rid of a slab we no longer need, as well as removing the majority of what's left on ocfs2_journal_handle. ocfs2_commit_unstarted_handle() has no more real work to do, so remove that function too. Signed-off-by: Mark Fasheh commit f2fb19f153cb871601e0590aad5566f78cc4fe05 Author: Mark Fasheh Date: Fri Oct 6 18:51:46 2006 -0700 ocfs2: remove unused ocfs2_handle_add_inode() We can also delete the unused infrastructure which was once in place to support this functionality. ocfs2_inode_private loses ip_handle and ip_handle_list. ocfs2_journal_handle loses handle_list. Signed-off-by: Mark Fasheh commit 485ba27751f242fbe91a39c6495aee2af8c50384 Author: Mark Fasheh Date: Fri Oct 6 18:40:41 2006 -0700 ocfs2: Don't allocate handle early in ocfs2_rename() It isn't used until ocfs2_start_trans() anyway. Signed-off-by: Mark Fasheh commit 5c9b1801b05bbb05acc4104373ad2f00d5d8fabd Author: Mark Fasheh Date: Fri Oct 6 18:34:35 2006 -0700 ocfs2: don't use handle for locking in allocation functions Instead we record our state on the allocation context structure which all callers already know about and lifetime correctly. This means the reservation functions don't need a handle passed in any more, and we can also take it off the alloc context. Signed-off-by: Mark Fasheh commit e47575895914402e1e72f00b3db539f468b849e3 Author: Joel Becker Date: Fri Oct 6 17:33:23 2006 -0700 configfs: accessing item hierarchy during rmdir(2) Add a notification callback, ops->disconnect_notify(). It has the same prototype as ->drop_item(), but it will be called just before the item linkage is broken. This way, configfs users who want to do work while the object is still in the heirarchy have a chance. Client drivers will still need to config_item_put() in their ->drop_item(), if they implement it. They need do nothing in ->disconnect_notify(). They don't have to provide it if they don't care. But someone who wants to be notified before ci_parent is set to NULL can now be notified. Signed-off-by: Joel Becker commit d6396b8fa714399c15c285914cebc2f513783f10 Author: Mark Fasheh Date: Fri Oct 6 15:04:51 2006 -0700 ocfs2: don't pass handle to ocfs2_meta_lock in ocfs2_rename() Take and drop the locks directly. Signed-off-by: Mark Fasheh commit 44bdda7e1b7d4d3fab32aeff63a161c591ffe315 Author: Mark Fasheh Date: Fri Oct 6 11:54:33 2006 -0700 ocfs2: don't pass handle to ocfs2_meta_lock in ocfs2_symlink() Take and drop the locks directly. Signed-off-by: Mark Fasheh commit b066f95bb813661bcdd23b096a319afa1bbccbce Author: Mark Fasheh Date: Fri Oct 6 11:49:45 2006 -0700 ocfs2: don't pass handle to ocfs2_meta_lock in ocfs2_unlink() Take and drop the locks directly. Signed-off-by: Mark Fasheh commit fafcfdd6582a8921ab7a6b02f885d96cd3c02cb7 Author: Mark Fasheh Date: Thu Oct 5 18:12:57 2006 -0700 ocfs2: don't pass handle to ocfs2_meta_lock() in orphan dir code Take and drop the locks directly. Signed-off-by: Mark Fasheh commit b6ecc7a43655031ddcc2fb52db3663b0481d7ad2 Author: Mark Fasheh Date: Thu Oct 5 16:48:23 2006 -0700 ocfs2: don't pass handle to ocfs2_meta_lock() in ocfs2_link() Take and drop the locks directly. Signed-off-by: Mark Fasheh commit 61a02a3684f0fa5c619f6af517124e67592140fa Author: Mark Fasheh Date: Thu Oct 5 16:04:17 2006 -0700 ocfs2: don't pass handle to ocfs2_meta_lock() in ocfs2_mknod() Take and drop the locks directly. Signed-off-by: Mark Fasheh commit 61ff1d34fc95bd78a082caf9f02f3b2399b6e512 Author: Mark Fasheh Date: Thu Oct 5 15:58:48 2006 -0700 ocfs2: don't pass handle to ocfs2_meta_lock() in __ocfs2_flush_truncate_log() Take and drop the locks directly. Signed-off-by: Mark Fasheh commit 20b168d7d4adb8bc973c0404a75c07f9ace0d3ea Author: Mark Fasheh Date: Thu Oct 5 15:42:08 2006 -0700 ocfs2: don't pass handle to ocfs2_meta_lock() in localalloc.c Take and drop the locks directly. Signed-off-by: Mark Fasheh commit c40b1e63d24a3adfe80f84fdace78a3319758504 Author: Mark Fasheh Date: Thu Oct 5 15:11:36 2006 -0700 ocfs2: remove ocfs2_journal_handle flags field Callers can set h_sync directly on the handle_t, whether a transaction has been started or not can be determined via the existence of the handle_t on the struct ocfs2_journal_handle. Signed-off-by: Mark Fasheh commit 50fff4821a565644fc9cd6bc9f99d17fba7c0187 Author: Mark Fasheh Date: Thu Oct 5 14:15:36 2006 -0700 ocfs2: have ocfs2_extend_trans() take handle_t No reason to use our wrapper struct in this function, so take the handle_t directly. Also fixes a bug where we were incorrectly setting the handle to NULL in case of a failure from journal_restart() Signed-off-by: Mark Fasheh commit a01ab1f012d76c55512689be118b4589637c4c69 Author: Mark Fasheh Date: Thu Oct 5 13:54:39 2006 -0700 ocfs2: remove unused ocfs2_journal_handle field max_buffs was just being set and not actually used. Signed-off-by: Mark Fasheh Documentation/filesystems/configfs/configfs.txt | 12 + fs/configfs/dir.c | 38 ++- fs/ocfs2/alloc.c | 90 +++--- fs/ocfs2/alloc.h | 2 fs/ocfs2/aops.c | 22 + fs/ocfs2/aops.h | 2 fs/ocfs2/dir.c | 33 +- fs/ocfs2/dir.h | 2 fs/ocfs2/dlm/dlmdomain.c | 2 fs/ocfs2/dlmglue.c | 60 +++- fs/ocfs2/dlmglue.h | 9 - fs/ocfs2/export.c | 2 fs/ocfs2/file.c | 343 ++++++++++++++++------- fs/ocfs2/file.h | 11 + fs/ocfs2/inode.c | 33 +- fs/ocfs2/inode.h | 9 - fs/ocfs2/ioctl.c | 10 - fs/ocfs2/journal.c | 274 ++---------------- fs/ocfs2/journal.h | 78 +---- fs/ocfs2/localalloc.c | 126 ++++---- fs/ocfs2/localalloc.h | 3 fs/ocfs2/mmap.c | 11 + fs/ocfs2/namei.c | 296 ++++++++++---------- fs/ocfs2/namei.h | 2 fs/ocfs2/ocfs2.h | 4 fs/ocfs2/suballoc.c | 174 +++++------- fs/ocfs2/suballoc.h | 16 - fs/ocfs2/super.c | 32 +- fs/ocfs2/symlink.c | 4 include/linux/configfs.h | 1 mm/filemap.c | 1 31 files changed, 803 insertions(+), 899 deletions(-) diff --git a/Documentation/filesystems/configfs/configfs.txt b/Documentation/filesystems/configfs/configfs.txt index c3a7afb..b0e94c8 100644 --- a/Documentation/filesystems/configfs/configfs.txt +++ b/Documentation/filesystems/configfs/configfs.txt @@ -238,6 +238,8 @@ config_item_type. struct config_group *(*make_group)(struct config_group *group, const char *name); int (*commit_item)(struct config_item *item); + void (*disconnect_notify)(struct config_group *group, + struct config_item *item); void (*drop_item)(struct config_group *group, struct config_item *item); }; @@ -268,6 +270,16 @@ the item in other threads, the memory is for the item to actually disappear from the subsystem's usage. But it is gone from configfs. +When drop_item() is called, the item's linkage has already been torn +down. It no longer has a reference on its parent and has no place in +the item hierarchy. If a client needs to do some cleanup before this +teardown happens, the subsystem can implement the +ct_group_ops->disconnect_notify() method. The method is called after +configfs has removed the item from the filesystem view but before the +item is removed from its parent group. Like drop_item(), +disconnect_notify() is void and cannot fail. Client subsystems should +not drop any references here, as they still must do it in drop_item(). + A config_group cannot be removed while it still has child items. This is implemented in the configfs rmdir(2) code. ->drop_item() will not be called, as the item has not been dropped. rmdir(2) will fail, as the diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c index 8a3b6a1..c09c454 100644 --- a/fs/configfs/dir.c +++ b/fs/configfs/dir.c @@ -93,8 +93,8 @@ static struct configfs_dirent *configfs_ * * called with parent inode's i_mutex held */ -int configfs_dirent_exists(struct configfs_dirent *parent_sd, - const unsigned char *new) +static int configfs_dirent_exists(struct configfs_dirent *parent_sd, + const unsigned char *new) { struct configfs_dirent * sd; @@ -715,6 +715,28 @@ static void configfs_detach_group(struct } /* + * After the item has been detached from the filesystem view, we are + * ready to tear it out of the hierarchy. Notify the client before + * we do that so they can perform any cleanup that requires + * navigating the hierarchy. A client does not need to provide this + * callback. The subsystem semaphore MUST be held by the caller, and + * references must be valid for both items. It also assumes the + * caller has validated ci_type. + */ +static void client_disconnect_notify(struct config_item *parent_item, + struct config_item *item) +{ + struct config_item_type *type; + + type = parent_item->ci_type; + BUG_ON(!type); + + if (type->ct_group_ops && type->ct_group_ops->disconnect_notify) + type->ct_group_ops->disconnect_notify(to_config_group(parent_item), + item); +} + +/* * Drop the initial reference from make_item()/make_group() * This function assumes that reference is held on item * and that item holds a valid reference to the parent. Also, it @@ -734,7 +756,7 @@ static void client_drop_item(struct conf */ if (type->ct_group_ops && type->ct_group_ops->drop_item) type->ct_group_ops->drop_item(to_config_group(parent_item), - item); + item); else config_item_put(item); } @@ -843,11 +865,14 @@ out_unlink: if (ret) { /* Tear down everything we built up */ down(&subsys->su_sem); + + client_disconnect_notify(parent_item, item); if (group) unlink_group(group); else unlink_obj(item); client_drop_item(parent_item, item); + up(&subsys->su_sem); if (module_got) @@ -912,11 +937,13 @@ static int configfs_rmdir(struct inode * configfs_detach_group(item); down(&subsys->su_sem); + client_disconnect_notify(parent_item, item); unlink_group(to_config_group(item)); } else { configfs_detach_item(item); down(&subsys->su_sem); + client_disconnect_notify(parent_item, item); unlink_obj(item); } @@ -1176,8 +1203,9 @@ void configfs_unregister_subsystem(struc return; } - mutex_lock(&configfs_sb->s_root->d_inode->i_mutex); - mutex_lock(&dentry->d_inode->i_mutex); + mutex_lock_nested(&configfs_sb->s_root->d_inode->i_mutex, + I_MUTEX_PARENT); + mutex_lock_nested(&dentry->d_inode->i_mutex, I_MUTEX_CHILD); if (configfs_detach_prep(dentry)) { printk(KERN_ERR "configfs: Tried to unregister non-empty subsystem!\n"); } diff --git a/fs/ocfs2/alloc.c b/fs/ocfs2/alloc.c index f43bc5f..85a048b 100644 --- a/fs/ocfs2/alloc.c +++ b/fs/ocfs2/alloc.c @@ -52,14 +52,14 @@ static int ocfs2_extent_contig(struct in u64 blkno); static int ocfs2_create_new_meta_bhs(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *inode, int wanted, struct ocfs2_alloc_context *meta_ac, struct buffer_head *bhs[]); static int ocfs2_add_branch(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *inode, struct buffer_head *fe_bh, struct buffer_head *eb_bh, @@ -67,14 +67,14 @@ static int ocfs2_add_branch(struct ocfs2 struct ocfs2_alloc_context *meta_ac); static int ocfs2_shift_tree_depth(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *inode, struct buffer_head *fe_bh, struct ocfs2_alloc_context *meta_ac, struct buffer_head **ret_new_eb_bh); static int ocfs2_do_insert_extent(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *inode, struct buffer_head *fe_bh, u64 blkno, @@ -152,7 +152,7 @@ bail: * l_count for you */ static int ocfs2_create_new_meta_bhs(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *inode, int wanted, struct ocfs2_alloc_context *meta_ac, @@ -253,7 +253,7 @@ bail: * contain a single record with e_clusters == 0. */ static int ocfs2_add_branch(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *inode, struct buffer_head *fe_bh, struct buffer_head *eb_bh, @@ -418,7 +418,7 @@ bail: * after this call. */ static int ocfs2_shift_tree_depth(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *inode, struct buffer_head *fe_bh, struct ocfs2_alloc_context *meta_ac, @@ -520,7 +520,7 @@ bail: * down. */ static int ocfs2_do_insert_extent(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *inode, struct buffer_head *fe_bh, u64 start_blk, @@ -809,7 +809,7 @@ bail: /* the caller needs to update fe->i_clusters */ int ocfs2_insert_extent(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *inode, struct buffer_head *fe_bh, u64 start_blk, @@ -951,7 +951,7 @@ static int ocfs2_truncate_log_can_coales } static int ocfs2_truncate_log_append(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, u64 start_blk, unsigned int num_clusters) { @@ -1034,7 +1034,7 @@ bail: } static int ocfs2_replay_truncate_records(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *data_alloc_inode, struct buffer_head *data_alloc_bh) { @@ -1113,7 +1113,7 @@ static int __ocfs2_flush_truncate_log(st { int status; unsigned int num_to_flush; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle; struct inode *tl_inode = osb->osb_tl_inode; struct inode *data_alloc_inode = NULL; struct buffer_head *tl_bh = osb->osb_tl_bh; @@ -1130,7 +1130,7 @@ static int __ocfs2_flush_truncate_log(st if (!OCFS2_IS_VALID_DINODE(di)) { OCFS2_RO_ON_INVALID_DINODE(osb->sb, di); status = -EIO; - goto bail; + goto out; } num_to_flush = le16_to_cpu(tl->tl_used); @@ -1138,14 +1138,7 @@ static int __ocfs2_flush_truncate_log(st num_to_flush, (unsigned long long)OCFS2_I(tl_inode)->ip_blkno); if (!num_to_flush) { status = 0; - goto bail; - } - - handle = ocfs2_alloc_handle(osb); - if (!handle) { - status = -ENOMEM; - mlog_errno(status); - goto bail; + goto out; } data_alloc_inode = ocfs2_get_system_file_inode(osb, @@ -1154,41 +1147,40 @@ static int __ocfs2_flush_truncate_log(st if (!data_alloc_inode) { status = -EINVAL; mlog(ML_ERROR, "Could not get bitmap inode!\n"); - goto bail; + goto out; } - ocfs2_handle_add_inode(handle, data_alloc_inode); - status = ocfs2_meta_lock(data_alloc_inode, handle, &data_alloc_bh, 1); + mutex_lock(&data_alloc_inode->i_mutex); + + status = ocfs2_meta_lock(data_alloc_inode, &data_alloc_bh, 1); if (status < 0) { mlog_errno(status); - goto bail; + goto out_mutex; } - handle = ocfs2_start_trans(osb, handle, OCFS2_TRUNCATE_LOG_UPDATE); + handle = ocfs2_start_trans(osb, OCFS2_TRUNCATE_LOG_UPDATE); if (IS_ERR(handle)) { status = PTR_ERR(handle); - handle = NULL; mlog_errno(status); - goto bail; + goto out_unlock; } status = ocfs2_replay_truncate_records(osb, handle, data_alloc_inode, data_alloc_bh); - if (status < 0) { + if (status < 0) mlog_errno(status); - goto bail; - } -bail: - if (handle) - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); - if (data_alloc_inode) - iput(data_alloc_inode); +out_unlock: + brelse(data_alloc_bh); + ocfs2_meta_unlock(data_alloc_inode, 1); - if (data_alloc_bh) - brelse(data_alloc_bh); +out_mutex: + mutex_unlock(&data_alloc_inode->i_mutex); + iput(data_alloc_inode); +out: mlog_exit(status); return status; } @@ -1347,7 +1339,7 @@ int ocfs2_complete_truncate_log_recovery int i; unsigned int clusters, num_recs, start_cluster; u64 start_blk; - struct ocfs2_journal_handle *handle; + handle_t *handle; struct inode *tl_inode = osb->osb_tl_inode; struct ocfs2_truncate_log *tl; @@ -1373,8 +1365,7 @@ int ocfs2_complete_truncate_log_recovery } } - handle = ocfs2_start_trans(osb, NULL, - OCFS2_TRUNCATE_LOG_UPDATE); + handle = ocfs2_start_trans(osb, OCFS2_TRUNCATE_LOG_UPDATE); if (IS_ERR(handle)) { status = PTR_ERR(handle); mlog_errno(status); @@ -1387,7 +1378,7 @@ int ocfs2_complete_truncate_log_recovery status = ocfs2_truncate_log_append(osb, handle, start_blk, clusters); - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); if (status < 0) { mlog_errno(status); goto bail_up; @@ -1543,7 +1534,7 @@ static int ocfs2_do_truncate(struct ocfs struct inode *inode, struct buffer_head *fe_bh, struct buffer_head *old_last_eb_bh, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct ocfs2_truncate_context *tc) { int status, i, depth; @@ -1782,7 +1773,7 @@ int ocfs2_commit_truncate(struct ocfs2_s struct ocfs2_extent_block *eb; struct ocfs2_extent_list *el; struct buffer_head *last_eb_bh; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; struct inode *tl_inode = osb->osb_tl_inode; mlog_entry_void(); @@ -1868,7 +1859,7 @@ start: credits = ocfs2_calc_tree_trunc_credits(osb->sb, clusters_to_del, fe, el); - handle = ocfs2_start_trans(osb, NULL, credits); + handle = ocfs2_start_trans(osb, credits); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; @@ -1891,7 +1882,7 @@ start: mutex_unlock(&tl_inode->i_mutex); tl_sem = 0; - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); handle = NULL; BUG_ON(le32_to_cpu(fe->i_clusters) < target_i_clusters); @@ -1906,7 +1897,7 @@ bail: mutex_unlock(&tl_inode->i_mutex); if (handle) - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); if (last_eb_bh) brelse(last_eb_bh); @@ -2011,10 +2002,7 @@ int ocfs2_prepare_truncate(struct ocfs2_ mutex_lock(&ext_alloc_inode->i_mutex); (*tc)->tc_ext_alloc_inode = ext_alloc_inode; - status = ocfs2_meta_lock(ext_alloc_inode, - NULL, - &ext_alloc_bh, - 1); + status = ocfs2_meta_lock(ext_alloc_inode, &ext_alloc_bh, 1); if (status < 0) { mlog_errno(status); goto bail; diff --git a/fs/ocfs2/alloc.h b/fs/ocfs2/alloc.h index 12ba897..0b82e80 100644 --- a/fs/ocfs2/alloc.h +++ b/fs/ocfs2/alloc.h @@ -28,7 +28,7 @@ #define OCFS2_ALLOC_H struct ocfs2_alloc_context; int ocfs2_insert_extent(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *inode, struct buffer_head *fe_bh, u64 blkno, diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c index 3d7c082..2f7268e 100644 --- a/fs/ocfs2/aops.c +++ b/fs/ocfs2/aops.c @@ -200,7 +200,7 @@ static int ocfs2_readpage(struct file *f mlog_entry("(0x%p, %lu)\n", file, (page ? page->index : 0)); - ret = ocfs2_meta_lock_with_page(inode, NULL, NULL, 0, page); + ret = ocfs2_meta_lock_with_page(inode, NULL, 0, page); if (ret != 0) { if (ret == AOP_TRUNCATED_PAGE) unlock = 0; @@ -305,7 +305,7 @@ static int ocfs2_prepare_write(struct fi mlog_entry("(0x%p, 0x%p, %u, %u)\n", file, page, from, to); - ret = ocfs2_meta_lock_with_page(inode, NULL, NULL, 0, page); + ret = ocfs2_meta_lock_with_page(inode, NULL, 0, page); if (ret != 0) { mlog_errno(ret); goto out; @@ -355,16 +355,16 @@ static int walk_page_buffers( handle_t * return ret; } -struct ocfs2_journal_handle *ocfs2_start_walk_page_trans(struct inode *inode, +handle_t *ocfs2_start_walk_page_trans(struct inode *inode, struct page *page, unsigned from, unsigned to) { struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; int ret = 0; - handle = ocfs2_start_trans(osb, NULL, OCFS2_INODE_UPDATE_CREDITS); + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); if (!handle) { ret = -ENOMEM; mlog_errno(ret); @@ -372,7 +372,7 @@ struct ocfs2_journal_handle *ocfs2_start } if (ocfs2_should_order_data(inode)) { - ret = walk_page_buffers(handle->k_handle, + ret = walk_page_buffers(handle, page_buffers(page), from, to, NULL, ocfs2_journal_dirty_data); @@ -382,7 +382,7 @@ struct ocfs2_journal_handle *ocfs2_start out: if (ret) { if (handle) - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); handle = ERR_PTR(ret); } return handle; @@ -394,7 +394,7 @@ static int ocfs2_commit_write(struct fil int ret; struct buffer_head *di_bh = NULL; struct inode *inode = page->mapping->host; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; struct ocfs2_dinode *di; mlog_entry("(0x%p, 0x%p, %u, %u)\n", file, page, from, to); @@ -412,7 +412,7 @@ static int ocfs2_commit_write(struct fil * stale inode allocation image (i_size, i_clusters, etc). */ - ret = ocfs2_meta_lock_with_page(inode, NULL, &di_bh, 1, page); + ret = ocfs2_meta_lock_with_page(inode, &di_bh, 1, page); if (ret != 0) { mlog_errno(ret); goto out; @@ -464,7 +464,7 @@ static int ocfs2_commit_write(struct fil } out_commit: - ocfs2_commit_trans(handle); + ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); out_unlock_data: ocfs2_data_unlock(inode, 1); out_unlock_meta: @@ -490,7 +490,7 @@ static sector_t ocfs2_bmap(struct addres * accessed concurrently from multiple nodes. */ if (!INODE_JOURNAL(inode)) { - err = ocfs2_meta_lock(inode, NULL, NULL, 0); + err = ocfs2_meta_lock(inode, NULL, 0); if (err) { if (err != -ENOENT) mlog_errno(err); diff --git a/fs/ocfs2/aops.h b/fs/ocfs2/aops.h index e88c3f0..f446a15 100644 --- a/fs/ocfs2/aops.h +++ b/fs/ocfs2/aops.h @@ -25,7 +25,7 @@ #define OCFS2_AOPS_H int ocfs2_prepare_write_nolock(struct inode *inode, struct page *page, unsigned from, unsigned to); -struct ocfs2_journal_handle *ocfs2_start_walk_page_trans(struct inode *inode, +handle_t *ocfs2_start_walk_page_trans(struct inode *inode, struct page *page, unsigned from, unsigned to); diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c index 04e0191..baad2aa 100644 --- a/fs/ocfs2/dir.c +++ b/fs/ocfs2/dir.c @@ -82,6 +82,7 @@ int ocfs2_readdir(struct file * filp, vo struct inode *inode = filp->f_dentry->d_inode; struct super_block * sb = inode->i_sb; unsigned int ra_sectors = 16; + int lock_level = 0; mlog_entry("dirino=%llu\n", (unsigned long long)OCFS2_I(inode)->ip_blkno); @@ -89,7 +90,15 @@ int ocfs2_readdir(struct file * filp, vo stored = 0; bh = NULL; - error = ocfs2_meta_lock(inode, NULL, NULL, 0); + error = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level); + if (lock_level && error >= 0) { + /* We release EX lock which used to update atime + * and get PR lock again to reduce contention + * on commonly accessed directories. */ + ocfs2_meta_unlock(inode, 1); + lock_level = 0; + error = ocfs2_meta_lock(inode, NULL, 0); + } if (error < 0) { if (error != -ENOENT) mlog_errno(error); @@ -198,7 +207,7 @@ revalidate: stored = 0; bail: - ocfs2_meta_unlock(inode, 0); + ocfs2_meta_unlock(inode, lock_level); bail_nolock: mlog_exit(stored); @@ -340,7 +349,7 @@ int ocfs2_empty_dir(struct inode *inode) /* returns a bh of the 1st new block in the allocation. */ int ocfs2_do_extend_dir(struct super_block *sb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *dir, struct buffer_head *parent_fe_bh, struct ocfs2_alloc_context *data_ac, @@ -398,7 +407,7 @@ static int ocfs2_extend_dir(struct ocfs2 struct ocfs2_dinode *fe = (struct ocfs2_dinode *) parent_fe_bh->b_data; struct ocfs2_alloc_context *data_ac = NULL; struct ocfs2_alloc_context *meta_ac = NULL; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; struct buffer_head *new_bh = NULL; struct ocfs2_dir_entry * de; struct super_block *sb = osb->sb; @@ -409,13 +418,6 @@ static int ocfs2_extend_dir(struct ocfs2 mlog(0, "extending dir %llu (i_size = %lld)\n", (unsigned long long)OCFS2_I(dir)->ip_blkno, dir_i_size); - handle = ocfs2_alloc_handle(osb); - if (handle == NULL) { - status = -ENOMEM; - mlog_errno(status); - goto bail; - } - /* dir->i_size is always block aligned. */ spin_lock(&OCFS2_I(dir)->ip_lock); if (dir_i_size == ocfs2_clusters_to_bytes(sb, OCFS2_I(dir)->ip_clusters)) { @@ -428,8 +430,7 @@ static int ocfs2_extend_dir(struct ocfs2 } if (!num_free_extents) { - status = ocfs2_reserve_new_metadata(osb, handle, - fe, &meta_ac); + status = ocfs2_reserve_new_metadata(osb, fe, &meta_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); @@ -437,7 +438,7 @@ static int ocfs2_extend_dir(struct ocfs2 } } - status = ocfs2_reserve_clusters(osb, handle, 1, &data_ac); + status = ocfs2_reserve_clusters(osb, 1, &data_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); @@ -450,7 +451,7 @@ static int ocfs2_extend_dir(struct ocfs2 credits = OCFS2_SIMPLE_DIR_EXTEND_CREDITS; } - handle = ocfs2_start_trans(osb, handle, credits); + handle = ocfs2_start_trans(osb, credits); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; @@ -496,7 +497,7 @@ static int ocfs2_extend_dir(struct ocfs2 get_bh(*new_de_bh); bail: if (handle) - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); if (data_ac) ocfs2_free_alloc_context(data_ac); diff --git a/fs/ocfs2/dir.h b/fs/ocfs2/dir.h index 5f614ec..3f67e14 100644 --- a/fs/ocfs2/dir.h +++ b/fs/ocfs2/dir.h @@ -45,7 +45,7 @@ int ocfs2_prepare_dir_for_insert(struct struct buffer_head **ret_de_bh); struct ocfs2_alloc_context; int ocfs2_do_extend_dir(struct super_block *sb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *dir, struct buffer_head *parent_fe_bh, struct ocfs2_alloc_context *data_ac, diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c index 8d1065f..a0b9763 100644 --- a/fs/ocfs2/dlm/dlmdomain.c +++ b/fs/ocfs2/dlm/dlmdomain.c @@ -67,7 +67,7 @@ static void **dlm_alloc_pagevec(int page if (!(vec[i] = (void *)__get_free_page(GFP_KERNEL))) goto out_free; - mlog(0, "Allocated DLM hash pagevec; %d pages (%lu expected), %lu buckets per page\n", + mlog(0, "Allocated DLM hash pagevec; %d pages (%d expected), %lu buckets per page\n", pages, DLM_HASH_PAGES, (unsigned long)DLM_BUCKETS_PER_PAGE); return vec; out_free: diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c index 8801e41..69fba16 100644 --- a/fs/ocfs2/dlmglue.c +++ b/fs/ocfs2/dlmglue.c @@ -49,6 +49,7 @@ #include "alloc.h" #include "dcache.h" #include "dlmglue.h" #include "extent_map.h" +#include "file.h" #include "heartbeat.h" #include "inode.h" #include "journal.h" @@ -1063,10 +1064,10 @@ static void ocfs2_cluster_unlock(struct mlog_exit_void(); } -int ocfs2_create_new_lock(struct ocfs2_super *osb, - struct ocfs2_lock_res *lockres, - int ex, - int local) +static int ocfs2_create_new_lock(struct ocfs2_super *osb, + struct ocfs2_lock_res *lockres, + int ex, + int local) { int level = ex ? LKM_EXMODE : LKM_PRMODE; unsigned long flags; @@ -1579,7 +1580,6 @@ static int ocfs2_assign_bh(struct inode * the result of the lock will be communicated via the callback. */ int ocfs2_meta_lock_full(struct inode *inode, - struct ocfs2_journal_handle *handle, struct buffer_head **ret_bh, int ex, int arg_flags) @@ -1668,12 +1668,6 @@ int ocfs2_meta_lock_full(struct inode *i } } - if (handle) { - status = ocfs2_handle_add_lock(handle, inode); - if (status < 0) - mlog_errno(status); - } - bail: if (status < 0) { if (ret_bh && (*ret_bh)) { @@ -1713,18 +1707,16 @@ bail: * the lock inversion simply. */ int ocfs2_meta_lock_with_page(struct inode *inode, - struct ocfs2_journal_handle *handle, struct buffer_head **ret_bh, int ex, struct page *page) { int ret; - ret = ocfs2_meta_lock_full(inode, handle, ret_bh, ex, - OCFS2_LOCK_NONBLOCK); + ret = ocfs2_meta_lock_full(inode, ret_bh, ex, OCFS2_LOCK_NONBLOCK); if (ret == -EAGAIN) { unlock_page(page); - if (ocfs2_meta_lock(inode, handle, ret_bh, ex) == 0) + if (ocfs2_meta_lock(inode, ret_bh, ex) == 0) ocfs2_meta_unlock(inode, ex); ret = AOP_TRUNCATED_PAGE; } @@ -1732,6 +1724,44 @@ int ocfs2_meta_lock_with_page(struct ino return ret; } +int ocfs2_meta_lock_atime(struct inode *inode, + struct vfsmount *vfsmnt, + int *level) +{ + int ret; + + mlog_entry_void(); + ret = ocfs2_meta_lock(inode, NULL, 0); + if (ret < 0) { + mlog_errno(ret); + return ret; + } + + /* + * If we should update atime, we will get EX lock, + * otherwise we just get PR lock. + */ + if (ocfs2_should_update_atime(inode, vfsmnt)) { + struct buffer_head *bh = NULL; + + ocfs2_meta_unlock(inode, 0); + ret = ocfs2_meta_lock(inode, &bh, 1); + if (ret < 0) { + mlog_errno(ret); + return ret; + } + *level = 1; + if (ocfs2_should_update_atime(inode, vfsmnt)) + ocfs2_update_inode_atime(inode, bh); + if (bh) + brelse(bh); + } else + *level = 0; + + mlog_exit(ret); + return ret; +} + void ocfs2_meta_unlock(struct inode *inode, int ex) { diff --git a/fs/ocfs2/dlmglue.h b/fs/ocfs2/dlmglue.h index 4a27693..c343fca 100644 --- a/fs/ocfs2/dlmglue.h +++ b/fs/ocfs2/dlmglue.h @@ -68,8 +68,6 @@ void ocfs2_dentry_lock_res_init(struct o u64 parent, struct inode *inode); void ocfs2_lock_res_free(struct ocfs2_lock_res *res); int ocfs2_create_new_inode_locks(struct inode *inode); -int ocfs2_create_new_lock(struct ocfs2_super *osb, - struct ocfs2_lock_res *lockres, int ex, int local); int ocfs2_drop_inode_locks(struct inode *inode); int ocfs2_data_lock_full(struct inode *inode, int write, @@ -82,19 +80,20 @@ void ocfs2_data_unlock(struct inode *ino int write); int ocfs2_rw_lock(struct inode *inode, int write); void ocfs2_rw_unlock(struct inode *inode, int write); +int ocfs2_meta_lock_atime(struct inode *inode, + struct vfsmount *vfsmnt, + int *level); int ocfs2_meta_lock_full(struct inode *inode, - struct ocfs2_journal_handle *handle, struct buffer_head **ret_bh, int ex, int arg_flags); int ocfs2_meta_lock_with_page(struct inode *inode, - struct ocfs2_journal_handle *handle, struct buffer_head **ret_bh, int ex, struct page *page); /* 99% of the time we don't want to supply any additional flags -- * those are for very specific cases only. */ -#define ocfs2_meta_lock(i, h, b, e) ocfs2_meta_lock_full(i, h, b, e, 0) +#define ocfs2_meta_lock(i, b, e) ocfs2_meta_lock_full(i, b, e, 0) void ocfs2_meta_unlock(struct inode *inode, int ex); int ocfs2_super_lock(struct ocfs2_super *osb, diff --git a/fs/ocfs2/export.c b/fs/ocfs2/export.c index fb91089..06be6e7 100644 --- a/fs/ocfs2/export.c +++ b/fs/ocfs2/export.c @@ -100,7 +100,7 @@ static struct dentry *ocfs2_get_parent(s mlog(0, "find parent of directory %llu\n", (unsigned long long)OCFS2_I(dir)->ip_blkno); - status = ocfs2_meta_lock(dir, NULL, NULL, 0); + status = ocfs2_meta_lock(dir, NULL, 0); if (status < 0) { if (status != -ENOENT) mlog_errno(status); diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c index 1be74c4..8786b3c 100644 --- a/fs/ocfs2/file.c +++ b/fs/ocfs2/file.c @@ -31,6 +31,8 @@ #include #include #include #include +#include +#include #define MLOG_MASK_PREFIX ML_INODE #include @@ -134,7 +136,58 @@ bail: return (err < 0) ? -EIO : 0; } -int ocfs2_set_inode_size(struct ocfs2_journal_handle *handle, +int ocfs2_should_update_atime(struct inode *inode, + struct vfsmount *vfsmnt) +{ + struct timespec now; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + + if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb)) + return 0; + + if ((inode->i_flags & S_NOATIME) || + ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))) + return 0; + + if ((vfsmnt->mnt_flags & MNT_NOATIME) || + ((vfsmnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))) + return 0; + + now = CURRENT_TIME; + if ((now.tv_sec - inode->i_atime.tv_sec <= osb->s_atime_quantum)) + return 0; + else + return 1; +} + +int ocfs2_update_inode_atime(struct inode *inode, + struct buffer_head *bh) +{ + int ret; + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + handle_t *handle; + + mlog_entry_void(); + + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); + if (handle == NULL) { + ret = -ENOMEM; + mlog_errno(ret); + goto out; + } + + inode->i_atime = CURRENT_TIME; + ret = ocfs2_mark_inode_dirty(handle, inode, bh); + if (ret < 0) + mlog_errno(ret); + + ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); +out: + mlog_exit(ret); + return ret; +} + +int ocfs2_set_inode_size(handle_t *handle, struct inode *inode, struct buffer_head *fe_bh, u64 new_i_size) @@ -163,10 +216,9 @@ static int ocfs2_simple_size_update(stru { int ret; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; - handle = ocfs2_start_trans(osb, NULL, - OCFS2_INODE_UPDATE_CREDITS); + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); if (handle == NULL) { ret = -ENOMEM; mlog_errno(ret); @@ -178,7 +230,7 @@ static int ocfs2_simple_size_update(stru if (ret < 0) mlog_errno(ret); - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); out: return ret; } @@ -189,14 +241,14 @@ static int ocfs2_orphan_for_truncate(str u64 new_i_size) { int status; - struct ocfs2_journal_handle *handle; + handle_t *handle; mlog_entry_void(); /* TODO: This needs to actually orphan the inode in this * transaction. */ - handle = ocfs2_start_trans(osb, NULL, OCFS2_INODE_UPDATE_CREDITS); + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); mlog_errno(status); @@ -207,7 +259,7 @@ static int ocfs2_orphan_for_truncate(str if (status < 0) mlog_errno(status); - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); out: mlog_exit(status); return status; @@ -328,7 +380,7 @@ int ocfs2_do_extend_allocation(struct oc struct inode *inode, u32 clusters_to_add, struct buffer_head *fe_bh, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct ocfs2_alloc_context *data_ac, struct ocfs2_alloc_context *meta_ac, enum ocfs2_alloc_restarted *reason_ret) @@ -433,7 +485,7 @@ static int ocfs2_extend_allocation(struc u32 prev_clusters; struct buffer_head *bh = NULL; struct ocfs2_dinode *fe = NULL; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; struct ocfs2_alloc_context *data_ac = NULL; struct ocfs2_alloc_context *meta_ac = NULL; enum ocfs2_alloc_restarted why; @@ -463,13 +515,6 @@ restart_all: (unsigned long long)OCFS2_I(inode)->ip_blkno, i_size_read(inode), fe->i_clusters, clusters_to_add); - handle = ocfs2_alloc_handle(osb); - if (handle == NULL) { - status = -ENOMEM; - mlog_errno(status); - goto leave; - } - num_free_extents = ocfs2_num_free_extents(osb, inode, fe); @@ -480,10 +525,7 @@ restart_all: } if (!num_free_extents) { - status = ocfs2_reserve_new_metadata(osb, - handle, - fe, - &meta_ac); + status = ocfs2_reserve_new_metadata(osb, fe, &meta_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); @@ -491,10 +533,7 @@ restart_all: } } - status = ocfs2_reserve_clusters(osb, - handle, - clusters_to_add, - &data_ac); + status = ocfs2_reserve_clusters(osb, clusters_to_add, &data_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); @@ -509,7 +548,7 @@ restart_all: drop_alloc_sem = 1; credits = ocfs2_calc_extend_credits(osb->sb, fe, clusters_to_add); - handle = ocfs2_start_trans(osb, handle, credits); + handle = ocfs2_start_trans(osb, credits); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; @@ -589,7 +628,7 @@ leave: drop_alloc_sem = 0; } if (handle) { - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); handle = NULL; } if (data_ac) { @@ -624,7 +663,7 @@ static int ocfs2_write_zero_page(struct struct page *page; unsigned long index; unsigned int offset; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; int ret; offset = (size & (PAGE_CACHE_SIZE-1)); /* Within page */ @@ -668,7 +707,7 @@ static int ocfs2_write_zero_page(struct ret = 0; if (handle) - ocfs2_commit_trans(handle); + ocfs2_commit_trans(OCFS2_SB(inode->i_sb), handle); out_unlock: unlock_page(page); page_cache_release(page); @@ -789,7 +828,7 @@ int ocfs2_setattr(struct dentry *dentry, struct super_block *sb = inode->i_sb; struct ocfs2_super *osb = OCFS2_SB(sb); struct buffer_head *bh = NULL; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; mlog_entry("(0x%p, '%.*s')\n", dentry, dentry->d_name.len, dentry->d_name.name); @@ -825,7 +864,7 @@ #define OCFS2_VALID_ATTRS (ATTR_ATIME | } } - status = ocfs2_meta_lock(inode, NULL, &bh, 1); + status = ocfs2_meta_lock(inode, &bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -845,7 +884,7 @@ #define OCFS2_VALID_ATTRS (ATTR_ATIME | } } - handle = ocfs2_start_trans(osb, NULL, OCFS2_INODE_UPDATE_CREDITS); + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); mlog_errno(status); @@ -863,7 +902,7 @@ #define OCFS2_VALID_ATTRS (ATTR_ATIME | mlog_errno(status); bail_commit: - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); bail_unlock: ocfs2_meta_unlock(inode, 1); bail_unlock_rw: @@ -906,19 +945,41 @@ bail: return err; } +int ocfs2_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + int ret; + + mlog_entry_void(); + + ret = ocfs2_meta_lock(inode, NULL, 0); + if (ret) { + mlog_errno(ret); + goto out; + } + + ret = generic_permission(inode, mask, NULL); + if (ret) + mlog_errno(ret); + + ocfs2_meta_unlock(inode, 0); +out: + mlog_exit(ret); + return ret; +} + static int ocfs2_write_remove_suid(struct inode *inode) { int ret; struct buffer_head *bh = NULL; struct ocfs2_inode_info *oi = OCFS2_I(inode); - struct ocfs2_journal_handle *handle; + handle_t *handle; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct ocfs2_dinode *di; mlog_entry("(Inode %llu, mode 0%o)\n", (unsigned long long)oi->ip_blkno, inode->i_mode); - handle = ocfs2_start_trans(osb, NULL, OCFS2_INODE_UPDATE_CREDITS); + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); if (handle == NULL) { ret = -ENOMEM; mlog_errno(ret); @@ -951,75 +1012,29 @@ static int ocfs2_write_remove_suid(struc out_bh: brelse(bh); out_trans: - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); out: mlog_exit(ret); return ret; } -static inline int ocfs2_write_should_remove_suid(struct inode *inode) -{ - mode_t mode = inode->i_mode; - - if (!capable(CAP_FSETID)) { - if (unlikely(mode & S_ISUID)) - return 1; - - if (unlikely((mode & S_ISGID) && (mode & S_IXGRP))) - return 1; - } - return 0; -} - -static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, - const struct iovec *iov, - unsigned long nr_segs, - loff_t pos) +static int ocfs2_prepare_inode_for_write(struct dentry *dentry, + loff_t *ppos, + size_t count, + int appending) { - int ret, rw_level = -1, meta_level = -1, have_alloc_sem = 0; + int ret = 0, meta_level = appending; + struct inode *inode = dentry->d_inode; u32 clusters; - struct file *filp = iocb->ki_filp; - struct inode *inode = filp->f_dentry->d_inode; loff_t newsize, saved_pos; - mlog_entry("(0x%p, %u, '%.*s')\n", filp, - (unsigned int)nr_segs, - filp->f_dentry->d_name.len, - filp->f_dentry->d_name.name); - - /* happy write of zero bytes */ - if (iocb->ki_left == 0) - return 0; - - if (!inode) { - mlog(0, "bad inode\n"); - return -EIO; - } - - mutex_lock(&inode->i_mutex); - /* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */ - if (filp->f_flags & O_DIRECT) { - have_alloc_sem = 1; - down_read(&inode->i_alloc_sem); - } - - /* concurrent O_DIRECT writes are allowed */ - rw_level = (filp->f_flags & O_DIRECT) ? 0 : 1; - ret = ocfs2_rw_lock(inode, rw_level); - if (ret < 0) { - rw_level = -1; - mlog_errno(ret); - goto out; - } - /* * We sample i_size under a read level meta lock to see if our write * is extending the file, if it is we back off and get a write level * meta lock. */ - meta_level = (filp->f_flags & O_APPEND) ? 1 : 0; for(;;) { - ret = ocfs2_meta_lock(inode, NULL, NULL, meta_level); + ret = ocfs2_meta_lock(inode, NULL, meta_level); if (ret < 0) { meta_level = -1; mlog_errno(ret); @@ -1035,7 +1050,7 @@ static ssize_t ocfs2_file_aio_write(stru * inode. There's also the dinode i_size state which * can be lost via setattr during extending writes (we * set inode->i_size at the end of a write. */ - if (ocfs2_write_should_remove_suid(inode)) { + if (should_remove_suid(dentry)) { if (meta_level == 0) { ocfs2_meta_unlock(inode, meta_level); meta_level = 1; @@ -1045,19 +1060,19 @@ static ssize_t ocfs2_file_aio_write(stru ret = ocfs2_write_remove_suid(inode); if (ret < 0) { mlog_errno(ret); - goto out; + goto out_unlock; } } /* work on a copy of ppos until we're sure that we won't have * to recalculate it due to relocking. */ - if (filp->f_flags & O_APPEND) { + if (appending) { saved_pos = i_size_read(inode); mlog(0, "O_APPEND: inode->i_size=%llu\n", saved_pos); } else { - saved_pos = iocb->ki_pos; + saved_pos = *ppos; } - newsize = iocb->ki_left + saved_pos; + newsize = count + saved_pos; mlog(0, "pos=%lld newsize=%lld cursize=%lld\n", (long long) saved_pos, (long long) newsize, @@ -1090,19 +1105,66 @@ static ssize_t ocfs2_file_aio_write(stru if (!clusters) break; - ret = ocfs2_extend_file(inode, NULL, newsize, iocb->ki_left); + ret = ocfs2_extend_file(inode, NULL, newsize, count); if (ret < 0) { if (ret != -ENOSPC) mlog_errno(ret); - goto out; + goto out_unlock; } break; } - /* ok, we're done with i_size and alloc work */ - iocb->ki_pos = saved_pos; + if (appending) + *ppos = saved_pos; + +out_unlock: ocfs2_meta_unlock(inode, meta_level); - meta_level = -1; + +out: + return ret; +} + +static ssize_t ocfs2_file_aio_write(struct kiocb *iocb, + const struct iovec *iov, + unsigned long nr_segs, + loff_t pos) +{ + int ret, rw_level, have_alloc_sem = 0; + struct file *filp = iocb->ki_filp; + struct inode *inode = filp->f_dentry->d_inode; + int appending = filp->f_flags & O_APPEND ? 1 : 0; + + mlog_entry("(0x%p, %u, '%.*s')\n", filp, + (unsigned int)nr_segs, + filp->f_dentry->d_name.len, + filp->f_dentry->d_name.name); + + /* happy write of zero bytes */ + if (iocb->ki_left == 0) + return 0; + + mutex_lock(&inode->i_mutex); + /* to match setattr's i_mutex -> i_alloc_sem -> rw_lock ordering */ + if (filp->f_flags & O_DIRECT) { + have_alloc_sem = 1; + down_read(&inode->i_alloc_sem); + } + + /* concurrent O_DIRECT writes are allowed */ + rw_level = (filp->f_flags & O_DIRECT) ? 0 : 1; + ret = ocfs2_rw_lock(inode, rw_level); + if (ret < 0) { + rw_level = -1; + mlog_errno(ret); + goto out; + } + + ret = ocfs2_prepare_inode_for_write(filp->f_dentry, &iocb->ki_pos, + iocb->ki_left, appending); + if (ret < 0) { + mlog_errno(ret); + goto out; + } /* communicate with ocfs2_dio_end_io */ ocfs2_iocb_set_rw_locked(iocb); @@ -1128,8 +1190,6 @@ static ssize_t ocfs2_file_aio_write(stru } out: - if (meta_level != -1) - ocfs2_meta_unlock(inode, meta_level); if (have_alloc_sem) up_read(&inode->i_alloc_sem); if (rw_level != -1) @@ -1140,12 +1200,83 @@ out: return ret; } +static ssize_t ocfs2_file_splice_write(struct pipe_inode_info *pipe, + struct file *out, + loff_t *ppos, + size_t len, + unsigned int flags) +{ + int ret; + struct inode *inode = out->f_dentry->d_inode; + + mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", out, pipe, + (unsigned int)len, + out->f_dentry->d_name.len, + out->f_dentry->d_name.name); + + inode_double_lock(inode, pipe->inode); + + ret = ocfs2_rw_lock(inode, 1); + if (ret < 0) { + mlog_errno(ret); + goto out; + } + + ret = ocfs2_prepare_inode_for_write(out->f_dentry, ppos, len, 0); + if (ret < 0) { + mlog_errno(ret); + goto out_unlock; + } + + /* ok, we're done with i_size and alloc work */ + ret = generic_file_splice_write_nolock(pipe, out, ppos, len, flags); + +out_unlock: + ocfs2_rw_unlock(inode, 1); +out: + inode_double_unlock(inode, pipe->inode); + + mlog_exit(ret); + return ret; +} + +static ssize_t ocfs2_file_splice_read(struct file *in, + loff_t *ppos, + struct pipe_inode_info *pipe, + size_t len, + unsigned int flags) +{ + int ret = 0; + struct inode *inode = in->f_dentry->d_inode; + + mlog_entry("(0x%p, 0x%p, %u, '%.*s')\n", in, pipe, + (unsigned int)len, + in->f_dentry->d_name.len, + in->f_dentry->d_name.name); + + /* + * See the comment in ocfs2_file_aio_read() + */ + ret = ocfs2_meta_lock(inode, NULL, 0); + if (ret < 0) { + mlog_errno(ret); + goto bail; + } + ocfs2_meta_unlock(inode, 0); + + ret = generic_file_splice_read(in, ppos, pipe, len, flags); + +bail: + mlog_exit(ret); + return ret; +} + static ssize_t ocfs2_file_aio_read(struct kiocb *iocb, const struct iovec *iov, unsigned long nr_segs, loff_t pos) { - int ret = 0, rw_level = -1, have_alloc_sem = 0; + int ret = 0, rw_level = -1, have_alloc_sem = 0, lock_level = 0; struct file *filp = iocb->ki_filp; struct inode *inode = filp->f_dentry->d_inode; @@ -1187,12 +1318,12 @@ static ssize_t ocfs2_file_aio_read(struc * like i_size. This allows the checks down below * generic_file_aio_read() a chance of actually working. */ - ret = ocfs2_meta_lock(inode, NULL, NULL, 0); + ret = ocfs2_meta_lock_atime(inode, filp->f_vfsmnt, &lock_level); if (ret < 0) { mlog_errno(ret); goto bail; } - ocfs2_meta_unlock(inode, 0); + ocfs2_meta_unlock(inode, lock_level); ret = generic_file_aio_read(iocb, iov, nr_segs, iocb->ki_pos); if (ret == -EINVAL) @@ -1220,11 +1351,13 @@ bail: struct inode_operations ocfs2_file_iops = { .setattr = ocfs2_setattr, .getattr = ocfs2_getattr, + .permission = ocfs2_permission, }; struct inode_operations ocfs2_special_file_iops = { .setattr = ocfs2_setattr, .getattr = ocfs2_getattr, + .permission = ocfs2_permission, }; const struct file_operations ocfs2_fops = { @@ -1238,6 +1371,8 @@ const struct file_operations ocfs2_fops .aio_read = ocfs2_file_aio_read, .aio_write = ocfs2_file_aio_write, .ioctl = ocfs2_ioctl, + .splice_read = ocfs2_file_splice_read, + .splice_write = ocfs2_file_splice_write, }; const struct file_operations ocfs2_dops = { diff --git a/fs/ocfs2/file.h b/fs/ocfs2/file.h index 740c9e7..601a453 100644 --- a/fs/ocfs2/file.h +++ b/fs/ocfs2/file.h @@ -41,17 +41,24 @@ int ocfs2_do_extend_allocation(struct oc struct inode *inode, u32 clusters_to_add, struct buffer_head *fe_bh, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct ocfs2_alloc_context *data_ac, struct ocfs2_alloc_context *meta_ac, enum ocfs2_alloc_restarted *reason); int ocfs2_setattr(struct dentry *dentry, struct iattr *attr); int ocfs2_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat); +int ocfs2_permission(struct inode *inode, int mask, + struct nameidata *nd); -int ocfs2_set_inode_size(struct ocfs2_journal_handle *handle, +int ocfs2_set_inode_size(handle_t *handle, struct inode *inode, struct buffer_head *fe_bh, u64 new_i_size); +int ocfs2_should_update_atime(struct inode *inode, + struct vfsmount *vfsmnt); +int ocfs2_update_inode_atime(struct inode *inode, + struct buffer_head *bh); + #endif /* OCFS2_FILE_H */ diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c index 16e8e74..42e361f 100644 --- a/fs/ocfs2/inode.c +++ b/fs/ocfs2/inode.c @@ -360,7 +360,6 @@ int ocfs2_populate_inode(struct inode *i inode); ocfs2_set_inode_flags(inode); - inode->i_flags |= S_NOATIME; status = 0; bail: @@ -441,7 +440,7 @@ static int ocfs2_read_locked_inode(struc generation, inode); if (can_lock) { - status = ocfs2_meta_lock(inode, NULL, NULL, 0); + status = ocfs2_meta_lock(inode, NULL, 0); if (status) { make_bad_inode(inode); mlog_errno(status); @@ -512,7 +511,7 @@ static int ocfs2_truncate_for_delete(str struct buffer_head *fe_bh) { int status = 0; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; struct ocfs2_truncate_context *tc = NULL; struct ocfs2_dinode *fe; @@ -524,7 +523,7 @@ static int ocfs2_truncate_for_delete(str if (!fe->i_clusters) goto bail; - handle = ocfs2_start_trans(osb, handle, OCFS2_INODE_UPDATE_CREDITS); + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; @@ -538,7 +537,7 @@ static int ocfs2_truncate_for_delete(str goto bail; } - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); handle = NULL; status = ocfs2_prepare_truncate(osb, inode, fe_bh, &tc); @@ -554,7 +553,7 @@ static int ocfs2_truncate_for_delete(str } bail: if (handle) - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); mlog_exit(status); return status; @@ -568,7 +567,7 @@ static int ocfs2_remove_inode(struct ino int status; struct inode *inode_alloc_inode = NULL; struct buffer_head *inode_alloc_bh = NULL; - struct ocfs2_journal_handle *handle; + handle_t *handle; struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); struct ocfs2_dinode *di = (struct ocfs2_dinode *) di_bh->b_data; @@ -582,7 +581,7 @@ static int ocfs2_remove_inode(struct ino } mutex_lock(&inode_alloc_inode->i_mutex); - status = ocfs2_meta_lock(inode_alloc_inode, NULL, &inode_alloc_bh, 1); + status = ocfs2_meta_lock(inode_alloc_inode, &inode_alloc_bh, 1); if (status < 0) { mutex_unlock(&inode_alloc_inode->i_mutex); @@ -590,7 +589,7 @@ static int ocfs2_remove_inode(struct ino goto bail; } - handle = ocfs2_start_trans(osb, NULL, OCFS2_DELETE_INODE_CREDITS); + handle = ocfs2_start_trans(osb, OCFS2_DELETE_INODE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); mlog_errno(status); @@ -629,7 +628,7 @@ static int ocfs2_remove_inode(struct ino mlog_errno(status); bail_commit: - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); bail_unlock: ocfs2_meta_unlock(inode_alloc_inode, 1); mutex_unlock(&inode_alloc_inode->i_mutex); @@ -705,7 +704,7 @@ static int ocfs2_wipe_inode(struct inode * delete_inode operation. We do this now to avoid races with * recovery completion on other nodes. */ mutex_lock(&orphan_dir_inode->i_mutex); - status = ocfs2_meta_lock(orphan_dir_inode, NULL, &orphan_dir_bh, 1); + status = ocfs2_meta_lock(orphan_dir_inode, &orphan_dir_bh, 1); if (status < 0) { mutex_unlock(&orphan_dir_inode->i_mutex); @@ -933,7 +932,7 @@ void ocfs2_delete_inode(struct inode *in * allocation lock here as it won't be needed - nobody will * have the file open. */ - status = ocfs2_meta_lock(inode, NULL, &di_bh, 1); + status = ocfs2_meta_lock(inode, &di_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -1067,12 +1066,6 @@ void ocfs2_clear_inode(struct inode *ino mlog_bug_on_msg(oi->ip_open_count, "Clear inode of %llu has open count %d\n", (unsigned long long)oi->ip_blkno, oi->ip_open_count); - mlog_bug_on_msg(!list_empty(&oi->ip_handle_list), - "Clear inode of %llu has non empty handle list\n", - (unsigned long long)oi->ip_blkno); - mlog_bug_on_msg(oi->ip_handle, - "Clear inode of %llu has non empty handle pointer\n", - (unsigned long long)oi->ip_blkno); /* Clear all other flags. */ oi->ip_flags = OCFS2_INODE_CACHE_INLINE; @@ -1186,7 +1179,7 @@ int ocfs2_inode_revalidate(struct dentry /* Let ocfs2_meta_lock do the work of updating our struct * inode for us. */ - status = ocfs2_meta_lock(inode, NULL, NULL, 0); + status = ocfs2_meta_lock(inode, NULL, 0); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -1204,7 +1197,7 @@ bail: * struct inode. * Only takes ip_lock. */ -int ocfs2_mark_inode_dirty(struct ocfs2_journal_handle *handle, +int ocfs2_mark_inode_dirty(handle_t *handle, struct inode *inode, struct buffer_head *bh) { diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h index 9957810..46a378f 100644 --- a/fs/ocfs2/inode.h +++ b/fs/ocfs2/inode.h @@ -48,13 +48,6 @@ struct ocfs2_inode_info struct mutex ip_io_mutex; - /* Used by the journalling code to attach an inode to a - * handle. These are protected by ip_io_mutex in order to lock - * out other I/O to the inode until we either commit or - * abort. */ - struct list_head ip_handle_list; - struct ocfs2_journal_handle *ip_handle; - u32 ip_flags; /* see below */ u32 ip_attr; /* inode attributes */ @@ -143,7 +136,7 @@ ssize_t ocfs2_rw_direct(int rw, struct f void ocfs2_sync_blockdev(struct super_block *sb); void ocfs2_refresh_inode(struct inode *inode, struct ocfs2_dinode *fe); -int ocfs2_mark_inode_dirty(struct ocfs2_journal_handle *handle, +int ocfs2_mark_inode_dirty(handle_t *handle, struct inode *inode, struct buffer_head *bh); int ocfs2_aio_read(struct file *file, struct kiocb *req, struct iocb *iocb); diff --git a/fs/ocfs2/ioctl.c b/fs/ocfs2/ioctl.c index 3663cef..4768be5 100644 --- a/fs/ocfs2/ioctl.c +++ b/fs/ocfs2/ioctl.c @@ -26,7 +26,7 @@ static int ocfs2_get_inode_attr(struct i { int status; - status = ocfs2_meta_lock(inode, NULL, NULL, 0); + status = ocfs2_meta_lock(inode, NULL, 0); if (status < 0) { mlog_errno(status); return status; @@ -43,14 +43,14 @@ static int ocfs2_set_inode_attr(struct i { struct ocfs2_inode_info *ocfs2_inode = OCFS2_I(inode); struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; struct buffer_head *bh = NULL; unsigned oldflags; int status; mutex_lock(&inode->i_mutex); - status = ocfs2_meta_lock(inode, NULL, &bh, 1); + status = ocfs2_meta_lock(inode, &bh, 1); if (status < 0) { mlog_errno(status); goto bail; @@ -67,7 +67,7 @@ static int ocfs2_set_inode_attr(struct i if (!S_ISDIR(inode->i_mode)) flags &= ~OCFS2_DIRSYNC_FL; - handle = ocfs2_start_trans(osb, NULL, OCFS2_INODE_UPDATE_CREDITS); + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); mlog_errno(status); @@ -96,7 +96,7 @@ static int ocfs2_set_inode_attr(struct i if (status < 0) mlog_errno(status); - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); bail_unlock: ocfs2_meta_unlock(inode, 1); bail: diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c index fd9734d..22106da 100644 --- a/fs/ocfs2/journal.c +++ b/fs/ocfs2/journal.c @@ -57,9 +57,6 @@ static int ocfs2_recover_node(struct ocf static int __ocfs2_recovery_thread(void *arg); static int ocfs2_commit_cache(struct ocfs2_super *osb); static int ocfs2_wait_on_mount(struct ocfs2_super *osb); -static void ocfs2_handle_cleanup_locks(struct ocfs2_journal *journal, - struct ocfs2_journal_handle *handle); -static void ocfs2_commit_unstarted_handle(struct ocfs2_journal_handle *handle); static int ocfs2_journal_toggle_dirty(struct ocfs2_super *osb, int dirty); static int ocfs2_trylock_journal(struct ocfs2_super *osb, @@ -113,46 +110,18 @@ finally: return status; } -struct ocfs2_journal_handle *ocfs2_alloc_handle(struct ocfs2_super *osb) -{ - struct ocfs2_journal_handle *retval = NULL; - - retval = kcalloc(1, sizeof(*retval), GFP_NOFS); - if (!retval) { - mlog(ML_ERROR, "Failed to allocate memory for journal " - "handle!\n"); - return NULL; - } - - retval->max_buffs = 0; - retval->num_locks = 0; - retval->k_handle = NULL; - - INIT_LIST_HEAD(&retval->locks); - INIT_LIST_HEAD(&retval->inode_list); - retval->journal = osb->journal; - - return retval; -} - /* pass it NULL and it will allocate a new handle object for you. If * you pass it a handle however, it may still return error, in which * case it has free'd the passed handle for you. */ -struct ocfs2_journal_handle *ocfs2_start_trans(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, - int max_buffs) +handle_t *ocfs2_start_trans(struct ocfs2_super *osb, int max_buffs) { - int ret; journal_t *journal = osb->journal->j_journal; - - mlog_entry("(max_buffs = %d)\n", max_buffs); + handle_t *handle; BUG_ON(!osb || !osb->journal->j_journal); - if (ocfs2_is_hard_readonly(osb)) { - ret = -EROFS; - goto done_free; - } + if (ocfs2_is_hard_readonly(osb)) + return ERR_PTR(-EROFS); BUG_ON(osb->journal->j_state == OCFS2_JOURNAL_FREE); BUG_ON(max_buffs <= 0); @@ -163,154 +132,39 @@ struct ocfs2_journal_handle *ocfs2_start BUG(); } - if (!handle) - handle = ocfs2_alloc_handle(osb); - if (!handle) { - ret = -ENOMEM; - mlog(ML_ERROR, "Failed to allocate memory for journal " - "handle!\n"); - goto done_free; - } - - handle->max_buffs = max_buffs; - down_read(&osb->journal->j_trans_barrier); - /* actually start the transaction now */ - handle->k_handle = journal_start(journal, max_buffs); - if (IS_ERR(handle->k_handle)) { + handle = journal_start(journal, max_buffs); + if (IS_ERR(handle)) { up_read(&osb->journal->j_trans_barrier); - ret = PTR_ERR(handle->k_handle); - handle->k_handle = NULL; - mlog_errno(ret); + mlog_errno(PTR_ERR(handle)); if (is_journal_aborted(journal)) { ocfs2_abort(osb->sb, "Detected aborted journal"); - ret = -EROFS; + handle = ERR_PTR(-EROFS); } - goto done_free; - } - - atomic_inc(&(osb->journal->j_num_trans)); - handle->flags |= OCFS2_HANDLE_STARTED; + } else + atomic_inc(&(osb->journal->j_num_trans)); - mlog_exit_ptr(handle); return handle; - -done_free: - if (handle) - ocfs2_commit_unstarted_handle(handle); /* will kfree handle */ - - mlog_exit(ret); - return ERR_PTR(ret); -} - -void ocfs2_handle_add_inode(struct ocfs2_journal_handle *handle, - struct inode *inode) -{ - BUG_ON(!handle); - BUG_ON(!inode); - - atomic_inc(&inode->i_count); - - /* we're obviously changing it... */ - mutex_lock(&inode->i_mutex); - - /* sanity check */ - BUG_ON(OCFS2_I(inode)->ip_handle); - BUG_ON(!list_empty(&OCFS2_I(inode)->ip_handle_list)); - - OCFS2_I(inode)->ip_handle = handle; - list_move_tail(&(OCFS2_I(inode)->ip_handle_list), &(handle->inode_list)); -} - -static void ocfs2_handle_unlock_inodes(struct ocfs2_journal_handle *handle) -{ - struct list_head *p, *n; - struct inode *inode; - struct ocfs2_inode_info *oi; - - list_for_each_safe(p, n, &handle->inode_list) { - oi = list_entry(p, struct ocfs2_inode_info, - ip_handle_list); - inode = &oi->vfs_inode; - - OCFS2_I(inode)->ip_handle = NULL; - list_del_init(&OCFS2_I(inode)->ip_handle_list); - - mutex_unlock(&inode->i_mutex); - iput(inode); - } -} - -/* This is trivial so we do it out of the main commit - * paths. Beware, it can be called from start_trans too! */ -static void ocfs2_commit_unstarted_handle(struct ocfs2_journal_handle *handle) -{ - mlog_entry_void(); - - BUG_ON(handle->flags & OCFS2_HANDLE_STARTED); - - ocfs2_handle_unlock_inodes(handle); - /* You are allowed to add journal locks before the transaction - * has started. */ - ocfs2_handle_cleanup_locks(handle->journal, handle); - - kfree(handle); - - mlog_exit_void(); } -void ocfs2_commit_trans(struct ocfs2_journal_handle *handle) +int ocfs2_commit_trans(struct ocfs2_super *osb, + handle_t *handle) { - handle_t *jbd_handle; - int retval; - struct ocfs2_journal *journal = handle->journal; - - mlog_entry_void(); + int ret; + struct ocfs2_journal *journal = osb->journal; BUG_ON(!handle); - if (!(handle->flags & OCFS2_HANDLE_STARTED)) { - ocfs2_commit_unstarted_handle(handle); - mlog_exit_void(); - return; - } - - /* release inode semaphores we took during this transaction */ - ocfs2_handle_unlock_inodes(handle); - - /* ocfs2_extend_trans may have had to call journal_restart - * which will always commit the transaction, but may return - * error for any number of reasons. If this is the case, we - * clear k_handle as it's not valid any more. */ - if (handle->k_handle) { - jbd_handle = handle->k_handle; - - if (handle->flags & OCFS2_HANDLE_SYNC) - jbd_handle->h_sync = 1; - else - jbd_handle->h_sync = 0; - - /* actually stop the transaction. if we've set h_sync, - * it'll have been committed when we return */ - retval = journal_stop(jbd_handle); - if (retval < 0) { - mlog_errno(retval); - mlog(ML_ERROR, "Could not commit transaction\n"); - BUG(); - } - - handle->k_handle = NULL; /* it's been free'd in journal_stop */ - } - - ocfs2_handle_cleanup_locks(journal, handle); + ret = journal_stop(handle); + if (ret < 0) + mlog_errno(ret); up_read(&journal->j_trans_barrier); - kfree(handle); - mlog_exit_void(); + return ret; } /* @@ -325,21 +179,22 @@ void ocfs2_commit_trans(struct ocfs2_jou * WARNING2: Note that we do *not* drop j_trans_barrier here. This is * good because transaction ids haven't yet been recorded on the * cluster locks associated with this handle. + * + * journal_restart() will commit the handle for us. In the case of + * Will set *handle to NULL if journal_restart() fails */ -int ocfs2_extend_trans(struct ocfs2_journal_handle *handle, - int nblocks) +int ocfs2_extend_trans(handle_t *handle, int nblocks) { int status; BUG_ON(!handle); - BUG_ON(!(handle->flags & OCFS2_HANDLE_STARTED)); BUG_ON(!nblocks); mlog_entry_void(); mlog(0, "Trying to extend transaction by %d blocks\n", nblocks); - status = journal_extend(handle->k_handle, nblocks); + status = journal_extend(handle, nblocks); if (status < 0) { mlog_errno(status); goto bail; @@ -347,15 +202,12 @@ int ocfs2_extend_trans(struct ocfs2_jour if (status > 0) { mlog(0, "journal_extend failed, trying journal_restart\n"); - status = journal_restart(handle->k_handle, nblocks); + status = journal_restart(handle, nblocks); if (status < 0) { - handle->k_handle = NULL; mlog_errno(status); goto bail; } - handle->max_buffs = nblocks; - } else - handle->max_buffs += nblocks; + } status = 0; bail: @@ -364,7 +216,7 @@ bail: return status; } -int ocfs2_journal_access(struct ocfs2_journal_handle *handle, +int ocfs2_journal_access(handle_t *handle, struct inode *inode, struct buffer_head *bh, int type) @@ -374,7 +226,6 @@ int ocfs2_journal_access(struct ocfs2_jo BUG_ON(!inode); BUG_ON(!handle); BUG_ON(!bh); - BUG_ON(!(handle->flags & OCFS2_HANDLE_STARTED)); mlog_entry("bh->b_blocknr=%llu, type=%d (\"%s\"), bh->b_size = %zu\n", (unsigned long long)bh->b_blocknr, type, @@ -403,11 +254,11 @@ int ocfs2_journal_access(struct ocfs2_jo switch (type) { case OCFS2_JOURNAL_ACCESS_CREATE: case OCFS2_JOURNAL_ACCESS_WRITE: - status = journal_get_write_access(handle->k_handle, bh); + status = journal_get_write_access(handle, bh); break; case OCFS2_JOURNAL_ACCESS_UNDO: - status = journal_get_undo_access(handle->k_handle, bh); + status = journal_get_undo_access(handle, bh); break; default: @@ -424,17 +275,15 @@ int ocfs2_journal_access(struct ocfs2_jo return status; } -int ocfs2_journal_dirty(struct ocfs2_journal_handle *handle, +int ocfs2_journal_dirty(handle_t *handle, struct buffer_head *bh) { int status; - BUG_ON(!(handle->flags & OCFS2_HANDLE_STARTED)); - mlog_entry("(bh->b_blocknr=%llu)\n", (unsigned long long)bh->b_blocknr); - status = journal_dirty_metadata(handle->k_handle, bh); + status = journal_dirty_metadata(handle, bh); if (status < 0) mlog(ML_ERROR, "Could not dirty metadata buffer. " "(bh->b_blocknr=%llu)\n", @@ -456,59 +305,6 @@ int ocfs2_journal_dirty_data(handle_t *h return err; } -/* We always assume you're adding a metadata lock at level 'ex' */ -int ocfs2_handle_add_lock(struct ocfs2_journal_handle *handle, - struct inode *inode) -{ - int status; - struct ocfs2_journal_lock *lock; - - BUG_ON(!inode); - - lock = kmem_cache_alloc(ocfs2_lock_cache, GFP_NOFS); - if (!lock) { - status = -ENOMEM; - mlog_errno(-ENOMEM); - goto bail; - } - - if (!igrab(inode)) - BUG(); - lock->jl_inode = inode; - - list_add_tail(&(lock->jl_lock_list), &(handle->locks)); - handle->num_locks++; - - status = 0; -bail: - mlog_exit(status); - return status; -} - -static void ocfs2_handle_cleanup_locks(struct ocfs2_journal *journal, - struct ocfs2_journal_handle *handle) -{ - struct list_head *p, *n; - struct ocfs2_journal_lock *lock; - struct inode *inode; - - list_for_each_safe(p, n, &(handle->locks)) { - lock = list_entry(p, struct ocfs2_journal_lock, - jl_lock_list); - list_del(&lock->jl_lock_list); - handle->num_locks--; - - inode = lock->jl_inode; - ocfs2_meta_unlock(inode, 1); - if (atomic_read(&inode->i_count) == 1) - mlog(ML_ERROR, - "Inode %llu, I'm doing a last iput for!", - (unsigned long long)OCFS2_I(inode)->ip_blkno); - iput(inode); - kmem_cache_free(ocfs2_lock_cache, lock); - } -} - #define OCFS2_DEFAULT_COMMIT_INTERVAL (HZ * 5) void ocfs2_set_journal_params(struct ocfs2_super *osb) @@ -562,8 +358,7 @@ int ocfs2_journal_init(struct ocfs2_jour /* Skip recovery waits here - journal inode metadata never * changes in a live cluster so it can be considered an * exception to the rule. */ - status = ocfs2_meta_lock_full(inode, NULL, &bh, 1, - OCFS2_META_LOCK_RECOVERY); + status = ocfs2_meta_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY); if (status < 0) { if (status != -ERESTARTSYS) mlog(ML_ERROR, "Could not get lock on journal!\n"); @@ -1160,8 +955,7 @@ static int ocfs2_replay_journal(struct o } SET_INODE_JOURNAL(inode); - status = ocfs2_meta_lock_full(inode, NULL, &bh, 1, - OCFS2_META_LOCK_RECOVERY); + status = ocfs2_meta_lock_full(inode, &bh, 1, OCFS2_META_LOCK_RECOVERY); if (status < 0) { mlog(0, "status returned from ocfs2_meta_lock=%d\n", status); if (status != -ERESTARTSYS) @@ -1350,7 +1144,7 @@ static int ocfs2_trylock_journal(struct SET_INODE_JOURNAL(inode); flags = OCFS2_META_LOCK_RECOVERY | OCFS2_META_LOCK_NOQUEUE; - status = ocfs2_meta_lock_full(inode, NULL, NULL, 1, flags); + status = ocfs2_meta_lock_full(inode, NULL, 1, flags); if (status < 0) { if (status != -EAGAIN) mlog_errno(status); @@ -1433,7 +1227,7 @@ static int ocfs2_queue_orphans(struct oc } mutex_lock(&orphan_dir_inode->i_mutex); - status = ocfs2_meta_lock(orphan_dir_inode, NULL, NULL, 0); + status = ocfs2_meta_lock(orphan_dir_inode, NULL, 0); if (status < 0) { mlog_errno(status); goto out; diff --git a/fs/ocfs2/journal.h b/fs/ocfs2/journal.h index 2f3a6ac..d86cb96 100644 --- a/fs/ocfs2/journal.h +++ b/fs/ocfs2/journal.h @@ -37,7 +37,6 @@ enum ocfs2_journal_state { struct ocfs2_super; struct ocfs2_dinode; -struct ocfs2_journal_handle; struct ocfs2_journal { enum ocfs2_journal_state j_state; /* Journals current state */ @@ -133,44 +132,6 @@ static inline void ocfs2_inode_set_new(s spin_unlock(&trans_inc_lock); } -extern kmem_cache_t *ocfs2_lock_cache; - -struct ocfs2_journal_lock { - struct inode *jl_inode; - struct list_head jl_lock_list; -}; - -struct ocfs2_journal_handle { - handle_t *k_handle; /* kernel handle. */ - struct ocfs2_journal *journal; - u32 flags; /* see flags below. */ - int max_buffs; /* Buffs reserved by this handle */ - - /* The following two fields are for ocfs2_handle_add_lock */ - int num_locks; - struct list_head locks; /* A bunch of locks to - * release on commit. This - * should be a list_head */ - - struct list_head inode_list; -}; - -#define OCFS2_HANDLE_STARTED 1 -/* should we sync-commit this handle? */ -#define OCFS2_HANDLE_SYNC 2 -static inline int ocfs2_handle_started(struct ocfs2_journal_handle *handle) -{ - return handle->flags & OCFS2_HANDLE_STARTED; -} - -static inline void ocfs2_handle_set_sync(struct ocfs2_journal_handle *handle, int sync) -{ - if (sync) - handle->flags |= OCFS2_HANDLE_SYNC; - else - handle->flags &= ~OCFS2_HANDLE_SYNC; -} - /* Exported only for the journal struct init code in super.c. Do not call. */ void ocfs2_complete_recovery(void *data); @@ -231,15 +192,14 @@ static inline void ocfs2_checkpoint_inod * Transaction Handling: * Manage the lifetime of a transaction handle. * - * ocfs2_alloc_handle - Only allocate a handle so we can start putting - * cluster locks on it. To actually change blocks, - * call ocfs2_start_trans with the handle returned - * from this function. You may call ocfs2_commit_trans - * at any time in the lifetime of a handle. * ocfs2_start_trans - Begin a transaction. Give it an upper estimate of * the number of blocks that will be changed during * this handle. - * ocfs2_commit_trans - Complete a handle. + * ocfs2_commit_trans - Complete a handle. It might return -EIO if + * the journal was aborted. The majority of paths don't + * check the return value as an error there comes too + * late to do anything (and will be picked up in a + * later transaction). * ocfs2_extend_trans - Extend a handle by nblocks credits. This may * commit the handle to disk in the process, but will * not release any locks taken during the transaction. @@ -249,24 +209,16 @@ static inline void ocfs2_checkpoint_inod * ocfs2_journal_dirty - Mark a journalled buffer as having dirty data. * ocfs2_journal_dirty_data - Indicate that a data buffer should go out before * the current handle commits. - * ocfs2_handle_add_lock - Sometimes we need to delay lock release - * until after a transaction has been completed. Use - * ocfs2_handle_add_lock to indicate that a lock needs - * to be released at the end of that handle. Locks - * will be released in the order that they are added. - * ocfs2_handle_add_inode - Add a locked inode to a transaction. */ /* You must always start_trans with a number of buffs > 0, but it's * perfectly legal to go through an entire transaction without having * dirtied any buffers. */ -struct ocfs2_journal_handle *ocfs2_alloc_handle(struct ocfs2_super *osb); -struct ocfs2_journal_handle *ocfs2_start_trans(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, +handle_t *ocfs2_start_trans(struct ocfs2_super *osb, int max_buffs); -void ocfs2_commit_trans(struct ocfs2_journal_handle *handle); -int ocfs2_extend_trans(struct ocfs2_journal_handle *handle, - int nblocks); +int ocfs2_commit_trans(struct ocfs2_super *osb, + handle_t *handle); +int ocfs2_extend_trans(handle_t *handle, int nblocks); /* * Create access is for when we get a newly created buffer and we're @@ -283,7 +235,7 @@ #define OCFS2_JOURNAL_ACCESS_CREATE 0 #define OCFS2_JOURNAL_ACCESS_WRITE 1 #define OCFS2_JOURNAL_ACCESS_UNDO 2 -int ocfs2_journal_access(struct ocfs2_journal_handle *handle, +int ocfs2_journal_access(handle_t *handle, struct inode *inode, struct buffer_head *bh, int type); @@ -306,18 +258,10 @@ int ocfs2_journal_acces * * ocfs2_journal_dirty(handle, bh); */ -int ocfs2_journal_dirty(struct ocfs2_journal_handle *handle, +int ocfs2_journal_dirty(handle_t *handle, struct buffer_head *bh); int ocfs2_journal_dirty_data(handle_t *handle, struct buffer_head *bh); -int ocfs2_handle_add_lock(struct ocfs2_journal_handle *handle, - struct inode *inode); -/* - * Use this to protect from other processes reading buffer state while - * it's in flight. - */ -void ocfs2_handle_add_inode(struct ocfs2_journal_handle *handle, - struct inode *inode); /* * Credit Macros: diff --git a/fs/ocfs2/localalloc.c b/fs/ocfs2/localalloc.c index 1f17a4d..698d79a 100644 --- a/fs/ocfs2/localalloc.c +++ b/fs/ocfs2/localalloc.c @@ -58,19 +58,18 @@ static int ocfs2_local_alloc_find_clear_ static void ocfs2_clear_local_alloc(struct ocfs2_dinode *alloc); static int ocfs2_sync_local_to_main(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct ocfs2_dinode *alloc, struct inode *main_bm_inode, struct buffer_head *main_bm_bh); static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, struct ocfs2_alloc_context **ac, struct inode **bitmap_inode, struct buffer_head **bitmap_bh); static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct ocfs2_alloc_context *ac); static int ocfs2_local_alloc_slide_window(struct ocfs2_super *osb, @@ -196,7 +195,7 @@ bail: void ocfs2_shutdown_local_alloc(struct ocfs2_super *osb) { int status; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle; struct inode *local_alloc_inode = NULL; struct buffer_head *bh = NULL; struct buffer_head *main_bm_bh = NULL; @@ -207,7 +206,7 @@ void ocfs2_shutdown_local_alloc(struct o mlog_entry_void(); if (osb->local_alloc_state == OCFS2_LA_UNUSED) - goto bail; + goto out; local_alloc_inode = ocfs2_get_system_file_inode(osb, @@ -216,40 +215,34 @@ void ocfs2_shutdown_local_alloc(struct o if (!local_alloc_inode) { status = -ENOENT; mlog_errno(status); - goto bail; + goto out; } osb->local_alloc_state = OCFS2_LA_DISABLED; - handle = ocfs2_alloc_handle(osb); - if (!handle) { - status = -ENOMEM; - mlog_errno(status); - goto bail; - } - main_bm_inode = ocfs2_get_system_file_inode(osb, GLOBAL_BITMAP_SYSTEM_INODE, OCFS2_INVALID_SLOT); if (!main_bm_inode) { status = -EINVAL; mlog_errno(status); - goto bail; + goto out; } - ocfs2_handle_add_inode(handle, main_bm_inode); - status = ocfs2_meta_lock(main_bm_inode, handle, &main_bm_bh, 1); + mutex_lock(&main_bm_inode->i_mutex); + + status = ocfs2_meta_lock(main_bm_inode, &main_bm_bh, 1); if (status < 0) { mlog_errno(status); - goto bail; + goto out_mutex; } /* WINDOW_MOVE_CREDITS is a bit heavy... */ - handle = ocfs2_start_trans(osb, handle, OCFS2_WINDOW_MOVE_CREDITS); + handle = ocfs2_start_trans(osb, OCFS2_WINDOW_MOVE_CREDITS); if (IS_ERR(handle)) { mlog_errno(PTR_ERR(handle)); handle = NULL; - goto bail; + goto out_unlock; } bh = osb->local_alloc_bh; @@ -258,7 +251,7 @@ void ocfs2_shutdown_local_alloc(struct o alloc_copy = kmalloc(bh->b_size, GFP_KERNEL); if (!alloc_copy) { status = -ENOMEM; - goto bail; + goto out_commit; } memcpy(alloc_copy, alloc, bh->b_size); @@ -266,7 +259,7 @@ void ocfs2_shutdown_local_alloc(struct o OCFS2_JOURNAL_ACCESS_WRITE); if (status < 0) { mlog_errno(status); - goto bail; + goto out_commit; } ocfs2_clear_local_alloc(alloc); @@ -274,7 +267,7 @@ void ocfs2_shutdown_local_alloc(struct o status = ocfs2_journal_dirty(handle, bh); if (status < 0) { mlog_errno(status); - goto bail; + goto out_commit; } brelse(bh); @@ -286,16 +279,20 @@ void ocfs2_shutdown_local_alloc(struct o if (status < 0) mlog_errno(status); -bail: - if (handle) - ocfs2_commit_trans(handle); +out_commit: + ocfs2_commit_trans(osb, handle); +out_unlock: if (main_bm_bh) brelse(main_bm_bh); - if (main_bm_inode) - iput(main_bm_inode); + ocfs2_meta_unlock(main_bm_inode, 1); +out_mutex: + mutex_unlock(&main_bm_inode->i_mutex); + iput(main_bm_inode); + +out: if (local_alloc_inode) iput(local_alloc_inode); @@ -385,61 +382,59 @@ int ocfs2_complete_local_alloc_recovery( struct ocfs2_dinode *alloc) { int status; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle; struct buffer_head *main_bm_bh = NULL; - struct inode *main_bm_inode = NULL; + struct inode *main_bm_inode; mlog_entry_void(); - handle = ocfs2_alloc_handle(osb); - if (!handle) { - status = -ENOMEM; - mlog_errno(status); - goto bail; - } - main_bm_inode = ocfs2_get_system_file_inode(osb, GLOBAL_BITMAP_SYSTEM_INODE, OCFS2_INVALID_SLOT); if (!main_bm_inode) { status = -EINVAL; mlog_errno(status); - goto bail; + goto out; } - ocfs2_handle_add_inode(handle, main_bm_inode); - status = ocfs2_meta_lock(main_bm_inode, handle, &main_bm_bh, 1); + mutex_lock(&main_bm_inode->i_mutex); + + status = ocfs2_meta_lock(main_bm_inode, &main_bm_bh, 1); if (status < 0) { mlog_errno(status); - goto bail; + goto out_mutex; } - handle = ocfs2_start_trans(osb, handle, OCFS2_WINDOW_MOVE_CREDITS); + handle = ocfs2_start_trans(osb, OCFS2_WINDOW_MOVE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; mlog_errno(status); - goto bail; + goto out_unlock; } /* we want the bitmap change to be recorded on disk asap */ - ocfs2_handle_set_sync(handle, 1); + handle->h_sync = 1; status = ocfs2_sync_local_to_main(osb, handle, alloc, main_bm_inode, main_bm_bh); if (status < 0) mlog_errno(status); -bail: - if (handle) - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); + +out_unlock: + ocfs2_meta_unlock(main_bm_inode, 1); + +out_mutex: + mutex_unlock(&main_bm_inode->i_mutex); if (main_bm_bh) brelse(main_bm_bh); - if (main_bm_inode) - iput(main_bm_inode); + iput(main_bm_inode); +out: mlog_exit(status); return status; } @@ -452,7 +447,6 @@ bail: * our own in order to shift windows. */ int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb, - struct ocfs2_journal_handle *passed_handle, u32 bits_wanted, struct ocfs2_alloc_context *ac) { @@ -463,9 +457,7 @@ int ocfs2_reserve_local_alloc_bits(struc mlog_entry_void(); - BUG_ON(!passed_handle); BUG_ON(!ac); - BUG_ON(passed_handle->flags & OCFS2_HANDLE_STARTED); local_alloc_inode = ocfs2_get_system_file_inode(osb, @@ -476,7 +468,11 @@ int ocfs2_reserve_local_alloc_bits(struc mlog_errno(status); goto bail; } - ocfs2_handle_add_inode(passed_handle, local_alloc_inode); + + mutex_lock(&local_alloc_inode->i_mutex); + + ac->ac_inode = local_alloc_inode; + ac->ac_which = OCFS2_AC_USE_LOCAL; if (osb->local_alloc_state != OCFS2_LA_ENABLED) { status = -ENOSPC; @@ -515,21 +511,17 @@ int ocfs2_reserve_local_alloc_bits(struc } } - ac->ac_inode = igrab(local_alloc_inode); get_bh(osb->local_alloc_bh); ac->ac_bh = osb->local_alloc_bh; - ac->ac_which = OCFS2_AC_USE_LOCAL; status = 0; bail: - if (local_alloc_inode) - iput(local_alloc_inode); mlog_exit(status); return status; } int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct ocfs2_alloc_context *ac, u32 min_bits, u32 *bit_off, @@ -707,7 +699,7 @@ #endif * passed is used for caching. */ static int ocfs2_sync_local_to_main(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct ocfs2_dinode *alloc, struct inode *main_bm_inode, struct buffer_head *main_bm_bh) @@ -778,7 +770,6 @@ bail: } static int ocfs2_local_alloc_reserve_for_window(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, struct ocfs2_alloc_context **ac, struct inode **bitmap_inode, struct buffer_head **bitmap_bh) @@ -792,7 +783,6 @@ static int ocfs2_local_alloc_reserve_for goto bail; } - (*ac)->ac_handle = handle; (*ac)->ac_bits_wanted = ocfs2_local_alloc_window_bits(osb); status = ocfs2_reserve_cluster_bitmap_bits(osb, *ac); @@ -821,7 +811,7 @@ bail: * pass it the bitmap lock in lock_bh if you have it. */ static int ocfs2_local_alloc_new_window(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct ocfs2_alloc_context *ac) { int status = 0; @@ -888,23 +878,15 @@ static int ocfs2_local_alloc_slide_windo int status = 0; struct buffer_head *main_bm_bh = NULL; struct inode *main_bm_inode = NULL; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; struct ocfs2_dinode *alloc; struct ocfs2_dinode *alloc_copy = NULL; struct ocfs2_alloc_context *ac = NULL; mlog_entry_void(); - handle = ocfs2_alloc_handle(osb); - if (!handle) { - status = -ENOMEM; - mlog_errno(status); - goto bail; - } - /* This will lock the main bitmap for us. */ status = ocfs2_local_alloc_reserve_for_window(osb, - handle, &ac, &main_bm_inode, &main_bm_bh); @@ -914,7 +896,7 @@ static int ocfs2_local_alloc_slide_windo goto bail; } - handle = ocfs2_start_trans(osb, handle, OCFS2_WINDOW_MOVE_CREDITS); + handle = ocfs2_start_trans(osb, OCFS2_WINDOW_MOVE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; @@ -972,7 +954,7 @@ static int ocfs2_local_alloc_slide_windo status = 0; bail: if (handle) - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); if (main_bm_bh) brelse(main_bm_bh); diff --git a/fs/ocfs2/localalloc.h b/fs/ocfs2/localalloc.h index 30f88ce..385a101 100644 --- a/fs/ocfs2/localalloc.h +++ b/fs/ocfs2/localalloc.h @@ -42,12 +42,11 @@ int ocfs2_alloc_should_use_local(struct struct ocfs2_alloc_context; int ocfs2_reserve_local_alloc_bits(struct ocfs2_super *osb, - struct ocfs2_journal_handle *passed_handle, u32 bits_wanted, struct ocfs2_alloc_context *ac); int ocfs2_claim_local_alloc_bits(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct ocfs2_alloc_context *ac, u32 min_bits, u32 *bit_off, diff --git a/fs/ocfs2/mmap.c b/fs/ocfs2/mmap.c index 83934e3..69f85ae 100644 --- a/fs/ocfs2/mmap.c +++ b/fs/ocfs2/mmap.c @@ -82,6 +82,8 @@ static struct vm_operations_struct ocfs2 int ocfs2_mmap(struct file *file, struct vm_area_struct *vma) { + int ret = 0, lock_level = 0; + /* We don't want to support shared writable mappings yet. */ if (((vma->vm_flags & VM_SHARED) || (vma->vm_flags & VM_MAYSHARE)) && ((vma->vm_flags & VM_WRITE) || (vma->vm_flags & VM_MAYWRITE))) { @@ -91,7 +93,14 @@ int ocfs2_mmap(struct file *file, struct return -EINVAL; } - file_accessed(file); + ret = ocfs2_meta_lock_atime(file->f_dentry->d_inode, + file->f_vfsmnt, &lock_level); + if (ret < 0) { + mlog_errno(ret); + goto out; + } + ocfs2_meta_unlock(file->f_dentry->d_inode, lock_level); +out: vma->vm_ops = &ocfs2_file_vm_ops; return 0; } diff --git a/fs/ocfs2/namei.c b/fs/ocfs2/namei.c index a57b751..21db45d 100644 --- a/fs/ocfs2/namei.c +++ b/fs/ocfs2/namei.c @@ -75,12 +75,12 @@ static int inline ocfs2_search_dirblock( unsigned long offset, struct ocfs2_dir_entry **res_dir); -static int ocfs2_delete_entry(struct ocfs2_journal_handle *handle, +static int ocfs2_delete_entry(handle_t *handle, struct inode *dir, struct ocfs2_dir_entry *de_del, struct buffer_head *bh); -static int __ocfs2_add_entry(struct ocfs2_journal_handle *handle, +static int __ocfs2_add_entry(handle_t *handle, struct inode *dir, const char *name, int namelen, struct inode *inode, u64 blkno, @@ -93,43 +93,37 @@ static int ocfs2_mknod_locked(struct ocf dev_t dev, struct buffer_head **new_fe_bh, struct buffer_head *parent_fe_bh, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode **ret_inode, struct ocfs2_alloc_context *inode_ac); static int ocfs2_fill_new_dir(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *parent, struct inode *inode, struct buffer_head *fe_bh, struct ocfs2_alloc_context *data_ac); -static int ocfs2_double_lock(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, - struct buffer_head **bh1, - struct inode *inode1, - struct buffer_head **bh2, - struct inode *inode2); - static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + struct inode **ret_orphan_dir, struct inode *inode, char *name, struct buffer_head **de_bh); static int ocfs2_orphan_add(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *inode, struct ocfs2_dinode *fe, char *name, - struct buffer_head *de_bh); + struct buffer_head *de_bh, + struct inode *orphan_dir_inode); static int ocfs2_create_symlink_data(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *inode, const char *symname); -static inline int ocfs2_add_entry(struct ocfs2_journal_handle *handle, +static inline int ocfs2_add_entry(handle_t *handle, struct dentry *dentry, struct inode *inode, u64 blkno, struct buffer_head *parent_fe_bh, @@ -165,7 +159,7 @@ static struct dentry *ocfs2_lookup(struc mlog(0, "find name %.*s in directory %llu\n", dentry->d_name.len, dentry->d_name.name, (unsigned long long)OCFS2_I(dir)->ip_blkno); - status = ocfs2_meta_lock(dir, NULL, NULL, 0); + status = ocfs2_meta_lock(dir, NULL, 0); if (status < 0) { if (status != -ENOENT) mlog_errno(status); @@ -242,7 +236,7 @@ bail: } static int ocfs2_fill_new_dir(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *parent, struct inode *inode, struct buffer_head *fe_bh, @@ -317,7 +311,7 @@ static int ocfs2_mknod(struct inode *dir { int status = 0; struct buffer_head *parent_fe_bh = NULL; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; struct ocfs2_super *osb; struct ocfs2_dinode *dirfe; struct buffer_head *new_fe_bh = NULL; @@ -333,18 +327,11 @@ static int ocfs2_mknod(struct inode *dir /* get our super block */ osb = OCFS2_SB(dir->i_sb); - handle = ocfs2_alloc_handle(osb); - if (handle == NULL) { - status = -ENOMEM; - mlog_errno(status); - goto leave; - } - - status = ocfs2_meta_lock(dir, handle, &parent_fe_bh, 1); + status = ocfs2_meta_lock(dir, &parent_fe_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); - goto leave; + return status; } if (S_ISDIR(mode) && (dir->i_nlink >= OCFS2_LINK_MAX)) { @@ -374,7 +361,7 @@ static int ocfs2_mknod(struct inode *dir } /* reserve an inode spot */ - status = ocfs2_reserve_new_inode(osb, handle, &inode_ac); + status = ocfs2_reserve_new_inode(osb, &inode_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); @@ -384,7 +371,7 @@ static int ocfs2_mknod(struct inode *dir /* are we making a directory? If so, reserve a cluster for his * 1st extent. */ if (S_ISDIR(mode)) { - status = ocfs2_reserve_clusters(osb, handle, 1, &data_ac); + status = ocfs2_reserve_clusters(osb, 1, &data_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); @@ -392,7 +379,7 @@ static int ocfs2_mknod(struct inode *dir } } - handle = ocfs2_start_trans(osb, handle, OCFS2_MKNOD_CREDITS); + handle = ocfs2_start_trans(osb, OCFS2_MKNOD_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; @@ -453,7 +440,9 @@ static int ocfs2_mknod(struct inode *dir status = 0; leave: if (handle) - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); + + ocfs2_meta_unlock(dir, 1); if (status == -ENOSPC) mlog(0, "Disk is full\n"); @@ -487,7 +476,7 @@ static int ocfs2_mknod_locked(struct ocf dev_t dev, struct buffer_head **new_fe_bh, struct buffer_head *parent_fe_bh, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode **ret_inode, struct ocfs2_alloc_context *inode_ac) { @@ -653,7 +642,7 @@ static int ocfs2_link(struct dentry *old struct inode *dir, struct dentry *dentry) { - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle; struct inode *inode = old_dentry->d_inode; int err; struct buffer_head *fe_bh = NULL; @@ -666,68 +655,60 @@ static int ocfs2_link(struct dentry *old old_dentry->d_name.len, old_dentry->d_name.name, dentry->d_name.len, dentry->d_name.name); - if (S_ISDIR(inode->i_mode)) { - err = -EPERM; - goto bail; - } - - handle = ocfs2_alloc_handle(osb); - if (handle == NULL) { - err = -ENOMEM; - goto bail; - } + if (S_ISDIR(inode->i_mode)) + return -EPERM; - err = ocfs2_meta_lock(dir, handle, &parent_fe_bh, 1); + err = ocfs2_meta_lock(dir, &parent_fe_bh, 1); if (err < 0) { if (err != -ENOENT) mlog_errno(err); - goto bail; + return err; } if (!dir->i_nlink) { err = -ENOENT; - goto bail; + goto out; } err = ocfs2_check_dir_for_entry(dir, dentry->d_name.name, dentry->d_name.len); if (err) - goto bail; + goto out; err = ocfs2_prepare_dir_for_insert(osb, dir, parent_fe_bh, dentry->d_name.name, dentry->d_name.len, &de_bh); if (err < 0) { mlog_errno(err); - goto bail; + goto out; } - err = ocfs2_meta_lock(inode, handle, &fe_bh, 1); + err = ocfs2_meta_lock(inode, &fe_bh, 1); if (err < 0) { if (err != -ENOENT) mlog_errno(err); - goto bail; + goto out; } fe = (struct ocfs2_dinode *) fe_bh->b_data; if (le16_to_cpu(fe->i_links_count) >= OCFS2_LINK_MAX) { err = -EMLINK; - goto bail; + goto out_unlock_inode; } - handle = ocfs2_start_trans(osb, handle, OCFS2_LINK_CREDITS); + handle = ocfs2_start_trans(osb, OCFS2_LINK_CREDITS); if (IS_ERR(handle)) { err = PTR_ERR(handle); handle = NULL; mlog_errno(err); - goto bail; + goto out_unlock_inode; } err = ocfs2_journal_access(handle, inode, fe_bh, OCFS2_JOURNAL_ACCESS_WRITE); if (err < 0) { mlog_errno(err); - goto bail; + goto out_commit; } inc_nlink(inode); @@ -741,7 +722,7 @@ static int ocfs2_link(struct dentry *old le16_add_cpu(&fe->i_links_count, -1); drop_nlink(inode); mlog_errno(err); - goto bail; + goto out_commit; } err = ocfs2_add_entry(handle, dentry, inode, @@ -751,21 +732,27 @@ static int ocfs2_link(struct dentry *old le16_add_cpu(&fe->i_links_count, -1); drop_nlink(inode); mlog_errno(err); - goto bail; + goto out_commit; } err = ocfs2_dentry_attach_lock(dentry, inode, OCFS2_I(dir)->ip_blkno); if (err) { mlog_errno(err); - goto bail; + goto out_commit; } atomic_inc(&inode->i_count); dentry->d_op = &ocfs2_dentry_ops; d_instantiate(dentry, inode); -bail: - if (handle) - ocfs2_commit_trans(handle); + +out_commit: + ocfs2_commit_trans(osb, handle); +out_unlock_inode: + ocfs2_meta_unlock(inode, 1); + +out: + ocfs2_meta_unlock(dir, 1); + if (de_bh) brelse(de_bh); if (fe_bh) @@ -812,13 +799,15 @@ static int ocfs2_unlink(struct inode *di struct dentry *dentry) { int status; + int child_locked = 0; struct inode *inode = dentry->d_inode; + struct inode *orphan_dir = NULL; struct ocfs2_super *osb = OCFS2_SB(dir->i_sb); u64 blkno; struct ocfs2_dinode *fe = NULL; struct buffer_head *fe_bh = NULL; struct buffer_head *parent_node_bh = NULL; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; struct ocfs2_dir_entry *dirent = NULL; struct buffer_head *dirent_bh = NULL; char orphan_name[OCFS2_ORPHAN_NAMELEN + 1]; @@ -833,22 +822,14 @@ static int ocfs2_unlink(struct inode *di if (inode == osb->root_inode) { mlog(0, "Cannot delete the root directory\n"); - status = -EPERM; - goto leave; + return -EPERM; } - handle = ocfs2_alloc_handle(osb); - if (handle == NULL) { - status = -ENOMEM; - mlog_errno(status); - goto leave; - } - - status = ocfs2_meta_lock(dir, handle, &parent_node_bh, 1); + status = ocfs2_meta_lock(dir, &parent_node_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); - goto leave; + return status; } status = ocfs2_find_files_on_disk(dentry->d_name.name, @@ -869,12 +850,13 @@ static int ocfs2_unlink(struct inode *di goto leave; } - status = ocfs2_meta_lock(inode, handle, &fe_bh, 1); + status = ocfs2_meta_lock(inode, &fe_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); goto leave; } + child_locked = 1; if (S_ISDIR(inode->i_mode)) { if (!ocfs2_empty_dir(inode)) { @@ -895,7 +877,7 @@ static int ocfs2_unlink(struct inode *di } if (inode_is_unlinkable(inode)) { - status = ocfs2_prepare_orphan_dir(osb, handle, inode, + status = ocfs2_prepare_orphan_dir(osb, &orphan_dir, inode, orphan_name, &orphan_entry_bh); if (status < 0) { @@ -904,7 +886,7 @@ static int ocfs2_unlink(struct inode *di } } - handle = ocfs2_start_trans(osb, handle, OCFS2_UNLINK_CREDITS); + handle = ocfs2_start_trans(osb, OCFS2_UNLINK_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; @@ -923,7 +905,7 @@ static int ocfs2_unlink(struct inode *di if (inode_is_unlinkable(inode)) { status = ocfs2_orphan_add(osb, handle, inode, fe, orphan_name, - orphan_entry_bh); + orphan_entry_bh, orphan_dir); if (status < 0) { mlog_errno(status); goto leave; @@ -960,7 +942,19 @@ static int ocfs2_unlink(struct inode *di leave: if (handle) - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); + + if (child_locked) + ocfs2_meta_unlock(inode, 1); + + ocfs2_meta_unlock(dir, 1); + + if (orphan_dir) { + /* This was locked for us in ocfs2_prepare_orphan_dir() */ + ocfs2_meta_unlock(orphan_dir, 1); + mutex_unlock(&orphan_dir->i_mutex); + iput(orphan_dir); + } if (fe_bh) brelse(fe_bh); @@ -984,7 +978,6 @@ leave: * if they have the same id, then the 1st one is the only one locked. */ static int ocfs2_double_lock(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, struct buffer_head **bh1, struct inode *inode1, struct buffer_head **bh2, @@ -1000,8 +993,6 @@ static int ocfs2_double_lock(struct ocfs (unsigned long long)oi1->ip_blkno, (unsigned long long)oi2->ip_blkno); - BUG_ON(!handle); - if (*bh1) *bh1 = NULL; if (*bh2) @@ -1021,25 +1012,41 @@ static int ocfs2_double_lock(struct ocfs inode1 = tmpinode; } /* lock id2 */ - status = ocfs2_meta_lock(inode2, handle, bh2, 1); + status = ocfs2_meta_lock(inode2, bh2, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); goto bail; } } + /* lock id1 */ - status = ocfs2_meta_lock(inode1, handle, bh1, 1); + status = ocfs2_meta_lock(inode1, bh1, 1); if (status < 0) { + /* + * An error return must mean that no cluster locks + * were held on function exit. + */ + if (oi1->ip_blkno != oi2->ip_blkno) + ocfs2_meta_unlock(inode2, 1); + if (status != -ENOENT) mlog_errno(status); - goto bail; } + bail: mlog_exit(status); return status; } +static void ocfs2_double_unlock(struct inode *inode1, struct inode *inode2) +{ + ocfs2_meta_unlock(inode1, 1); + + if (inode1 != inode2) + ocfs2_meta_unlock(inode2, 1); +} + #define PARENT_INO(buffer) \ ((struct ocfs2_dir_entry *) \ ((char *)buffer + \ @@ -1050,9 +1057,11 @@ static int ocfs2_rename(struct inode *ol struct inode *new_dir, struct dentry *new_dentry) { - int status = 0, rename_lock = 0; + int status = 0, rename_lock = 0, parents_locked = 0; + int old_child_locked = 0, new_child_locked = 0; struct inode *old_inode = old_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode; + struct inode *orphan_dir = NULL; struct ocfs2_dinode *newfe = NULL; char orphan_name[OCFS2_ORPHAN_NAMELEN + 1]; struct buffer_head *orphan_entry_bh = NULL; @@ -1060,7 +1069,7 @@ static int ocfs2_rename(struct inode *ol struct buffer_head *insert_entry_bh = NULL; struct ocfs2_super *osb = NULL; u64 newfe_blkno; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; struct buffer_head *old_dir_bh = NULL; struct buffer_head *new_dir_bh = NULL; struct ocfs2_dir_entry *old_de = NULL, *new_de = NULL; // dirent for old_dentry @@ -1105,21 +1114,14 @@ static int ocfs2_rename(struct inode *ol rename_lock = 1; } - handle = ocfs2_alloc_handle(osb); - if (handle == NULL) { - status = -ENOMEM; - mlog_errno(status); - goto bail; - } - /* if old and new are the same, this'll just do one lock. */ - status = ocfs2_double_lock(osb, handle, - &old_dir_bh, old_dir, - &new_dir_bh, new_dir); + status = ocfs2_double_lock(osb, &old_dir_bh, old_dir, + &new_dir_bh, new_dir); if (status < 0) { mlog_errno(status); goto bail; } + parents_locked = 1; /* make sure both dirs have bhs * get an extra ref on old_dir_bh if old==new */ @@ -1140,12 +1142,13 @@ static int ocfs2_rename(struct inode *ol * the vote thread on other nodes won't have to concurrently * downconvert the inode and the dentry locks. */ - status = ocfs2_meta_lock(old_inode, handle, NULL, 1); + status = ocfs2_meta_lock(old_inode, NULL, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); goto bail; } + old_child_locked = 1; status = ocfs2_remote_dentry_delete(old_dentry); if (status < 0) { @@ -1231,12 +1234,13 @@ static int ocfs2_rename(struct inode *ol goto bail; } - status = ocfs2_meta_lock(new_inode, handle, &newfe_bh, 1); + status = ocfs2_meta_lock(new_inode, &newfe_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); goto bail; } + new_child_locked = 1; status = ocfs2_remote_dentry_delete(new_dentry); if (status < 0) { @@ -1252,7 +1256,7 @@ static int ocfs2_rename(struct inode *ol (unsigned long long)newfe_bh->b_blocknr : 0ULL); if (S_ISDIR(new_inode->i_mode) || (new_inode->i_nlink == 1)) { - status = ocfs2_prepare_orphan_dir(osb, handle, + status = ocfs2_prepare_orphan_dir(osb, &orphan_dir, new_inode, orphan_name, &orphan_entry_bh); @@ -1280,7 +1284,7 @@ static int ocfs2_rename(struct inode *ol } } - handle = ocfs2_start_trans(osb, handle, OCFS2_RENAME_CREDITS); + handle = ocfs2_start_trans(osb, OCFS2_RENAME_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; @@ -1307,7 +1311,7 @@ static int ocfs2_rename(struct inode *ol (newfe->i_links_count == cpu_to_le16(1))){ status = ocfs2_orphan_add(osb, handle, new_inode, newfe, orphan_name, - orphan_entry_bh); + orphan_entry_bh, orphan_dir); if (status < 0) { mlog_errno(status); goto bail; @@ -1424,7 +1428,23 @@ bail: ocfs2_rename_unlock(osb); if (handle) - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); + + if (parents_locked) + ocfs2_double_unlock(old_dir, new_dir); + + if (old_child_locked) + ocfs2_meta_unlock(old_inode, 1); + + if (new_child_locked) + ocfs2_meta_unlock(new_inode, 1); + + if (orphan_dir) { + /* This was locked for us in ocfs2_prepare_orphan_dir() */ + ocfs2_meta_unlock(orphan_dir, 1); + mutex_unlock(&orphan_dir->i_mutex); + iput(orphan_dir); + } if (new_inode) sync_mapping_buffers(old_inode->i_mapping); @@ -1458,7 +1478,7 @@ bail: * data, including the null terminator. */ static int ocfs2_create_symlink_data(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *inode, const char *symname) { @@ -1573,7 +1593,7 @@ static int ocfs2_symlink(struct inode *d struct buffer_head *parent_fe_bh = NULL; struct ocfs2_dinode *fe = NULL; struct ocfs2_dinode *dirfe; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; struct ocfs2_alloc_context *inode_ac = NULL; struct ocfs2_alloc_context *data_ac = NULL; @@ -1587,19 +1607,12 @@ static int ocfs2_symlink(struct inode *d credits = ocfs2_calc_symlink_credits(sb); - handle = ocfs2_alloc_handle(osb); - if (handle == NULL) { - status = -ENOMEM; - mlog_errno(status); - goto bail; - } - /* lock the parent directory */ - status = ocfs2_meta_lock(dir, handle, &parent_fe_bh, 1); + status = ocfs2_meta_lock(dir, &parent_fe_bh, 1); if (status < 0) { if (status != -ENOENT) mlog_errno(status); - goto bail; + return status; } dirfe = (struct ocfs2_dinode *) parent_fe_bh->b_data; @@ -1622,7 +1635,7 @@ static int ocfs2_symlink(struct inode *d goto bail; } - status = ocfs2_reserve_new_inode(osb, handle, &inode_ac); + status = ocfs2_reserve_new_inode(osb, &inode_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); @@ -1631,7 +1644,7 @@ static int ocfs2_symlink(struct inode *d /* don't reserve bitmap space for fast symlinks. */ if (l > ocfs2_fast_symlink_chars(sb)) { - status = ocfs2_reserve_clusters(osb, handle, 1, &data_ac); + status = ocfs2_reserve_clusters(osb, 1, &data_ac); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); @@ -1639,7 +1652,7 @@ static int ocfs2_symlink(struct inode *d } } - handle = ocfs2_start_trans(osb, handle, credits); + handle = ocfs2_start_trans(osb, credits); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; @@ -1717,7 +1730,10 @@ static int ocfs2_symlink(struct inode *d d_instantiate(dentry, inode); bail: if (handle) - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); + + ocfs2_meta_unlock(dir, 1); + if (new_fe_bh) brelse(new_fe_bh); if (parent_fe_bh) @@ -1768,7 +1784,7 @@ int ocfs2_check_dir_entry(struct inode * * If you pass me insert_bh, I'll skip the search of the other dir * blocks and put the record in there. */ -static int __ocfs2_add_entry(struct ocfs2_journal_handle *handle, +static int __ocfs2_add_entry(handle_t *handle, struct inode *dir, const char *name, int namelen, struct inode *inode, u64 blkno, @@ -1854,7 +1870,7 @@ bail: * ocfs2_delete_entry deletes a directory entry by merging it with the * previous entry */ -static int ocfs2_delete_entry(struct ocfs2_journal_handle *handle, +static int ocfs2_delete_entry(handle_t *handle, struct inode *dir, struct ocfs2_dir_entry *de_del, struct buffer_head *bh) @@ -2085,19 +2101,19 @@ bail: } static int ocfs2_prepare_orphan_dir(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + struct inode **ret_orphan_dir, struct inode *inode, char *name, struct buffer_head **de_bh) { - struct inode *orphan_dir_inode = NULL; + struct inode *orphan_dir_inode; struct buffer_head *orphan_dir_bh = NULL; int status = 0; status = ocfs2_blkno_stringify(OCFS2_I(inode)->ip_blkno, name); if (status < 0) { mlog_errno(status); - goto leave; + return status; } orphan_dir_inode = ocfs2_get_system_file_inode(osb, @@ -2106,11 +2122,12 @@ static int ocfs2_prepare_orphan_dir(stru if (!orphan_dir_inode) { status = -ENOENT; mlog_errno(status); - goto leave; + return status; } - ocfs2_handle_add_inode(handle, orphan_dir_inode); - status = ocfs2_meta_lock(orphan_dir_inode, handle, &orphan_dir_bh, 1); + mutex_lock(&orphan_dir_inode->i_mutex); + + status = ocfs2_meta_lock(orphan_dir_inode, &orphan_dir_bh, 1); if (status < 0) { mlog_errno(status); goto leave; @@ -2120,13 +2137,19 @@ static int ocfs2_prepare_orphan_dir(stru orphan_dir_bh, name, OCFS2_ORPHAN_NAMELEN, de_bh); if (status < 0) { + ocfs2_meta_unlock(orphan_dir_inode, 1); + mlog_errno(status); goto leave; } + *ret_orphan_dir = orphan_dir_inode; + leave: - if (orphan_dir_inode) + if (status) { + mutex_unlock(&orphan_dir_inode->i_mutex); iput(orphan_dir_inode); + } if (orphan_dir_bh) brelse(orphan_dir_bh); @@ -2136,28 +2159,19 @@ leave: } static int ocfs2_orphan_add(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *inode, struct ocfs2_dinode *fe, char *name, - struct buffer_head *de_bh) + struct buffer_head *de_bh, + struct inode *orphan_dir_inode) { - struct inode *orphan_dir_inode = NULL; struct buffer_head *orphan_dir_bh = NULL; int status = 0; struct ocfs2_dinode *orphan_fe; mlog_entry("(inode->i_ino = %lu)\n", inode->i_ino); - orphan_dir_inode = ocfs2_get_system_file_inode(osb, - ORPHAN_DIR_SYSTEM_INODE, - osb->slot_num); - if (!orphan_dir_inode) { - status = -ENOENT; - mlog_errno(status); - goto leave; - } - status = ocfs2_read_block(osb, OCFS2_I(orphan_dir_inode)->ip_blkno, &orphan_dir_bh, OCFS2_BH_CACHED, @@ -2209,9 +2223,6 @@ static int ocfs2_orphan_add(struct ocfs2 (unsigned long long)OCFS2_I(inode)->ip_blkno, osb->slot_num); leave: - if (orphan_dir_inode) - iput(orphan_dir_inode); - if (orphan_dir_bh) brelse(orphan_dir_bh); @@ -2221,7 +2232,7 @@ leave: /* unlike orphan_add, we expect the orphan dir to already be locked here. */ int ocfs2_orphan_del(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *orphan_dir_inode, struct inode *inode, struct buffer_head *orphan_dir_bh) @@ -2300,4 +2311,5 @@ struct inode_operations ocfs2_dir_iops = .rename = ocfs2_rename, .setattr = ocfs2_setattr, .getattr = ocfs2_getattr, + .permission = ocfs2_permission, }; diff --git a/fs/ocfs2/namei.h b/fs/ocfs2/namei.h index deaaa97..8425944 100644 --- a/fs/ocfs2/namei.h +++ b/fs/ocfs2/namei.h @@ -39,7 +39,7 @@ struct buffer_head *ocfs2_find_entry(con struct inode *dir, struct ocfs2_dir_entry **res_dir); int ocfs2_orphan_del(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct inode *orphan_dir_inode, struct inode *inode, struct buffer_head *orphan_dir_bh); diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h index 0462a7f..0788837 100644 --- a/fs/ocfs2/ocfs2.h +++ b/fs/ocfs2/ocfs2.h @@ -34,6 +34,7 @@ #include #include #include #include +#include #include "cluster/nodemanager.h" #include "cluster/heartbeat.h" @@ -179,9 +180,9 @@ enum ocfs2_mount_options #define OCFS2_OSB_SOFT_RO 0x0001 #define OCFS2_OSB_HARD_RO 0x0002 #define OCFS2_OSB_ERROR_FS 0x0004 +#define OCFS2_DEFAULT_ATIME_QUANTUM 60 struct ocfs2_journal; -struct ocfs2_journal_handle; struct ocfs2_super { struct task_struct *commit_task; @@ -218,6 +219,7 @@ struct ocfs2_super unsigned long osb_flags; unsigned long s_mount_opt; + unsigned int s_atime_quantum; u16 max_slots; s16 node_num; diff --git a/fs/ocfs2/suballoc.c b/fs/ocfs2/suballoc.c index 9d91e66..000d71c 100644 --- a/fs/ocfs2/suballoc.c +++ b/fs/ocfs2/suballoc.c @@ -49,7 +49,7 @@ #include "buffer_head_io.h" static inline void ocfs2_debug_bg(struct ocfs2_group_desc *bg); static inline void ocfs2_debug_suballoc_inode(struct ocfs2_dinode *fe); static inline u16 ocfs2_find_victim_chain(struct ocfs2_chain_list *cl); -static int ocfs2_block_group_fill(struct ocfs2_journal_handle *handle, +static int ocfs2_block_group_fill(handle_t *handle, struct inode *alloc_inode, struct buffer_head *bg_bh, u64 group_blkno, @@ -59,9 +59,6 @@ static int ocfs2_block_group_alloc(struc struct inode *alloc_inode, struct buffer_head *bh); -static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb, - struct ocfs2_alloc_context *ac); - static int ocfs2_cluster_group_search(struct inode *inode, struct buffer_head *group_bh, u32 bits_wanted, u32 min_bits, @@ -72,6 +69,7 @@ static int ocfs2_block_group_search(stru u16 *bit_off, u16 *bits_found); static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb, struct ocfs2_alloc_context *ac, + handle_t *handle, u32 bits_wanted, u32 min_bits, u16 *bit_off, @@ -79,20 +77,20 @@ static int ocfs2_claim_suballoc_bits(str u64 *bg_blkno); static int ocfs2_test_bg_bit_allocatable(struct buffer_head *bg_bh, int nr); -static inline int ocfs2_block_group_set_bits(struct ocfs2_journal_handle *handle, +static inline int ocfs2_block_group_set_bits(handle_t *handle, struct inode *alloc_inode, struct ocfs2_group_desc *bg, struct buffer_head *group_bh, unsigned int bit_off, unsigned int num_bits); -static inline int ocfs2_block_group_clear_bits(struct ocfs2_journal_handle *handle, +static inline int ocfs2_block_group_clear_bits(handle_t *handle, struct inode *alloc_inode, struct ocfs2_group_desc *bg, struct buffer_head *group_bh, unsigned int bit_off, unsigned int num_bits); -static int ocfs2_relink_block_group(struct ocfs2_journal_handle *handle, +static int ocfs2_relink_block_group(handle_t *handle, struct inode *alloc_inode, struct buffer_head *fe_bh, struct buffer_head *bg_bh, @@ -100,7 +98,7 @@ static int ocfs2_relink_block_group(stru u16 chain); static inline int ocfs2_block_group_reasonably_empty(struct ocfs2_group_desc *bg, u32 wanted); -static int ocfs2_free_suballoc_bits(struct ocfs2_journal_handle *handle, +static int ocfs2_free_suballoc_bits(handle_t *handle, struct inode *alloc_inode, struct buffer_head *alloc_bh, unsigned int start_bit, @@ -120,8 +118,16 @@ static inline void ocfs2_block_to_cluste void ocfs2_free_alloc_context(struct ocfs2_alloc_context *ac) { - if (ac->ac_inode) - iput(ac->ac_inode); + struct inode *inode = ac->ac_inode; + + if (inode) { + if (ac->ac_which != OCFS2_AC_USE_LOCAL) + ocfs2_meta_unlock(inode, 1); + + mutex_unlock(&inode->i_mutex); + + iput(inode); + } if (ac->ac_bh) brelse(ac->ac_bh); kfree(ac); @@ -190,7 +196,7 @@ static int ocfs2_check_group_descriptor( return 0; } -static int ocfs2_block_group_fill(struct ocfs2_journal_handle *handle, +static int ocfs2_block_group_fill(handle_t *handle, struct inode *alloc_inode, struct buffer_head *bg_bh, u64 group_blkno, @@ -273,7 +279,7 @@ static int ocfs2_block_group_alloc(struc struct ocfs2_dinode *fe = (struct ocfs2_dinode *) bh->b_data; struct ocfs2_chain_list *cl; struct ocfs2_alloc_context *ac = NULL; - struct ocfs2_journal_handle *handle = NULL; + handle_t *handle = NULL; u32 bit_off, num_bits; u16 alloc_rec; u64 bg_blkno; @@ -284,16 +290,8 @@ static int ocfs2_block_group_alloc(struc mlog_entry_void(); - handle = ocfs2_alloc_handle(osb); - if (!handle) { - status = -ENOMEM; - mlog_errno(status); - goto bail; - } - cl = &fe->id2.i_chain; status = ocfs2_reserve_clusters(osb, - handle, le16_to_cpu(cl->cl_cpg), &ac); if (status < 0) { @@ -304,7 +302,7 @@ static int ocfs2_block_group_alloc(struc credits = ocfs2_calc_group_alloc_credits(osb->sb, le16_to_cpu(cl->cl_cpg)); - handle = ocfs2_start_trans(osb, handle, credits); + handle = ocfs2_start_trans(osb, credits); if (IS_ERR(handle)) { status = PTR_ERR(handle); handle = NULL; @@ -389,7 +387,7 @@ static int ocfs2_block_group_alloc(struc status = 0; bail: if (handle) - ocfs2_commit_trans(handle); + ocfs2_commit_trans(osb, handle); if (ac) ocfs2_free_alloc_context(ac); @@ -402,27 +400,38 @@ bail: } static int ocfs2_reserve_suballoc_bits(struct ocfs2_super *osb, - struct ocfs2_alloc_context *ac) + struct ocfs2_alloc_context *ac, + int type, + u32 slot) { int status; u32 bits_wanted = ac->ac_bits_wanted; - struct inode *alloc_inode = ac->ac_inode; + struct inode *alloc_inode; struct buffer_head *bh = NULL; - struct ocfs2_journal_handle *handle = ac->ac_handle; struct ocfs2_dinode *fe; u32 free_bits; mlog_entry_void(); - BUG_ON(handle->flags & OCFS2_HANDLE_STARTED); + alloc_inode = ocfs2_get_system_file_inode(osb, type, slot); + if (!alloc_inode) { + mlog_errno(-EINVAL); + return -EINVAL; + } - ocfs2_handle_add_inode(handle, alloc_inode); - status = ocfs2_meta_lock(alloc_inode, handle, &bh, 1); + mutex_lock(&alloc_inode->i_mutex); + + status = ocfs2_meta_lock(alloc_inode, &bh, 1); if (status < 0) { + mutex_unlock(&alloc_inode->i_mutex); + iput(alloc_inode); + mlog_errno(status); - goto bail; + return status; } + ac->ac_inode = alloc_inode; + fe = (struct ocfs2_dinode *) bh->b_data; if (!OCFS2_IS_VALID_DINODE(fe)) { OCFS2_RO_ON_INVALID_DINODE(alloc_inode->i_sb, fe); @@ -473,12 +482,11 @@ bail: } int ocfs2_reserve_new_metadata(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, struct ocfs2_dinode *fe, struct ocfs2_alloc_context **ac) { int status; - struct inode *alloc_inode = NULL; + u32 slot; *ac = kcalloc(1, sizeof(struct ocfs2_alloc_context), GFP_KERNEL); if (!(*ac)) { @@ -488,28 +496,18 @@ int ocfs2_reserve_new_metadata(struct oc } (*ac)->ac_bits_wanted = ocfs2_extend_meta_needed(fe); - (*ac)->ac_handle = handle; (*ac)->ac_which = OCFS2_AC_USE_META; #ifndef OCFS2_USE_ALL_METADATA_SUBALLOCATORS - alloc_inode = ocfs2_get_system_file_inode(osb, - EXTENT_ALLOC_SYSTEM_INODE, - 0); + slot = 0; #else - alloc_inode = ocfs2_get_system_file_inode(osb, - EXTENT_ALLOC_SYSTEM_INODE, - osb->slot_num); + slot = osb->slot_num; #endif - if (!alloc_inode) { - status = -ENOMEM; - mlog_errno(status); - goto bail; - } - (*ac)->ac_inode = igrab(alloc_inode); (*ac)->ac_group_search = ocfs2_block_group_search; - status = ocfs2_reserve_suballoc_bits(osb, (*ac)); + status = ocfs2_reserve_suballoc_bits(osb, (*ac), + EXTENT_ALLOC_SYSTEM_INODE, slot); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); @@ -523,19 +521,14 @@ bail: *ac = NULL; } - if (alloc_inode) - iput(alloc_inode); - mlog_exit(status); return status; } int ocfs2_reserve_new_inode(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, struct ocfs2_alloc_context **ac) { int status; - struct inode *alloc_inode = NULL; *ac = kcalloc(1, sizeof(struct ocfs2_alloc_context), GFP_KERNEL); if (!(*ac)) { @@ -545,22 +538,13 @@ int ocfs2_reserve_new_inode(struct ocfs2 } (*ac)->ac_bits_wanted = 1; - (*ac)->ac_handle = handle; (*ac)->ac_which = OCFS2_AC_USE_INODE; - alloc_inode = ocfs2_get_system_file_inode(osb, - INODE_ALLOC_SYSTEM_INODE, - osb->slot_num); - if (!alloc_inode) { - status = -ENOMEM; - mlog_errno(status); - goto bail; - } - - (*ac)->ac_inode = igrab(alloc_inode); (*ac)->ac_group_search = ocfs2_block_group_search; - status = ocfs2_reserve_suballoc_bits(osb, *ac); + status = ocfs2_reserve_suballoc_bits(osb, *ac, + INODE_ALLOC_SYSTEM_INODE, + osb->slot_num); if (status < 0) { if (status != -ENOSPC) mlog_errno(status); @@ -574,9 +558,6 @@ bail: *ac = NULL; } - if (alloc_inode) - iput(alloc_inode); - mlog_exit(status); return status; } @@ -588,20 +569,17 @@ int ocfs2_reserve_cluster_bitmap_bits(st { int status; - ac->ac_inode = ocfs2_get_system_file_inode(osb, - GLOBAL_BITMAP_SYSTEM_INODE, - OCFS2_INVALID_SLOT); - if (!ac->ac_inode) { - status = -EINVAL; - mlog(ML_ERROR, "Could not get bitmap inode!\n"); - goto bail; - } ac->ac_which = OCFS2_AC_USE_MAIN; ac->ac_group_search = ocfs2_cluster_group_search; - status = ocfs2_reserve_suballoc_bits(osb, ac); - if (status < 0 && status != -ENOSPC) + status = ocfs2_reserve_suballoc_bits(osb, ac, + GLOBAL_BITMAP_SYSTEM_INODE, + OCFS2_INVALID_SLOT); + if (status < 0 && status != -ENOSPC) { mlog_errno(status); + goto bail; + } + bail: return status; } @@ -610,7 +588,6 @@ bail: * use so we figure it out for them, but unfortunately this clutters * things a bit. */ int ocfs2_reserve_clusters(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, u32 bits_wanted, struct ocfs2_alloc_context **ac) { @@ -618,8 +595,6 @@ int ocfs2_reserve_clusters(struct ocfs2_ mlog_entry_void(); - BUG_ON(!handle); - *ac = kcalloc(1, sizeof(struct ocfs2_alloc_context), GFP_KERNEL); if (!(*ac)) { status = -ENOMEM; @@ -628,12 +603,10 @@ int ocfs2_reserve_clusters(struct ocfs2_ } (*ac)->ac_bits_wanted = bits_wanted; - (*ac)->ac_handle = handle; status = -ENOSPC; if (ocfs2_alloc_should_use_local(osb, bits_wanted)) { status = ocfs2_reserve_local_alloc_bits(osb, - handle, bits_wanted, *ac); if ((status < 0) && (status != -ENOSPC)) { @@ -774,7 +747,7 @@ static int ocfs2_block_group_find_clear_ return status; } -static inline int ocfs2_block_group_set_bits(struct ocfs2_journal_handle *handle, +static inline int ocfs2_block_group_set_bits(handle_t *handle, struct inode *alloc_inode, struct ocfs2_group_desc *bg, struct buffer_head *group_bh, @@ -845,7 +818,7 @@ static inline u16 ocfs2_find_victim_chai return best; } -static int ocfs2_relink_block_group(struct ocfs2_journal_handle *handle, +static int ocfs2_relink_block_group(handle_t *handle, struct inode *alloc_inode, struct buffer_head *fe_bh, struct buffer_head *bg_bh, @@ -1025,7 +998,7 @@ static int ocfs2_block_group_search(stru } static int ocfs2_alloc_dinode_update_counts(struct inode *inode, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct buffer_head *di_bh, u32 num_bits, u16 chain) @@ -1055,6 +1028,7 @@ out: } static int ocfs2_search_one_group(struct ocfs2_alloc_context *ac, + handle_t *handle, u32 bits_wanted, u32 min_bits, u16 *bit_off, @@ -1067,7 +1041,6 @@ static int ocfs2_search_one_group(struct struct buffer_head *group_bh = NULL; struct ocfs2_group_desc *gd; struct inode *alloc_inode = ac->ac_inode; - struct ocfs2_journal_handle *handle = ac->ac_handle; ret = ocfs2_read_block(OCFS2_SB(alloc_inode->i_sb), gd_blkno, &group_bh, OCFS2_BH_CACHED, alloc_inode); @@ -1115,6 +1088,7 @@ out: } static int ocfs2_search_chain(struct ocfs2_alloc_context *ac, + handle_t *handle, u32 bits_wanted, u32 min_bits, u16 *bit_off, @@ -1126,7 +1100,6 @@ static int ocfs2_search_chain(struct ocf u16 chain, tmp_bits; u32 tmp_used; u64 next_group; - struct ocfs2_journal_handle *handle = ac->ac_handle; struct inode *alloc_inode = ac->ac_inode; struct buffer_head *group_bh = NULL; struct buffer_head *prev_group_bh = NULL; @@ -1272,6 +1245,7 @@ bail: /* will give out up to bits_wanted contiguous bits. */ static int ocfs2_claim_suballoc_bits(struct ocfs2_super *osb, struct ocfs2_alloc_context *ac, + handle_t *handle, u32 bits_wanted, u32 min_bits, u16 *bit_off, @@ -1313,8 +1287,8 @@ static int ocfs2_claim_suballoc_bits(str * by jumping straight to the most recently used * allocation group. This helps us mantain some * contiguousness across allocations. */ - status = ocfs2_search_one_group(ac, bits_wanted, min_bits, - bit_off, num_bits, + status = ocfs2_search_one_group(ac, handle, bits_wanted, + min_bits, bit_off, num_bits, hint_blkno, &bits_left); if (!status) { /* Be careful to update *bg_blkno here as the @@ -1336,7 +1310,7 @@ static int ocfs2_claim_suballoc_bits(str ac->ac_chain = victim; ac->ac_allow_chain_relink = 1; - status = ocfs2_search_chain(ac, bits_wanted, min_bits, bit_off, + status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits, bit_off, num_bits, bg_blkno, &bits_left); if (!status) goto set_hint; @@ -1360,7 +1334,7 @@ static int ocfs2_claim_suballoc_bits(str continue; ac->ac_chain = i; - status = ocfs2_search_chain(ac, bits_wanted, min_bits, + status = ocfs2_search_chain(ac, handle, bits_wanted, min_bits, bit_off, num_bits, bg_blkno, &bits_left); if (!status) @@ -1388,7 +1362,7 @@ bail: } int ocfs2_claim_metadata(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct ocfs2_alloc_context *ac, u32 bits_wanted, u16 *suballoc_bit_start, @@ -1401,10 +1375,10 @@ int ocfs2_claim_metadata(struct ocfs2_su BUG_ON(!ac); BUG_ON(ac->ac_bits_wanted < (ac->ac_bits_given + bits_wanted)); BUG_ON(ac->ac_which != OCFS2_AC_USE_META); - BUG_ON(ac->ac_handle != handle); status = ocfs2_claim_suballoc_bits(osb, ac, + handle, bits_wanted, 1, suballoc_bit_start, @@ -1425,7 +1399,7 @@ bail: } int ocfs2_claim_new_inode(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct ocfs2_alloc_context *ac, u16 *suballoc_bit, u64 *fe_blkno) @@ -1440,10 +1414,10 @@ int ocfs2_claim_new_inode(struct ocfs2_s BUG_ON(ac->ac_bits_given != 0); BUG_ON(ac->ac_bits_wanted != 1); BUG_ON(ac->ac_which != OCFS2_AC_USE_INODE); - BUG_ON(ac->ac_handle != handle); status = ocfs2_claim_suballoc_bits(osb, ac, + handle, 1, 1, suballoc_bit, @@ -1528,7 +1502,7 @@ static inline void ocfs2_block_to_cluste * of any size. */ int ocfs2_claim_clusters(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct ocfs2_alloc_context *ac, u32 min_clusters, u32 *cluster_start, @@ -1546,7 +1520,6 @@ int ocfs2_claim_clusters(struct ocfs2_su BUG_ON(ac->ac_which != OCFS2_AC_USE_LOCAL && ac->ac_which != OCFS2_AC_USE_MAIN); - BUG_ON(ac->ac_handle != handle); if (ac->ac_which == OCFS2_AC_USE_LOCAL) { status = ocfs2_claim_local_alloc_bits(osb, @@ -1572,6 +1545,7 @@ int ocfs2_claim_clusters(struct ocfs2_su status = ocfs2_claim_suballoc_bits(osb, ac, + handle, bits_wanted, min_clusters, &bg_bit_off, @@ -1598,7 +1572,7 @@ bail: return status; } -static inline int ocfs2_block_group_clear_bits(struct ocfs2_journal_handle *handle, +static inline int ocfs2_block_group_clear_bits(handle_t *handle, struct inode *alloc_inode, struct ocfs2_group_desc *bg, struct buffer_head *group_bh, @@ -1653,7 +1627,7 @@ bail: /* * expects the suballoc inode to already be locked. */ -static int ocfs2_free_suballoc_bits(struct ocfs2_journal_handle *handle, +static int ocfs2_free_suballoc_bits(handle_t *handle, struct inode *alloc_inode, struct buffer_head *alloc_bh, unsigned int start_bit, @@ -1737,7 +1711,7 @@ static inline u64 ocfs2_which_suballoc_g return group; } -int ocfs2_free_dinode(struct ocfs2_journal_handle *handle, +int ocfs2_free_dinode(handle_t *handle, struct inode *inode_alloc_inode, struct buffer_head *inode_alloc_bh, struct ocfs2_dinode *di) @@ -1750,7 +1724,7 @@ int ocfs2_free_dinode(struct ocfs2_journ inode_alloc_bh, bit, bg_blkno, 1); } -int ocfs2_free_extent_block(struct ocfs2_journal_handle *handle, +int ocfs2_free_extent_block(handle_t *handle, struct inode *eb_alloc_inode, struct buffer_head *eb_alloc_bh, struct ocfs2_extent_block *eb) @@ -1763,7 +1737,7 @@ int ocfs2_free_extent_block(struct ocfs2 bit, bg_blkno, 1); } -int ocfs2_free_clusters(struct ocfs2_journal_handle *handle, +int ocfs2_free_clusters(handle_t *handle, struct inode *bitmap_inode, struct buffer_head *bitmap_bh, u64 start_blk, diff --git a/fs/ocfs2/suballoc.h b/fs/ocfs2/suballoc.h index c787838..1a3c94c 100644 --- a/fs/ocfs2/suballoc.h +++ b/fs/ocfs2/suballoc.h @@ -43,7 +43,6 @@ #define OCFS2_AC_USE_MAIN 2 #define OCFS2_AC_USE_INODE 3 #define OCFS2_AC_USE_META 4 u32 ac_which; - struct ocfs2_journal_handle *ac_handle; /* these are used by the chain search */ u16 ac_chain; @@ -60,45 +59,42 @@ static inline int ocfs2_alloc_context_bi } int ocfs2_reserve_new_metadata(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, struct ocfs2_dinode *fe, struct ocfs2_alloc_context **ac); int ocfs2_reserve_new_inode(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, struct ocfs2_alloc_context **ac); int ocfs2_reserve_clusters(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, u32 bits_wanted, struct ocfs2_alloc_context **ac); int ocfs2_claim_metadata(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct ocfs2_alloc_context *ac, u32 bits_wanted, u16 *suballoc_bit_start, u32 *num_bits, u64 *blkno_start); int ocfs2_claim_new_inode(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct ocfs2_alloc_context *ac, u16 *suballoc_bit, u64 *fe_blkno); int ocfs2_claim_clusters(struct ocfs2_super *osb, - struct ocfs2_journal_handle *handle, + handle_t *handle, struct ocfs2_alloc_context *ac, u32 min_clusters, u32 *cluster_start, u32 *num_clusters); -int ocfs2_free_dinode(struct ocfs2_journal_handle *handle, +int ocfs2_free_dinode(handle_t *handle, struct inode *inode_alloc_inode, struct buffer_head *inode_alloc_bh, struct ocfs2_dinode *di); -int ocfs2_free_extent_block(struct ocfs2_journal_handle *handle, +int ocfs2_free_extent_block(handle_t *handle, struct inode *eb_alloc_inode, struct buffer_head *eb_alloc_bh, struct ocfs2_extent_block *eb); -int ocfs2_free_clusters(struct ocfs2_journal_handle *handle, +int ocfs2_free_clusters(handle_t *handle, struct inode *bitmap_inode, struct buffer_head *bitmap_bh, u64 start_blk, diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c index 76b46eb..b099257 100644 --- a/fs/ocfs2/super.c +++ b/fs/ocfs2/super.c @@ -70,8 +70,6 @@ #include "buffer_head_io.h" static kmem_cache_t *ocfs2_inode_cachep = NULL; -kmem_cache_t *ocfs2_lock_cache = NULL; - /* OCFS2 needs to schedule several differnt types of work which * require cluster locking, disk I/O, recovery waits, etc. Since these * types of work tend to be heavy we avoid using the kernel events @@ -141,6 +139,7 @@ enum { Opt_hb_local, Opt_data_ordered, Opt_data_writeback, + Opt_atime_quantum, Opt_err, }; @@ -154,6 +153,7 @@ static match_table_t tokens = { {Opt_hb_local, OCFS2_HB_LOCAL}, {Opt_data_ordered, "data=ordered"}, {Opt_data_writeback, "data=writeback"}, + {Opt_atime_quantum, "atime_quantum=%u"}, {Opt_err, NULL} }; @@ -707,6 +707,7 @@ static int ocfs2_parse_options(struct su while ((p = strsep(&options, ",")) != NULL) { int token, option; substring_t args[MAX_OPT_ARGS]; + struct ocfs2_super * osb = OCFS2_SB(sb); if (!*p) continue; @@ -747,6 +748,16 @@ static int ocfs2_parse_options(struct su case Opt_data_writeback: *mount_opt |= OCFS2_MOUNT_DATA_WRITEBACK; break; + case Opt_atime_quantum: + if (match_int(&args[0], &option)) { + status = 0; + goto bail; + } + if (option >= 0) + osb->s_atime_quantum = option; + else + osb->s_atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM; + break; default: mlog(ML_ERROR, "Unrecognized mount option \"%s\" " @@ -867,7 +878,7 @@ static int ocfs2_statfs(struct dentry *d goto bail; } - status = ocfs2_meta_lock(inode, NULL, &bh, 0); + status = ocfs2_meta_lock(inode, &bh, 0); if (status < 0) { mlog_errno(status); goto bail; @@ -914,9 +925,7 @@ static void ocfs2_inode_init_once(void * oi->ip_open_count = 0; spin_lock_init(&oi->ip_lock); ocfs2_extent_map_init(&oi->vfs_inode); - INIT_LIST_HEAD(&oi->ip_handle_list); INIT_LIST_HEAD(&oi->ip_io_markers); - oi->ip_handle = NULL; oi->ip_created_trans = 0; oi->ip_last_trans = 0; oi->ip_dir_start_lookup = 0; @@ -948,14 +957,6 @@ static int ocfs2_initialize_mem_caches(v if (!ocfs2_inode_cachep) return -ENOMEM; - ocfs2_lock_cache = kmem_cache_create("ocfs2_lock", - sizeof(struct ocfs2_journal_lock), - 0, - SLAB_HWCACHE_ALIGN, - NULL, NULL); - if (!ocfs2_lock_cache) - return -ENOMEM; - return 0; } @@ -963,11 +964,8 @@ static void ocfs2_free_mem_caches(void) { if (ocfs2_inode_cachep) kmem_cache_destroy(ocfs2_inode_cachep); - if (ocfs2_lock_cache) - kmem_cache_destroy(ocfs2_lock_cache); ocfs2_inode_cachep = NULL; - ocfs2_lock_cache = NULL; } static int ocfs2_get_sector(struct super_block *sb, @@ -1280,6 +1278,8 @@ static int ocfs2_initialize_super(struct init_waitqueue_head(&osb->checkpoint_event); atomic_set(&osb->needs_checkpoint, 0); + osb->s_atime_quantum = OCFS2_DEFAULT_ATIME_QUANTUM; + osb->node_num = O2NM_INVALID_NODE_NUM; osb->slot_num = OCFS2_INVALID_SLOT; diff --git a/fs/ocfs2/symlink.c b/fs/ocfs2/symlink.c index c0f68aa..957d687 100644 --- a/fs/ocfs2/symlink.c +++ b/fs/ocfs2/symlink.c @@ -126,6 +126,10 @@ static int ocfs2_readlink(struct dentry goto out; } + /* + * Without vfsmount we can't update atime now, + * but we will update atime here ultimately. + */ ret = vfs_readlink(dentry, buffer, buflen, link); brelse(bh); diff --git a/include/linux/configfs.h b/include/linux/configfs.h index a7f0150..11100ca 100644 --- a/include/linux/configfs.h +++ b/include/linux/configfs.h @@ -157,6 +157,7 @@ struct configfs_group_operations { struct config_item *(*make_item)(struct config_group *group, const char *name); struct config_group *(*make_group)(struct config_group *group, const char *name); int (*commit_item)(struct config_item *item); + void (*disconnect_notify)(struct config_group *group, struct config_item *item); void (*drop_item)(struct config_group *group, struct config_item *item); }; diff --git a/mm/filemap.c b/mm/filemap.c index 7b84dc8..13df01c 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -1893,6 +1893,7 @@ int should_remove_suid(struct dentry *de return 0; } +EXPORT_SYMBOL(should_remove_suid); int __remove_suid(struct dentry *dentry, int kill) {