+/* move cluster handle to the target position
+ specified by the page of index @pgidx
+*/
+static inline void
+move_cluster_forward(reiser4_cluster_t * clust, struct inode * inode,
+ pgoff_t pgidx, int * progress)
+{
+ assert("edward-1297", clust != NULL);
+ assert("edward-1298", inode != NULL);
+
+ reset_cluster_params(clust);
+ if (*progress &&
+ /* Hole in the indices. Hint became invalid and can not be
+ used by find_cluster_item() even if seal/node versions
+ will coincide */
+ pg_to_clust(pgidx, inode) != clust->index + 1) {
+ unset_hint(clust->hint);
+ invalidate_hint_cluster(clust);
+ }
+ *progress = 1;
+ clust->index = pg_to_clust(pgidx, inode);
+}
+
static inline int
alloc_clust_pages(reiser4_cluster_t * clust, struct inode * inode )
{
diff -puN fs/reiser4/context.c~reiser4-update fs/reiser4/context.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/context.c~reiser4-update 2005-04-19 17:58:43.373945371 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/context.c 2005-04-19 17:58:43.489931075 +0400
@@ -173,6 +173,25 @@ reiser4_internal void reiser4_exit_conte
txn_restart(context);
balance_dirty_pages_at(context);
}
+
+ /* if filesystem is mounted with -o sync or -o dirsync - commit
+ transaction. FIXME: TXNH_DONT_COMMIT is used to avoid
+ commiting on exit_context when inode semaphore is held and
+ to have ktxnmgrd to do commit instead to get better
+ concurrent filesystem accesses. But, when one mounts with -o
+ sync, he cares more about reliability than about
+ performance. So, for now we have this simple mount -o sync
+ support. */
+ if (context->super->s_flags & (MS_SYNCHRONOUS | MS_DIRSYNC)) {
+ txn_atom *atom;
+
+ atom = get_current_atom_locked_nocheck();
+ if (atom) {
+ atom->flags |= ATOM_FORCE_COMMIT;
+ context->trans->flags &= ~TXNH_DONT_COMMIT;
+ UNLOCK_ATOM(atom);
+ }
+ }
txn_end(context);
}
done_context(context);
diff -puN fs/reiser4/flush.c~reiser4-update fs/reiser4/flush.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/flush.c~reiser4-update 2005-04-19 17:58:43.379944632 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/flush.c 2005-04-19 17:58:43.492930705 +0400
@@ -1191,7 +1191,7 @@ static int alloc_pos_and_ancestors(flush
} else {
if (!znode_is_root(pos->lock.node)) {
/* all formatted nodes except tree root */
- ret = reiser4_get_parent(&plock, pos->lock.node, ZNODE_WRITE_LOCK, 0);
+ ret = reiser4_get_parent(&plock, pos->lock.node, ZNODE_WRITE_LOCK);
if (ret)
goto exit;
@@ -1704,11 +1704,11 @@ static int squalloc_upper_levels (flush_
init_load_count(&left_parent_load);
init_load_count(&right_parent_load);
- ret = reiser4_get_parent(&left_parent_lock, left, ZNODE_WRITE_LOCK, 0);
+ ret = reiser4_get_parent(&left_parent_lock, left, ZNODE_WRITE_LOCK);
if (ret)
goto out;
- ret = reiser4_get_parent(&right_parent_lock, right, ZNODE_WRITE_LOCK, 0);
+ ret = reiser4_get_parent(&right_parent_lock, right, ZNODE_WRITE_LOCK);
if (ret)
goto out;
@@ -1811,7 +1811,7 @@ static int lock_parent_and_allocate_znod
init_lh(&parent_lock);
init_load_count(&parent_load);
- ret = reiser4_get_parent(&parent_lock, node, ZNODE_WRITE_LOCK, 0);
+ ret = reiser4_get_parent(&parent_lock, node, ZNODE_WRITE_LOCK);
if (ret)
goto out;
@@ -2224,7 +2224,7 @@ static int handle_pos_to_twig (flush_pos
init_lh(&parent_lock);
init_load_count(&parent_load);
- ret = reiser4_get_parent(&parent_lock, pos->lock.node, ZNODE_WRITE_LOCK, 0);
+ ret = reiser4_get_parent(&parent_lock, pos->lock.node, ZNODE_WRITE_LOCK);
if (ret)
goto out;
/* set compression */
- inode_set_compression(object, data->compression);
-
+ result = inode_set_compression(object, data->compression);
+ if (result)
+ goto error;
/* set cluster info */
result = inode_set_cluster(object, data->cluster);
if (result)
@@ -626,7 +670,7 @@ eq_to_ldk(znode *node, const reiser4_key
#endif
/* The core search procedure.
- If result is not cbk_errored current znode is locked */
+ If returned value is not cbk_errored, current znode is locked */
static int
find_cluster_item(hint_t * hint,
const reiser4_key *key, /* key of the item we are
@@ -776,7 +820,9 @@ max_crypto_overhead(struct inode * inode
static unsigned
compress_overhead(struct inode * inode, int in_len)
{
- return inode_compression_plugin(inode)->overrun(in_len);
+ return (inode_compression_plugin(inode)->overrun != NULL ?
+ inode_compression_plugin(inode)->overrun(in_len) :
+ 0);
}
/* Since small input stream can not get compressed,
@@ -789,15 +835,18 @@ min_size_to_compress(struct inode * inod
return inode_compression_plugin(inode)->min_tfm_size();
}
-/* Prepare cluster handle before write. Called by all the clients which
- age going to modify the page cluster and put it into a transaction
- (file_write, truncate, writepages, etc..)
+/* Prepare cluster handle before write and(or) capture. This function
+ is called by all the clients which modify page cluster and(or) put
+ it into a transaction (file_write, truncate, writepages, etc..)
. grab cluster pages;
. reserve disk space;
. maybe read pages from disk and set the disk cluster dirty;
. maybe write hole;
- . maybe create 'unprepped' disk cluster (if the disk cluster is fake (isn't represenred
- by any items on disk)
+ . maybe create 'unprepped' disk cluster if the last one is fake
+ (isn't represenred by any items on disk)
*/
+ result = check_cryptcompress(inode);
+ if (result)
+ return result;
result = load_file_hint(file, &hint);
if (result)
return result;
@@ -2632,7 +2683,8 @@ set_append_cluster_key(const coord_t *co
It succes was returned:
(@index == 0 && @found == 0) means that the object doesn't have real disk
clusters.
- (@index != 0 && @found == 0) means that disk cluster of @index doesn't exist.
+ (@index != 0 && @found == 0) means that disk cluster of (@index -1 ) doesn't
+ exist.
*/
static int
find_real_disk_cluster(struct inode * inode, cloff_t * found, cloff_t index)
@@ -2878,13 +2930,9 @@ cryptcompress_append_hole(struct inode *
win.stat = HOLE_WINDOW;
assert("edward-1137", clust.index == off_to_clust(inode->i_size, inode));
-#if REISER4_DEBUG
- printk("edward-1138, Warning: Hole of size %llu in "
- "cryptcompress file (inode %llu); "
- "%u zeroes appended to cluster (index = %lu) \n",
- hole_size, (unsigned long long)get_inode_oid(inode), nr_zeroes, clust.index);
-#endif
+
result = prepare_cluster(inode, 0, 0, &clust, PCL_APPEND);
+
assert("edward-1271", !result);
if (result)
goto out;
@@ -3045,12 +3093,12 @@ prune_cryptcompress(struct inode * inode
assert("edward-1191", inode->i_size == new_size);
assert("edward-1206", body_truncate_ok(inode, fidx));
finish:
- /* drop all the pages that don't have jnodes
- because of holes represented by fake disk clusters
- including the pages of partially truncated cluster
- which was released by prepare_cluster() */
- truncate_inode_pages(inode->i_mapping,
- pg_to_off(count_to_nrpages(new_size)));
+ /* drop all the pages that don't have jnodes (i.e. pages
+ which can not be truncated by cut_file_items() because
+ of holes represented by fake disk clusters) including
+ the pages of partially truncated cluster which was
+ released by prepare_cluster() */
+ truncate_inode_pages(inode->i_mapping, new_size);
INODE_SET_FIELD(inode, i_size, new_size);
out:
done_lh(&lh);
@@ -3089,13 +3137,20 @@ cryptcompress_truncate(struct inode *ino
ergo(aidx > 0, inode->i_size > clust_to_off(aidx - 1, inode)));
if (truncating_last_fake_dc(inode, aidx, new_size)) {
- /* we do not need to truncate items, so just drop pages
- which can not acquire jnodes because of exclusive access */
-
+ /* The last page cluster we truncate (fully or partially)
+ is fake (don't have disk cluster) */
INODE_SET_FIELD(inode, i_size, new_size);
if (old_size > new_size) {
- truncate_inode_pages(inode->i_mapping,
- pg_to_off(count_to_nrpages(new_size)));
+ /* Drop page cluster.
+ There are only 2 cases for partially truncated page:
+ 1. If is is dirty, therefore it is anonymous
+ (was dirtied via mmap), and will be captured
+ later via ->capture().
+ 2. If is clean, therefore it is filled by zeroes.
+ In both cases we don't need to make it dirty and
+ capture here.
+ */
+ truncate_inode_pages(inode->i_mapping, new_size);
assert("edward-663", ergo(!new_size,
reiser4_inode_data(inode)->anonymous_eflushed == 0 &&
reiser4_inode_data(inode)->captured_eflushed == 0));
@@ -3135,7 +3190,7 @@ capture_anonymous_cluster(reiser4_cluste
set_cluster_pages_dirty(clust);
+ if (wbc->sync_mode != WB_SYNC_ALL)
+ to_capture = min_count(wbc->nr_to_write, MAX_CLUSTERS_TO_CAPTURE(inode));
+ else
+ to_capture = MAX_CLUSTERS_TO_CAPTURE(inode);
do {
reiser4_context ctx;
if (is_in_reiser4_context()) {
+ /* FIXME-EDWARD: REMOVEME */
+ all_grabbed2free();
+
/* It can be in the context of write system call from
balance_dirty_pages() */
if (down_read_trylock(&info->lock) == 0) {
@@ -3257,7 +3315,7 @@ capture_cryptcompress(struct inode *inod
LOCK_CNT_INC(inode_sem_r);
- result = capture_anonymous_clusters(inode->i_mapping, &index);
+ result = capture_anonymous_clusters(inode->i_mapping, &index, to_capture);
up_read(&info->lock);
@@ -3269,7 +3327,7 @@ capture_cryptcompress(struct inode *inod
}
result = txnmgr_force_commit_all(inode->i_sb, 0);
reiser4_exit_context(&ctx);
- } while (result == 0 && crc_inode_has_anon_pages(inode));
+ } while (result == 0 && index < nrpages);
-/* VS-FIXME-HANS: what is pre deleting all about? */
-/* plugin->u.file.pre_delete */
+/* plugin->u.file.pre_delete
+
+ We need this because generic_delete_inode calls truncate_inode_pages before
+ filesystem's delete_inode method. As result of this, reiser4 tree may have
+ unallocated extents which do not have pages pointed by them (those pages are
+ removed by truncate_inode_pages), which may confuse flush code. The solution
+ for this problem is to call pre_delete method from reiser4_put_inode to
+ remove file items together with corresponding pages. Generic_delete_inode
+ will call truncate_inode_pages which will do nothing and
+ reiser4_delete_inode which completes file deletion by removing stat data
+ from the tree.
+ This method is to be called from reiser4_put_inode when file is already
+ unlinked and iput is about to drop last reference to inode. If nfsd manages
+ to iget the file after pre_delete started, it will either be able to access
+ a file content (if it will get access to file earlier than pre_delete) or it
+ will get file truncated to 0 size if pre_delete goes first
+*/
reiser4_internal int
pre_delete_unix_file(struct inode *inode)
{
unix_file_info_t *uf_info;
int result;
/* offset in a file to start read from */
file_off = get_key_offset(&flow->key);
- /* index of page containing that offset */
- page_nr = (unsigned long)(file_off >> PAGE_CACHE_SHIFT);
/* offset within the page to start read from */
page_off = (unsigned long)(file_off & (PAGE_CACHE_SIZE - 1));
/* bytes which can be read from the page which contains file_off */
count = PAGE_CACHE_SIZE - page_off;
+
+ /* index of page containing offset read is to start from */
+ cur_page = (unsigned long)(file_off >> PAGE_CACHE_SHIFT);
+ next_page = cur_page;
/* number of pages flow spans over */
- ra_pages = (flow->length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+ nr_pages = ((file_off + flow->length + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT) - cur_page;
/* we start having twig node read locked. However, we do not want to
keep that lock all the time readahead works. So, set a sel and
@@ -1282,26 +1325,50 @@ read_extent(struct file *file, flow_t *f
set_hint(hint, &flow->key, ZNODE_READ_LOCK);
longterm_unlock_znode(hint->ext_coord.lh);
+ ra = file->f_ra;
+ prev_page = ra.prev_page;
do {
- call_page_cache_readahead(mapping, file, hint, page_nr, ra_pages);
+ if (next_page == cur_page)
+ next_page = call_page_cache_readahead(mapping, file, hint, cur_page, nr_pages, &ra);
- /* this will return page if it exists and is uptodate,
- otherwise it will allocate page and call readpage_extent to
- fill it */
- page = read_cache_page(mapping, page_nr, readpage_unix_file, file);
- if (IS_ERR(page))
- return PTR_ERR(page);
-
- wait_on_page_locked(page);
- if (!PageUptodate(page)) {
- page_detach_jnode(page, mapping, page_nr);
- page_cache_release(page);
- warning("jmacd-97178", "extent_read: page is not up to date");
- return RETERR(-EIO);
+ page = find_get_page(mapping, cur_page);
+ if (unlikely(page == NULL)) {
+ handle_ra_miss(mapping, &ra, cur_page);
+ page = read_cache_page(mapping, cur_page, readpage_unix_file, file);
+ if (IS_ERR(page))
+ return PTR_ERR(page);
+ lock_page(page);
+ if (!PageUptodate(page)) {
+ unlock_page(page);
+ page_detach_jnode(page, mapping, cur_page);
+ page_cache_release(page);
+ warning("jmacd-97178", "extent_read: page is not up to date");
+ return RETERR(-EIO);
+ }
+ unlock_page(page);
+ } else {
+ if (!PageUptodate(page)) {
+ lock_page(page);
+
+ assert("", page->mapping == mapping);
+ if (PageUptodate(page))
+ unlock_page(page);
+ else {
+ result = call_readpage(file, page);
+ if (result) {
+ page_cache_release(page);
+ return RETERR(result);
+ }
+ }
+ }
+ if (prev_page != cur_page)
+ mark_page_accessed(page);
+ prev_page = cur_page;
}
- /* If users can be writing to this page using arbitrary virtual addresses, take care about potential
- aliasing before reading the page on the kernel side.
+ /* If users can be writing to this page using arbitrary virtual
+ addresses, take care about potential aliasing before reading
+ the page on the kernel side.
*/
if (mapping_writably_mapped(mapping))
flush_dcache_page(page);
@@ -1324,11 +1391,12 @@ read_extent(struct file *file, flow_t *f
move_flow_forward(flow, count);
-/* ->not_linked() method the for directory file plugin */
-static int
-not_linked_dir(const struct inode *inode)
-{
- assert("nikita-2008", inode != NULL);
- /* one link from dot */
- return (inode->i_nlink == 1);
+ /*
+ * decrement ->i_nlink and update ->i_ctime
+ */
+ INODE_DEC_FIELD(object, i_nlink);
+ if (object->i_nlink == 1)
+ INODE_DEC_FIELD(object, i_nlink);
+ object->i_ctime = CURRENT_TIME;
+ return 0;
}
/* ->adjust_to_parent() method for regular files */
@@ -954,102 +956,6 @@ setattr_common(struct inode *inode /* Ob
return result;
}
-/* doesn't seem to be exported in headers. */
-extern spinlock_t inode_lock;
-
-/* ->delete_inode() method. This is called by
- * iput()->iput_final()->drop_inode() when last reference to inode is released
- * and inode has no names. */
-static void delete_inode_common(struct inode *object)
-{
- /* create context here.
- *
- * removal of inode from the hash table (done at the very beginning of
- * generic_delete_inode(), truncate of pages, and removal of file's
- * extents has to be performed in the same atom. Otherwise, it may so
- * happen, that twig node with unallocated extent will be flushed to
- * the disk.
- */
- reiser4_context ctx;
-
- /*
- * FIXME: this resembles generic_delete_inode
- */
- list_del_init(&object->i_list);
- list_del_init(&object->i_sb_list);
- object->i_state |= I_FREEING;
- inodes_stat.nr_inodes--;
- spin_unlock(&inode_lock);
-
- init_context(&ctx, object->i_sb);
-
- kill_cursors(object);
-
- if (!is_bad_inode(object)) {
- file_plugin *fplug;
-
- /* truncate object body */
- fplug = inode_file_plugin(object);
- if (fplug->pre_delete != NULL && fplug->pre_delete(object) != 0)
- warning("vs-1216", "Failed to delete file body %llu",
- (unsigned long long)get_inode_oid(object));
- else
- assert("vs-1430",
- reiser4_inode_data(object)->anonymous_eflushed == 0 &&
- reiser4_inode_data(object)->captured_eflushed == 0);
- }
-
- if (object->i_data.nrpages) {
- warning("vs-1434", "nrpages %ld\n", object->i_data.nrpages);
- truncate_inode_pages(&object->i_data, 0);
- }
- security_inode_delete(object);
- if (!is_bad_inode(object))
- DQUOT_INIT(object);
-
- object->i_sb->s_op->delete_inode(object);
-
- spin_lock(&inode_lock);
- hlist_del_init(&object->i_hash);
- spin_unlock(&inode_lock);
- wake_up_inode(object);
- if (object->i_state != I_CLEAR)
- BUG();
- destroy_inode(object);
- reiser4_exit_context(&ctx);
-}
-
-/*
- * ->forget_inode() method. Called by iput()->iput_final()->drop_inode() when
- * last reference to inode with names is released
- */
-static void forget_inode_common(struct inode *object)
-{
- generic_forget_inode(object);
-}
-
-/* ->drop_inode() method. Called by iput()->iput_final() when last reference
- * to inode is released */
-static void drop_common(struct inode * object)
-{
- file_plugin *fplug;
-
- assert("nikita-2643", object != NULL);
-
- /* -not- creating context in this method, because it is frequently
- called and all existing ->not_linked() methods are one liners. */
-
- fplug = inode_file_plugin(object);
- /* fplug is NULL for fake inode */
- if (fplug != NULL && fplug->not_linked(object)) {
- assert("nikita-3231", fplug->delete_inode != NULL);
- fplug->delete_inode(object);
- } else {
- assert("nikita-3232", fplug->forget_inode != NULL);
- fplug->forget_inode(object);
- }
-}
-
static ssize_t
isdir(void)
{
@@ -1293,7 +1199,6 @@ file_plugin file_plugins[LAST_FILE_PLUGI
.owns_item = owns_item_unix_file,
.can_add_link = can_add_link_common,
.can_rem_link = NULL,
- .not_linked = not_linked_common,
.setattr = setattr_unix_file,
.getattr = getattr_common,
.seek = NULL,
@@ -1315,10 +1220,7 @@ file_plugin file_plugins[LAST_FILE_PLUGI
.init_inode_data = init_inode_data_unix_file,
.pre_delete = pre_delete_unix_file,
.cut_tree_worker = cut_tree_worker_common,
- .drop = drop_common,
- .delete_inode = delete_inode_common,
.destroy_inode = NULL,
- .forget_inode = forget_inode_common,
.sendfile = sendfile_unix_file,
.prepare_write = prepare_write_unix_file
},
@@ -1350,11 +1252,10 @@ file_plugin file_plugins[LAST_FILE_PLUGI
.delete = delete_directory_common,
.sync = sync_common,
.add_link = add_link_common,
- .rem_link = rem_link_common,
+ .rem_link = rem_link_common_dir,
.owns_item = owns_item_hashed,
.can_add_link = can_add_link_common,
.can_rem_link = can_rem_dir,
- .not_linked = not_linked_dir,
.setattr = setattr_common,
.getattr = getattr_common,
.seek = seek_dir,
@@ -1376,10 +1277,7 @@ file_plugin file_plugins[LAST_FILE_PLUGI
.init_inode_data = init_inode_ordering,
.pre_delete = NULL,
.cut_tree_worker = cut_tree_worker_common,
- .drop = drop_common,
- .delete_inode = delete_inode_common,
.destroy_inode = NULL,
- .forget_inode = forget_inode_common,
},
[SYMLINK_FILE_PLUGIN_ID] = {
.h = {
@@ -1416,7 +1314,6 @@ file_plugin file_plugins[LAST_FILE_PLUGI
.owns_item = NULL,
.can_add_link = can_add_link_common,
.can_rem_link = NULL,
- .not_linked = not_linked_common,
.setattr = setattr_common,
.getattr = getattr_common,
.seek = NULL,
@@ -1438,10 +1335,7 @@ file_plugin file_plugins[LAST_FILE_PLUGI
.init_inode_data = init_inode_ordering,
.pre_delete = NULL,
.cut_tree_worker = cut_tree_worker_common,
- .drop = drop_common,
- .delete_inode = delete_inode_common,
.destroy_inode = destroy_inode_symlink,
- .forget_inode = forget_inode_common,
},
[SPECIAL_FILE_PLUGIN_ID] = {
.h = {
@@ -1476,7 +1370,6 @@ file_plugin file_plugins[LAST_FILE_PLUGI
.owns_item = owns_item_common,
.can_add_link = can_add_link_common,
.can_rem_link = NULL,
- .not_linked = not_linked_common,
.setattr = setattr_common,
.getattr = getattr_common,
.seek = NULL,
@@ -1498,10 +1391,7 @@ file_plugin file_plugins[LAST_FILE_PLUGI
.init_inode_data = init_inode_ordering,
.pre_delete = NULL,
.cut_tree_worker = cut_tree_worker_common,
- .drop = drop_common,
- .delete_inode = delete_inode_common,
.destroy_inode = NULL,
- .forget_inode = forget_inode_common,
},
[PSEUDO_FILE_PLUGIN_ID] = {
.h = {
@@ -1536,7 +1426,6 @@ file_plugin file_plugins[LAST_FILE_PLUGI
.owns_item = NULL,
.can_add_link = cannot,
.can_rem_link = cannot,
- .not_linked = NULL,
.setattr = inode_setattr,
.getattr = getattr_common,
.seek = seek_pseudo,
@@ -1558,10 +1447,7 @@ file_plugin file_plugins[LAST_FILE_PLUGI
.init_inode_data = NULL,
.pre_delete = NULL,
.cut_tree_worker = cut_tree_worker_common,
- .drop = drop_pseudo,
- .delete_inode = NULL,
.destroy_inode = NULL,
- .forget_inode = NULL,
},
[CRC_FILE_PLUGIN_ID] = {
.h = {
@@ -1597,7 +1483,6 @@ file_plugin file_plugins[LAST_FILE_PLUGI
.owns_item = owns_item_common,
.can_add_link = can_add_link_common,
.can_rem_link = NULL,
- .not_linked = not_linked_common,
.setattr = setattr_cryptcompress,
.getattr = getattr_common,
.seek = NULL,
@@ -1620,10 +1505,7 @@ file_plugin file_plugins[LAST_FILE_PLUGI
.init_inode_data = init_inode_data_cryptcompress,
.pre_delete = pre_delete_cryptcompress,
.cut_tree_worker = cut_tree_worker_cryptcompress,
- .drop = drop_common,
- .delete_inode = delete_inode_common,
.destroy_inode = destroy_inode_cryptcompress,
- .forget_inode = forget_inode_common,
.sendfile = sendfile_common,
.prepare_write = prepare_write_common
}
diff -puN fs/reiser4/plugin/plugin.h~reiser4-update fs/reiser4/plugin/plugin.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/plugin/plugin.h~reiser4-update 2005-04-19 17:58:43.441936990 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/plugin/plugin.h 2005-04-19 17:58:43.517927624 +0400
@@ -238,8 +238,6 @@ Elena doing this for you if that helps.
int (*can_add_link) (const struct inode * inode);
/* checks whether hard links to this object can be removed */
int (*can_rem_link) (const struct inode * inode);
- /* true if there is only one link (aka name) for this file */
- int (*not_linked) (const struct inode * inode);
/* change inode attributes. */
int (*setattr) (struct inode * inode, struct iattr * attr);
@@ -293,16 +291,9 @@ Elena doing this for you if that helps.
/* truncate file to zero size. called by reiser4_drop_inode before truncate_inode_pages */
int (*pre_delete)(struct inode *);
- /* called from reiser4_drop_inode() */
- void (*drop)(struct inode *);
-
- /* called from ->drop() when there are no links, and object should be
- * garbage collected. */
- void (*delete_inode)(struct inode *);
-
/* called from ->destroy_inode() */
void (*destroy_inode)(struct inode *);
- void (*forget_inode)(struct inode *);
+
ssize_t (*sendfile)(struct file *, loff_t *, size_t, read_actor_t, void __user *);
/*
* methods to serialize object identify. This is used, for example, by
@@ -453,6 +444,9 @@ typedef struct digest_plugin {
typedef struct compression_plugin {
/* generic fields */
plugin_header h;
+ /* id of the dual plugin */
+ reiser4_compression_id dual;
+ int (*init) (void);
/* the maximum number of bytes the size of the "compressed" data can
* exceed the uncompressed data. */
int (*overrun) (unsigned src_len);
diff -puN fs/reiser4/safe_link.c~reiser4-update fs/reiser4/safe_link.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/safe_link.c~reiser4-update 2005-04-19 17:58:43.445936498 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/safe_link.c 2005-04-19 17:58:43.519927377 +0400
@@ -91,11 +91,12 @@ safe_link_locality(reiser4_tree *tree)
/*
@@ -273,6 +275,7 @@ static int process_safelink(struct super
fplug = inode_file_plugin(inode);
assert("nikita-3428", fplug != NULL);
+ assert("", oid == get_inode_oid(inode));
if (fplug->safelink != NULL) {
/* txn_restart_current is not necessary because
* mounting is signle thread. However, without it
@@ -295,11 +298,11 @@ static int process_safelink(struct super
reiser4_iget_complete(inode);
iput(inode);
if (result == 0) {
- result = safe_link_grab(tree_by_inode(inode),
+ result = safe_link_grab(get_tree(super),
BA_CAN_COMMIT);
if (result == 0)
- result = safe_link_del(inode, link);
- safe_link_release(tree_by_inode(inode));
+ result = safe_link_del(get_tree(super), oid, link);
+ safe_link_release(get_tree(super));
/*
* restart transaction: if there was large number of
* safe-links, their processing may fail to fit into
diff -puN fs/reiser4/safe_link.h~reiser4-update fs/reiser4/safe_link.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/safe_link.h~reiser4-update 2005-04-19 17:58:43.450935881 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/safe_link.h 2005-04-19 17:58:43.519927377 +0400
@@ -11,7 +11,7 @@
int safe_link_grab(reiser4_tree *tree, reiser4_ba_flags_t flags);
void safe_link_release(reiser4_tree *tree);
int safe_link_add(struct inode *inode, reiser4_safe_link_t link);
-int safe_link_del(struct inode *inode, reiser4_safe_link_t link);
+int safe_link_del(reiser4_tree *, oid_t oid, reiser4_safe_link_t link);
-/* A wrapper for reiser4_get_parent_flags(). */
-reiser4_internal int
-reiser4_get_parent(lock_handle * result /* resulting lock
- * handle */ ,
- znode * node /* child node */ ,
- znode_lock_mode mode /* type of lock: read or write */ ,
- int only_connected_p /* if this is true, parent is
- * only returned when it is
- * connected. If parent is
- * unconnected, -E_NO_NEIGHBOR is
- * returned. Normal users should
- * pass 1 here. Only during carry
- * we want to access still
- * unconnected parents. */ )
-{
- assert("umka-238", znode_get_tree(node) != NULL);
-
- return reiser4_get_parent_flags(result, node, mode,
- only_connected_p ? 0 : GN_ALLOW_NOT_CONNECTED);
-}
-
/* wrapper function to lock right or left neighbor depending on GN_GO_LEFT
bit in @flags parameter */
/* Audited by: umka (2002.06.14) */
@@ -705,7 +684,7 @@ again:
/* before establishing of sibling link we lock parent node; it is
required by renew_neighbor() to work. */
init_lh(&path[0]);
- ret = reiser4_get_parent(&path[0], node, ZNODE_READ_LOCK, 1);
+ ret = reiser4_get_parent(&path[0], node, ZNODE_READ_LOCK);
if (ret)
return ret;
if (znode_above_root(path[0].node)) {
@@ -753,7 +732,7 @@ again:
/* sibling link is not available -- we go
upward. */
init_lh(&path[h + 1]);
- ret = reiser4_get_parent(&path[h + 1], parent, ZNODE_READ_LOCK, 1);
+ ret = reiser4_get_parent(&path[h + 1], parent, ZNODE_READ_LOCK);
if (ret)
goto fail;
++h;
@@ -1034,7 +1013,7 @@ static int tw_up (struct tw_handle * h)
init_load_count(&load);
do {
- ret = reiser4_get_parent(&lock, h->tap.lh->node, ZNODE_WRITE_LOCK, 0);
+ ret = reiser4_get_parent(&lock, h->tap.lh->node, ZNODE_WRITE_LOCK);
if (ret)
break;
if (znode_above_root(lock.node)) {
diff -puN fs/reiser4/tree_walk.h~reiser4-update fs/reiser4/tree_walk.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/tree_walk.h~reiser4-update 2005-04-19 17:58:43.464934156 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/tree_walk.h 2005-04-19 17:58:43.524926761 +0400
@@ -37,8 +37,6 @@ int
reiser4_get_parent_flags(lock_handle * result, znode * node,
znode_lock_mode mode, int flags);
-int reiser4_get_parent(lock_handle * result, znode * node, znode_lock_mode mode, int only_connected_p);
-
/* bits definition for reiser4_get_neighbor function `flags' arg. */
typedef enum {
/* If sibling pointer is NULL, this flag allows get_neighbor() to try to
@@ -62,6 +60,13 @@ typedef enum {
GN_ASYNC = 0x80
} znode_get_neigbor_flags;
+/* A commonly used wrapper for reiser4_get_parent_flags(). */
+static inline int reiser4_get_parent(
+ lock_handle * result, znode * node, znode_lock_mode mode)
+{
+ return reiser4_get_parent_flags(result, node, mode, GN_ALLOW_NOT_CONNECTED);
+}
+
int reiser4_get_neighbor(lock_handle * neighbor, znode * node, znode_lock_mode lock_mode, int flags);
/* there are wrappers for most common usages of reiser4_get_neighbor() */
diff -puN fs/reiser4/txnmgr.c~reiser4-update fs/reiser4/txnmgr.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/txnmgr.c~reiser4-update 2005-04-19 17:58:43.470933416 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/txnmgr.c 2005-04-19 17:58:43.527926391 +0400
@@ -1380,6 +1380,51 @@ commit_some_atoms(txn_mgr * mgr)
return 0;
}
+static int txn_try_to_fuse_small_atom (txn_mgr * tmgr, txn_atom * atom)
+{
+ int atom_stage;
+ txn_atom *atom_2;
+ int repeat;
+
+ assert ("zam-1051", atom->stage < ASTAGE_PRE_COMMIT);
+
+ atom_stage = atom->stage;
+ repeat = 0;
+
+ if (!spin_trylock_txnmgr(tmgr)) {
+ UNLOCK_ATOM(atom);
+ spin_lock_txnmgr(tmgr);
+ LOCK_ATOM(atom);
+ repeat = 1;
+ if (atom->stage != atom_stage)
+ goto out;
+ }
+
+ for_all_type_safe_list(atom, &tmgr->atoms_list, atom_2) {
+ if (atom == atom_2)
+ continue;
+ /* if trylock does not succeed we just do not fuse with that
+ * atom. */
+ if (spin_trylock_atom(atom_2)) {
+ if (atom_2->stage < ASTAGE_PRE_COMMIT) {
+ spin_unlock_txnmgr(tmgr);
+ capture_fuse_into(atom_2, atom);
+ /* all locks are lost we can only repeat here */
+ return -E_REPEAT;
+ }
+ UNLOCK_ATOM(atom_2);
+ }
+ }
+ spin_unlock_txnmgr(tmgr);
+ atom->flags |= ATOM_CANCEL_FUSION;
+ out:
+ if (repeat) {
+ UNLOCK_ATOM(atom);
+ return -E_REPEAT;
+ }
+ return 0;
+}
+
/* Calls jnode_flush for current atom if it exists; if not, just take another
atom and call jnode_flush() for him. If current transaction handle has
already assigned atom (current atom) we have to close current transaction
@@ -1397,6 +1442,7 @@ reiser4_internal int
flush_some_atom(long *nr_submitted, const struct writeback_control *wbc, int flags)
{
reiser4_context *ctx = get_current_context();
+ txn_mgr *tmgr = &get_super_private(ctx->super)->tmgr;
txn_handle *txnh = ctx->trans;
txn_atom *atom;
int ret;
@@ -1406,8 +1452,6 @@ flush_some_atom(long *nr_submitted, cons
repeat:
if (txnh->atom == NULL) {
/* current atom is available, take first from txnmgr */
- txn_mgr *tmgr = &get_super_private(ctx->super)->tmgr;
-
spin_lock_txnmgr(tmgr);
/* traverse the list of all atoms */
@@ -1463,6 +1507,12 @@ flush_some_atom(long *nr_submitted, cons
ret = flush_current_atom(flags, nr_submitted, &atom);
if (ret == 0) {
if (*nr_submitted == 0 || atom_should_commit_asap(atom)) {
+ if (atom->capture_count < tmgr->atom_min_size &&
+ !(atom->flags & ATOM_CANCEL_FUSION)) {
+ ret =txn_try_to_fuse_small_atom(tmgr, atom);
+ if (ret == -E_REPEAT)
+ goto repeat;
+ }
/* if early flushing could not make more nodes clean,
* or atom is too old/large,
* we force current atom to commit */
diff -puN fs/reiser4/txnmgr.h~reiser4-update fs/reiser4/txnmgr.h
--- linux-2.6.12-rc2-mm3/fs/reiser4/txnmgr.h~reiser4-update 2005-04-19 17:58:43.475932800 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/txnmgr.h 2005-04-19 17:58:43.529926145 +0400
@@ -161,7 +161,10 @@ typedef enum {
/* Certain flags may be set in the txn_atom->flags field. */
typedef enum {
/* Indicates that the atom should commit as soon as possible. */
- ATOM_FORCE_COMMIT = (1 << 0)
+ ATOM_FORCE_COMMIT = (1 << 0),
+ /* to avoid endless loop, mark the atom (which was considered as too
+ * small) after failed attempt to fuse it. */
+ ATOM_CANCEL_FUSION = (1 << 1)
} txn_flags;
/* Flags for controlling commit_txnh */
@@ -434,6 +437,7 @@ struct txn_mgr {
/* parameters. Adjustable through mount options. */
unsigned int atom_max_size;
unsigned int atom_max_age;
+ unsigned int atom_min_size;
/* max number of concurrent flushers for one atom, 0 - unlimited. */
unsigned int atom_max_flushers;
};
diff -puN fs/reiser4/vfs_ops.c~reiser4-update fs/reiser4/vfs_ops.c
--- linux-2.6.12-rc2-mm3/fs/reiser4/vfs_ops.c~reiser4-update 2005-04-19 17:58:43.480932184 +0400
+++ linux-2.6.12-rc2-mm3-vs/fs/reiser4/vfs_ops.c 2005-04-19 17:58:43.531925898 +0400
@@ -56,14 +56,14 @@
-/* our ->drop_inode() method. This is called by iput_final() when last
- * reference on inode is released */
+/* put_inode of super_operations
+
+ we use put_inode to call pre_delete method of file plugin if it is defined
+ and if inode is unlinked and if it is about to drop inode reference count to
+ 0. */
static void
-reiser4_drop_inode(struct inode *object)
+reiser4_put_inode(struct inode *inode)
{
+ reiser4_context ctx;
file_plugin *fplug;
- assert("nikita-2643", object != NULL);
-
- /* -not- creating context in this method, because it is frequently
- called and all existing ->not_linked() methods are one liners. */
+ fplug = inode_file_plugin(inode);
+ if (fplug == NULL ||
+ inode->i_nlink != 0 ||
+ atomic_read(&inode->i_count) > 1 ||
+ fplug->pre_delete == NULL)
+ return;
- fplug = inode_file_plugin(object);
- /* fplug is NULL for fake inode */
- if (fplug != NULL) {
- assert("nikita-3251", fplug->drop != NULL);
- fplug->drop(object);
- } else
- generic_forget_inode(object);
+ init_context(&ctx, inode->i_sb);
+ /* kill cursors which might be attached to inode if it were a directory one */
+ kill_cursors(inode);
+ fplug->pre_delete(inode);
+ reiser4_exit_context(&ctx);
}
/*
@@ -955,6 +959,12 @@ do { \
decimal.
*/
PUSH_SB_FIELD_OPT(tmgr.atom_max_age, "%u");
+ /* tmgr.atom_min_size=N
+
+ In committing an atom to free dirty pages, force the atom less than N in
+ size to fuse with another one.
+ */
+ PUSH_SB_FIELD_OPT(tmgr.atom_min_size, "%u");
/* tmgr.atom_max_flushers=N
limit of concurrent flushers for one atom. 0 means no limit.
@@ -1047,6 +1057,7 @@ do { \