All of lore.kernel.org
 help / color / mirror / Atom feed
* + reiser4-granulate-rw-serialization-when-accessing-file-conversion-set.patch added to -mm tree
@ 2008-01-07 23:03 akpm
  0 siblings, 0 replies; only message in thread
From: akpm @ 2008-01-07 23:03 UTC (permalink / raw)
  To: mm-commits; +Cc: edward.shishkin


The patch titled
     reiser4: granulate rw-serialization when accessing file conversion set
has been added to the -mm tree.  Its filename is
     reiser4-granulate-rw-serialization-when-accessing-file-conversion-set.patch

*** Remember to use Documentation/SubmitChecklist when testing your code ***

See http://www.zip.com.au/~akpm/linux/patches/stuff/added-to-mm.txt to find
out what to do about this

The current -mm tree may be found at http://userweb.kernel.org/~akpm/mmotm/

------------------------------------------------------
Subject: reiser4: granulate rw-serialization when accessing file conversion set
From: Edward Shishkin <edward.shishkin@gmail.com>

Split common file plugin conversion procedure into
. plugin scheduling part
. plugin conversion part
Move the last one to the plugin-independent file operation
(reiser4_write_careful) with active protection of file
conversion set (conv_sem held).

Signed-off-by: Edward Shishkin <edward.shishkin@gmail.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---

 fs/reiser4/plugin/cluster.h              |    2 
 fs/reiser4/plugin/file/cryptcompress.c   |  102 +++----
 fs/reiser4/plugin/file/cryptcompress.h   |   16 -
 fs/reiser4/plugin/file/file.c            |   31 --
 fs/reiser4/plugin/file/file.h            |   21 +
 fs/reiser4/plugin/file/file_conversion.c |  296 +++++++++++----------
 fs/reiser4/plugin/file/tail_conversion.c |    4 
 fs/reiser4/plugin/object.c               |    2 
 fs/reiser4/plugin/plugin.h               |    9 
 9 files changed, 253 insertions(+), 230 deletions(-)

diff -puN fs/reiser4/plugin/cluster.h~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set fs/reiser4/plugin/cluster.h
--- a/fs/reiser4/plugin/cluster.h~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set
+++ a/fs/reiser4/plugin/cluster.h
@@ -333,6 +333,8 @@ int set_cluster_by_page(struct cluster_h
 			int count);
 int prepare_page_cluster(struct inode *inode, struct cluster_handle * clust,
 			 rw_op rw);
+void __put_page_cluster(int from, int count,
+			struct page ** pages, struct inode  * inode);
 void put_page_cluster(struct cluster_handle * clust,
 		      struct inode  * inode, rw_op rw);
 void put_cluster_handle(struct cluster_handle * clust);
diff -puN fs/reiser4/plugin/file/cryptcompress.c~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set fs/reiser4/plugin/file/cryptcompress.c
--- a/fs/reiser4/plugin/file/cryptcompress.c~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set
+++ a/fs/reiser4/plugin/file/cryptcompress.c
@@ -1343,8 +1343,8 @@ static void truncate_page_cluster_range(
 }
 
 /* Put @count pages starting from @from offset */
-static void __put_page_cluster(int from, int count,
-			       struct page ** pages, struct inode  * inode)
+void __put_page_cluster(int from, int count,
+			struct page ** pages, struct inode  * inode)
 {
 	int i;
 	assert("edward-1468", pages != NULL);
@@ -2637,7 +2637,7 @@ void reset_cluster_params(struct cluster
 /* the heart of write_cryptcompress */
 static loff_t do_write_cryptcompress(struct file *file, struct inode *inode,
 				     const char __user *buf, size_t to_write,
-				     loff_t pos, int *conv_occured)
+				     loff_t pos, struct psched_context *cont)
 {
 	int i;
 	hint_t *hint;
@@ -2647,6 +2647,7 @@ static loff_t do_write_cryptcompress(str
 	struct cluster_handle clust;
 	struct cryptcompress_info * info;
 
+	assert("edward-154", buf != NULL);
 	assert("edward-161", reiser4_schedulable());
 	assert("edward-748", cryptcompress_inode_ok(inode));
 	assert("edward-159", current_blocksize == PAGE_CACHE_SIZE);
@@ -2677,10 +2678,10 @@ static loff_t do_write_cryptcompress(str
 	if (next_window_stat(&win) == HOLE_WINDOW) {
 		/* write hole in this iteration
 		   separated from the loop below */
-		result = write_conversion_hook(file, inode,
-					       pos,
-					       &clust,
-					       NULL);
+		result = write_pschedule_hook(file, inode,
+					      pos,
+					      &clust,
+					      cont);
 		if (result)
 			goto out;
 		result = prepare_logical_cluster(inode, pos, count, &clust,
@@ -2694,12 +2695,15 @@ static loff_t do_write_cryptcompress(str
 
 		assert("edward-750", reiser4_schedulable());
 
-		result = write_conversion_hook(file, inode,
-					       pos + to_write - count,
-					       &clust,
-					       conv_occured);
-		if (result || *conv_occured)
+		result = write_pschedule_hook(file, inode,
+					      pos + to_write - count,
+					      &clust,
+					      cont);
+		if (result)
 			goto out;
+		if (cont->state == PSCHED_ASSIGNED_NEW)
+			goto out_no_release;
+
 		result = prepare_logical_cluster(inode, pos, count, &clust,
 						 LC_APPOV);
 		if (result)
@@ -2768,30 +2772,16 @@ static loff_t do_write_cryptcompress(str
 		break;
 	} while (count);
  out:
-	/*
-	 * NOTE: at this point file may have
-	 * another (unix-file) plugin installed
-	 */
 	done_lh(&hint->lh);
-	if (result == -EEXIST)
-		warning("edward-1407", "write returns EEXIST!\n");
-
-	put_cluster_handle(&clust);
+	mutex_unlock(&info->checkin_mutex);
 	save_file_hint(file, hint);
+ out_no_release:
 	kfree(hint);
-	/*
-	 * don't release cryptcompress-specific
-	 * checkin_mutex, if conversion occured
-	 */
-	if (*conv_occured == 0)
-		mutex_unlock(&info->checkin_mutex);
-	if (buf) {
-		/* if nothing were written - there must be an error */
-		assert("edward-195", ergo((to_write == count),
-					  (result < 0 || *conv_occured)));
-		return (to_write - count) ? (to_write - count) : result;
-	}
-	return result;
+	put_cluster_handle(&clust);
+	assert("edward-195",
+	       ergo((to_write == count),
+		    (result < 0 || cont->state == PSCHED_ASSIGNED_NEW)));
+	return (to_write - count) ? (to_write - count) : result;
 }
 
 /**
@@ -2802,7 +2792,8 @@ static loff_t do_write_cryptcompress(str
  * @off: position in file to write to
  */
 ssize_t write_cryptcompress(struct file *file, const char __user *buf,
-			    size_t count, loff_t *off, int *conv)
+			    size_t count, loff_t *off,
+			    struct psched_context *cont)
 {
 	ssize_t result;
 	struct inode *inode;
@@ -2810,41 +2801,37 @@ ssize_t write_cryptcompress(struct file 
   	loff_t pos = *off;
   	struct cryptcompress_info *info;
 
-  	assert("edward-1449", *conv == 0);
+  	assert("edward-1449", cont->state == PSCHED_INVAL_STATE);
 
 	inode = file->f_dentry->d_inode;
 	assert("edward-196", cryptcompress_inode_ok(inode));
 
 	info = cryptcompress_inode_data(inode);
-
-	ctx = reiser4_init_context(inode->i_sb);
-	if (IS_ERR(ctx))
-		return PTR_ERR(ctx);
-
- 	mutex_lock(&inode->i_mutex);
+	ctx = get_current_context();
 
 	result = generic_write_checks(file, &pos, &count, 0);
-  	if (unlikely(result != 0))
-		goto out;
+  	if (unlikely(result != 0)) {
+		context_set_commit_async(ctx);
+		return result;
+	}
   	if (unlikely(count == 0))
-		goto out;
+		return 0;
 	result = remove_suid(file->f_dentry);
-	if (unlikely(result != 0))
-		goto out;
+	if (unlikely(result != 0)) {
+		context_set_commit_async(ctx);
+		return result;
+	}
 	/* remove_suid might create a transaction */
 	reiser4_txn_restart(ctx);
 
-	result = do_write_cryptcompress(file, inode, buf, count, pos, conv);
+	result = do_write_cryptcompress(file, inode, buf, count, pos, cont);
 
-  	if (result < 0)
-		goto out;
+  	if (unlikely(result < 0)) {
+		context_set_commit_async(ctx);
+		return result;
+	}
   	/* update position in a file */
   	*off = pos + result;
- out:
-	mutex_unlock(&inode->i_mutex);
-
-	context_set_commit_async(ctx);
-	reiser4_exit_context(ctx);
 	return result;
 }
 
@@ -3705,7 +3692,12 @@ int setattr_cryptcompress(struct dentry 
 			ctx = reiser4_init_context(dentry->d_inode->i_sb);
 			if (IS_ERR(ctx))
 				return PTR_ERR(ctx);
-
+			result = setattr_pschedule_hook(inode);
+			if (result) {
+				context_set_commit_async(ctx);
+				reiser4_exit_context(ctx);
+				return result;
+			}
 			old_size = i_size_read(inode);
 			inode_check_scale(inode, old_size, attr->ia_size);
 
diff -puN fs/reiser4/plugin/file/cryptcompress.h~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set fs/reiser4/plugin/file/cryptcompress.h
--- a/fs/reiser4/plugin/file/cryptcompress.h~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set
+++ a/fs/reiser4/plugin/file/cryptcompress.h
@@ -448,6 +448,16 @@ static inline int alloc_cluster_pgset(st
 	return 0;
 }
 
+static inline void move_cluster_pgset(struct cluster_handle *clust,
+				      struct page ***pages, int * nr_pages)
+{
+	assert("edward-1545", clust != NULL && clust->pages != NULL);
+	assert("edward-1546", pages != NULL && *pages == NULL);
+	*pages = clust->pages;
+	*nr_pages = clust->nr_pages;
+	clust->pages = NULL;
+}
+
 static inline void free_cluster_pgset(struct cluster_handle * clust)
 {
 	assert("edward-951", clust->pages != NULL);
@@ -552,8 +562,10 @@ int bind_cryptcompress(struct inode *chi
 void destroy_inode_cryptcompress(struct inode * inode);
 int grab_page_cluster(struct inode *inode, struct cluster_handle * clust,
 		      rw_op rw);
-int write_conversion_hook(struct file *file, struct inode * inode, loff_t pos,
- 			  struct cluster_handle * clust, int * progress);
+int write_pschedule_hook(struct file *file, struct inode * inode,
+			 loff_t pos, struct cluster_handle * clust,
+			 struct psched_context * cont);
+int setattr_pschedule_hook(struct inode * inode);
 struct reiser4_crypto_info * inode_crypto_info(struct inode * inode);
 void inherit_crypto_info_common(struct inode * parent, struct inode * object,
 				int (*can_inherit)(struct inode * child,
diff -puN fs/reiser4/plugin/file/file.c~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set fs/reiser4/plugin/file/file.c
--- a/fs/reiser4/plugin/file/file.c~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set
+++ a/fs/reiser4/plugin/file/file.c
@@ -2077,17 +2077,17 @@ static void drop_access(struct unix_file
 			      __FILE__, __LINE__, __FUNCTION__, ## __VA_ARGS__)
 
 /**
- * write_unix_file - write of struct file_operations
+ * write_unix_file - private ->write() method of unix_file plugin.
+ *
  * @file: file to write to
  * @buf: address of user-space buffer
- * @write_amount: number of bytes to write
- * @off: position in file to write to
- *
- * This is implementation of vfs's write method of struct file_operations for
- * unix file plugin.
+ * @count: number of bytes to write
+ * @pos: position in file to write to
+ * @cont: unused argument, as we don't perform plugin conversion when being
+ * managed by unix_file plugin.
  */
 ssize_t write_unix_file(struct file *file, const char __user *buf,
-			size_t count, loff_t *pos, int *conv)
+			size_t count, loff_t *pos, struct psched_context *cont)
 {
 	int result;
 	reiser4_context *ctx;
@@ -2102,12 +2102,8 @@ ssize_t write_unix_file(struct file *fil
 	int ea;
 	loff_t new_size;
 
+	ctx = get_current_context();
 	inode = file->f_dentry->d_inode;
-	ctx = reiser4_init_context(inode->i_sb);
-	if (IS_ERR(ctx))
-		return PTR_ERR(ctx);
-
-	mutex_lock(&inode->i_mutex);
 
 	assert("vs-947", !reiser4_inode_get_flag(inode, REISER4_NO_SD));
 	assert("vs-9471", (!reiser4_inode_get_flag(inode, REISER4_PART_MIXED)));
@@ -2115,17 +2111,13 @@ ssize_t write_unix_file(struct file *fil
 	/* check amount of bytes to write and writing position */
 	result = generic_write_checks(file, pos, &count, 0);
 	if (result) {
-		mutex_unlock(&inode->i_mutex);
 		context_set_commit_async(ctx);
-		reiser4_exit_context(ctx);
 		return result;
 	}
 
 	result = remove_suid(file->f_dentry);
 	if (result) {
-		mutex_unlock(&inode->i_mutex);
 		context_set_commit_async(ctx);
-		reiser4_exit_context(ctx);
 		return result;
 	}
 	/* remove_suid might create a transaction */
@@ -2249,11 +2241,9 @@ ssize_t write_unix_file(struct file *fil
 		file_update_time(file);
 		result = reiser4_update_sd(inode);
 		if (result) {
-			mutex_unlock(&inode->i_mutex);
 			current->backing_dev_info = NULL;
 			drop_access(uf_info);
 			context_set_commit_async(ctx);
-			reiser4_exit_context(ctx);
 			return result;
 		}
 		drop_access(uf_info);
@@ -2272,9 +2262,6 @@ ssize_t write_unix_file(struct file *fil
 		buf += written;
 		*pos += written;
 	}
-
-	mutex_unlock(&inode->i_mutex);
-
 	if (result == 0 && ((file->f_flags & O_SYNC) || IS_SYNC(inode))) {
 		reiser4_txn_restart_current();
 		grab_space_enable();
@@ -2287,8 +2274,6 @@ ssize_t write_unix_file(struct file *fil
 
 	current->backing_dev_info = NULL;
 
-	reiser4_exit_context(ctx);
-
 	/*
 	 * return number of written bytes or error code if nothing is
 	 * written. Note, that it does not work correctly in case when
diff -puN fs/reiser4/plugin/file/file.h~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set fs/reiser4/plugin/file/file.h
--- a/fs/reiser4/plugin/file/file.h~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set
+++ a/fs/reiser4/plugin/file/file.h
@@ -8,6 +8,20 @@
 #if !defined( __REISER4_FILE_H__ )
 #define __REISER4_FILE_H__
 
+/* possible states when scheduling a new file plugin */
+typedef enum {
+	PSCHED_INVAL_STATE,    /* invalid state */
+	PSCHED_SCHED_POINT,    /* scheduling point has been achieved */
+	PSCHED_REMAINS_OLD,    /* made a decision to be managed by old plugin */
+	PSCHED_ASSIGNED_NEW    /* new plugin has been scheduled */
+} psched_state;
+
+struct psched_context {
+	int nr_pages;
+	struct page **pages;
+	psched_state state;
+};
+
 /**
  * Declarations of common/careful/generic methods.
  * Suppose ->foo() is a vs method (of f_ops, i_ops, or a_ops);
@@ -26,7 +40,7 @@
  */
 
 /* inode operations */
-int reiser4_setattr_careful(struct dentry *, struct iattr *);
+int reiser4_setattr(struct dentry *, struct iattr *);
 
 /* file operations */
 ssize_t reiser4_read_careful(struct file *, char __user *buf,
@@ -64,7 +78,7 @@ int setattr_unix_file(struct dentry *, s
 ssize_t read_unix_file(struct file *, char __user *buf, size_t read_amount,
 		       loff_t *off);
 ssize_t write_unix_file(struct file *, const char __user *buf, size_t write_amount,
-			loff_t * off, int * conv);
+			loff_t * off, struct psched_context * cont);
 int ioctl_unix_file(struct inode *, struct file *, unsigned int cmd,
 		    unsigned long arg);
 int mmap_unix_file(struct file *, struct vm_area_struct *);
@@ -101,7 +115,8 @@ int setattr_cryptcompress(struct dentry 
 ssize_t read_cryptcompress(struct file *, char __user *buf,
 			   size_t count, loff_t *off);
 ssize_t write_cryptcompress(struct file *, const char __user *buf,
-			    size_t count, loff_t * off, int *conv);
+			    size_t count, loff_t * off,
+			    struct psched_context *cont);
 int ioctl_cryptcompress(struct inode *, struct file *, unsigned int cmd,
 			unsigned long arg);
 int mmap_cryptcompress(struct file *, struct vm_area_struct *);
diff -puN fs/reiser4/plugin/file/file_conversion.c~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set fs/reiser4/plugin/file/file_conversion.c
--- a/fs/reiser4/plugin/file/file_conversion.c~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set
+++ a/fs/reiser4/plugin/file/file_conversion.c
@@ -1,17 +1,25 @@
 /* Copyright 2001, 2002, 2003 by Hans Reiser,
    licensing governed by reiser4/README */
 
-/* *
- * This file contains a converter cryptcompress->unix_file, and O(1)-heuristic,
- * which allows to assign for a regular file the most reasonable plugin to be
- * managed by. Note, that we don't perform back conversion because of
- * compatibility reasons (see http://dev.namesys.com/Version4.X.Y for details).
- *
- * Currently used heuristic is very simple: if first complete logical cluster
- * (64K by default) of a file is incompressible, then we make a decision, that
- * the whole file is incompressible (*). When creating a file the conversion
- * is enabled by default via installing a special "permitting" compression mode
- * plugin (**) (CONVX_COMPRESSION_MODE_ID, see plugin/compress/compress_mode.c
+/**
+ * This file contains plugin schedule hooks, and plugin conversion methods.
+ *
+ * Plugin schedule hook makes a decision (at plugin schedule point) about the
+ * most reasonable plugins for managing a regular file. Usually such decisions
+ * is made by some O(1)-heuristic.
+ *
+ * By default we assign a unix_file plugin id when writing incompressible file
+ * managed by cryptcompress plugin id. Currently used heuristic for estimating
+ * compressibility is very simple: if first complete logical cluster (64K by
+ * default) of a file is incompressible, then we make a decision, that the whole
+ * file is incompressible (*).
+ *
+ * To enable a conversion we install a special "magic" compression mode plugin
+ * (CONVX_COMPRESSION_MODE_ID, see plugin/compress/compress_mode.c for details)
+ * at file creation time (**).
+ *
+ * Note, that we don't perform back conversion (unix_file->cryptcompress)
+ * because of compatibility reasons (see http://dev.namesys.com/Version4.X.Y
  * for details).
  *
  * The conversion is accompanied by rebuilding disk structures of a file, so it
@@ -19,11 +27,12 @@
  * don't expect them to be in such inconsistent state. For this to be protected
  * we serialize readers and writers of a file's conversion set (FCS).
  *
- * We define FCS as a file plugin id installed in inode's pset all structures
- * specific for this id (like stat-data, etc. items). Note, that FCS is defined
- * per file.
+ * We define FCS as a file plugin installed in inode's pset plus file's data
+ * and metadata that this file plugin manipulates with (items, etc).
+ * Note, that FCS is defined per file.
  * FCS reader is defined as a set of instruction of the following type:
- * inode_file_plugin(inode)->method();
+ * {inode_file_plugin(inode)->method()} (I.e. retrieving a file plugin id
+ * conjoined with all method's instructions should be atomic).
  * FCS writer is a set of instructions that perform file plugin conversion
  * (convert items, update pset, etc).
  * Example:
@@ -48,7 +57,7 @@
  *
  * ---
  * (*)  This heuristic can be changed to a better one (benchmarking is needed).
- * (**) Such solution allows to keep enable/disable state on disk.
+ * (**) Such technique allows to keep enable/disable state on disk.
  */
 
 #include "../../inode.h"
@@ -71,9 +80,10 @@
 	 file_plugin_by_id(CRYPTCOMPRESS_FILE_PLUGIN_ID) &&		\
 	 conversion_enabled(inode))
 /**
- * We'll speak about "passive" protection for readers and "active"
- * protection for writers. All methods with active or passive protection
- * has suffix "careful".
+ * To avoid confusion with read/write file operations, we'll speak about
+ * "passive" protection for FCS readers and "active" protection for FCS
+ * writers. All methods with active or passive protection have suffix
+ * "careful".
  */
 /**
  * Macros for passive protection.
@@ -117,33 +127,6 @@
 		up_read(guard);						\
 })
 
-/**
- * This macro is for invariant methods which can be decomposed
- * into "active expression" that goes first and contains pset
- * writers (and, hence, needs serialization), and generic plugin
- * method which doesn't need serialization.
- *
- * The macro accepts the following lexemes:
- * @type - type of the value represented by the compound statement;
- * @method - name of invariant operation supplied to VFS;
- * @active_expr - name of "active expression", usually some O(1) -
- * heuristic for disabling a conversion.
- */
-#define PROT_ACTIVE(type, method, args, active_expr)			\
-({	                 						\
-	type _result = 0;						\
-	struct rw_semaphore * guard =					\
-		&reiser4_inode_data(inode)->conv_sem;			\
-									\
-	if (should_protect(inode)) {					\
-		down_write(guard);					\
-		if (should_protect(inode))				\
-			_result = active_expr;				\
-		up_write(guard);					\
-	}								\
-	_result = inode_file_plugin(inode)->method args;                \
-})
-
 /* Pass management to the unix-file plugin with "notail" policy */
 static int __cryptcompress2unixfile(struct file *file, struct inode * inode)
 {
@@ -206,9 +189,14 @@ static int disabled_conversion_inode_ok(
 }
 #endif
 
-/* Assign another mode that will control
-   compression at flush time only */
-static int disable_conversion_no_update_sd(struct inode * inode)
+/**
+ * Disable future attempts to schedule/convert file plugin.
+ * This function is called by plugin schedule hooks.
+ *
+ * To disable conversion we assign any compression mode plugin id
+ * different from CONVX_COMPRESSION_MODE_ID.
+ */
+static int disable_conversion(struct inode * inode)
 {
 	int result;
 	result =
@@ -221,17 +209,14 @@ static int disable_conversion_no_update_
 	return result;
 }
 
-/* Disable future attempts to check/convert. This function is called by
-   conversion hooks. */
-static int disable_conversion(struct inode * inode)
-{
-	return disable_conversion_no_update_sd(inode);
-}
-
-static int check_position(struct inode * inode,
-			  loff_t pos /* position in the file to write from */,
-			  struct cluster_handle * clust,
-			  int * check_compress)
+/**
+ * Check if we really have achieved plugin scheduling point
+ */
+static int check_psched_point(struct inode * inode,
+			      loff_t pos /* position in the
+					    file to write from */,
+			      struct cluster_handle * clust,
+			      struct psched_context * cont)
 {
 	assert("edward-1505", conversion_enabled(inode));
 	/*
@@ -255,8 +240,10 @@ static int check_position(struct inode *
 	assert("edward-1498",
 	       pos == inode->i_size &&
 	       pos == inode_cluster_size(inode));
+	assert("edward-1539", cont != NULL);
+	assert("edward-1540", cont->state == PSCHED_INVAL_STATE);
 
-	*check_compress = 1;
+	cont->state = PSCHED_SCHED_POINT;
 	return 0;
 }
 
@@ -310,17 +297,18 @@ static int prepped_dclust_ok(hint_t * hi
  * A simple O(1)-heuristic for compressibility.
  * This is called not more then one time per file's life.
  * Read first logical cluster (of index #0) and estimate its compressibility.
- * Save estimation result in @compressible.
+ * Save estimation result in @cont.
  */
 static int read_check_compressibility(struct inode * inode,
 				      struct cluster_handle * clust,
-				      int * compressible)
+				      struct psched_context * cont)
 {
 	int i;
 	int result;
 	__u32 dst_len;
 	hint_t tmp_hint;
 	hint_t * cur_hint = clust->hint;
+	assert("edward-1541", cont->state == PSCHED_SCHED_POINT);
 
 	start_check_compressibility(inode, clust, &tmp_hint);
 
@@ -383,8 +371,10 @@ static int read_check_compressibility(st
 		       dst_len <= tfm_stream_size(tc, OUTPUT_STREAM));
 	}
 	finish_check_compressibility(inode, clust, cur_hint);
-	*compressible = data_is_compressible(dst_len,
-					     inode_cluster_size(inode));
+	cont->state =
+		(data_is_compressible(dst_len, inode_cluster_size(inode)) ?
+		 PSCHED_REMAINS_OLD :
+		 PSCHED_ASSIGNED_NEW);
 	return 0;
  error:
 	put_page_cluster(clust, inode, READ_OP);
@@ -461,18 +451,17 @@ static int complete_file_conversion(stru
 	return 0;
 }
 
-
-/* do conversion */
+/**
+ * Convert cryptcompress file plugin to unix_file plugin.
+ */
 static int cryptcompress2unixfile(struct file * file, struct inode * inode,
-				  struct cluster_handle * clust)
+				  struct psched_context * cont)
 {
 	int i;
 	int result = 0;
 	struct cryptcompress_info *cr_info;
 	struct unix_file_info *uf_info;
-
-	assert("edward-1516", clust->pages[0]->index == 0);
-	assert("edward-1517", clust->hint != NULL);
+	assert("edward-1516", cont->pages[0]->index == 0);
 
 	/* release all cryptcompress-specific resources */
 	cr_info = cryptcompress_inode_data(inode);
@@ -480,7 +469,6 @@ static int cryptcompress2unixfile(struct
 	if (result)
 		goto out;
 	reiser4_inode_set_flag(inode, REISER4_FILE_CONV_IN_PROGRESS);
-	reiser4_unset_hint(clust->hint);
 	result = cut_disk_cluster(inode, 0);
 	if (result)
 		goto out;
@@ -496,13 +484,13 @@ static int cryptcompress2unixfile(struct
 	uf_info = unix_file_inode_data(inode);
 
 	assert("edward-1518",
-	       ergo(jprivate(clust->pages[0]),
-		    !jnode_is_cluster_page(jprivate(clust->pages[0]))));
-	for(i = 0; i < clust->nr_pages; i++) {
-		assert("edward-1519", clust->pages[i]);
-		assert("edward-1520", PageUptodate(clust->pages[i]));
+	       ergo(jprivate(cont->pages[0]),
+		    !jnode_is_cluster_page(jprivate(cont->pages[0]))));
+	for(i = 0; i < cont->nr_pages; i++) {
+		assert("edward-1519", cont->pages[i]);
+		assert("edward-1520", PageUptodate(cont->pages[i]));
 
-		result = find_or_create_extent(clust->pages[i]);
+		result = find_or_create_extent(cont->pages[i]);
 		if (result)
 			break;
 	}
@@ -518,42 +506,62 @@ static int cryptcompress2unixfile(struct
 	return result;
 }
 
-/* Check, then perform or disable conversion if needed */
-int write_conversion_hook(struct file * file, struct inode * inode, loff_t pos,
-			  struct cluster_handle * clust, int * progress)
+/**
+ * This is called by ->write() method of a cryptcompress file plugin.
+ * Make a decision about the most reasonable file plugin id to manage
+ * the file.
+ */
+int write_pschedule_hook(struct file * file, struct inode * inode,
+			 loff_t pos, struct cluster_handle * clust,
+			 struct psched_context * cont)
 {
 	int result;
-	int check_compress = 0;
-	int compressible = 0;
-
 	if (!conversion_enabled(inode))
 		return 0;
-	result = check_position(inode, pos, clust, &check_compress);
-	if (result || !check_compress)
+	result = check_psched_point(inode, pos, clust, cont);
+	if (result || cont->state != PSCHED_SCHED_POINT)
 		return result;
-	result = read_check_compressibility(inode, clust, &compressible);
+	result = read_check_compressibility(inode, clust, cont);
 	if (result)
 		return result;
-
-	/* At this point page cluster is grabbed and uptodate */
-	if (!compressible) {
-		result = cryptcompress2unixfile(file, inode, clust);
-		if (result == 0)
-			*progress = 1;
+	if (cont->state == PSCHED_REMAINS_OLD) {
+		put_page_cluster(clust, inode, READ_OP);
+		return disable_conversion(inode);
 	}
-	else
-		result = disable_conversion(inode);
+	assert("edward-1543", cont->state == PSCHED_ASSIGNED_NEW);
+	/*
+	 * page cluster is grabbed and uptodate. It will be
+	 * released with a pgset after plugin conversion is
+	 * finished, see put_psched_context().
+	 */
+	reiser4_unset_hint(clust->hint);
+	move_cluster_pgset(clust, &cont->pages, &cont->nr_pages);
+	return 0;
+}
 
-	reiser4_txn_restart_current();
-	put_page_cluster(clust, inode, READ_OP);
-	return result;
+/**
+ * This is called by ->setattr() method of cryptcompress file plugin.
+ */
+int setattr_pschedule_hook(struct inode * inode)
+{
+	if (conversion_enabled(inode))
+		return disable_conversion(inode);
+	return 0;
 }
 
-static int setattr_conversion_hook(struct inode * inode, struct iattr *attr)
+static inline void init_psched_context(struct psched_context * cont)
 {
-	return (attr->ia_valid & ATTR_SIZE ? disable_conversion(inode) : 0);
+	memset(cont, 0, sizeof(*cont));
 }
 
+static inline void done_psched_context(struct psched_context * cont,
+				       struct inode * inode)
+{
+	if (cont->pages) {
+		__put_page_cluster(0, cont->nr_pages, cont->pages, inode);
+		kfree(cont->pages);
+	}
+}
 /**
  * Here are wrappers with "protection", aka Reiser4 "careful" methods.
  * They are used by vfs (as methods of file_ops, inode_ops or as_ops),
@@ -564,51 +572,58 @@ static int setattr_conversion_hook(struc
  * Wrappers with active protection for:
  *
  * ->write();
- * ->setattr();
  */
 
 /*
- * Reiser4 invariant ->write() method supplied to VFS.
- * Write a file in 2 steps:
- *  . start write with initial file plugin,
- *    switch to a new (more resonable) file plugin (if any);
- *  . finish write with the new plugin.
+ * ->write() file operation supplied to VFS.
+ * Write a file in 3 steps (some of them can be optional).
  */
 ssize_t reiser4_write_careful(struct file *file, const char __user *buf,
 			      size_t count, loff_t *off)
 {
-	int prot = 0;
-	int conv = 0;
-	ssize_t written_old = 0; /* bytes written with old plugin */
+	int result;
+	reiser4_context *ctx;
+	ssize_t written_old = 0; /* bytes written with initial plugin */
 	ssize_t written_new = 0; /* bytes written with new plugin */
+	struct psched_context cont;
 	struct inode * inode = file->f_dentry->d_inode;
-	struct rw_semaphore * guard = &reiser4_inode_data(inode)->conv_sem;
 
+	ctx = reiser4_init_context(inode->i_sb);
+	if (IS_ERR(ctx))
+		return PTR_ERR(ctx);
+	init_psched_context(&cont);
+	mutex_lock(&inode->i_mutex);
 	/**
 	 * First step.
-	 * Check, if conversion is possible.
-	 * If yes, then ->write() method contains pset
-	 * writers, so active protection is required.
+	 * Start write with initial file plugin.
+	 * Keep a plugin schedule status at @cont (if any).
 	 */
-	if (should_protect(inode)) {
-		prot = 1;
-		down_write(guard);
-	}
 	written_old = inode_file_plugin(inode)->write(file,
 						      buf,
 						      count,
 						      off,
-						      &conv);
-	if (prot)
-		up_write(guard);
-	if (written_old < 0 || conv == 0)
-		return written_old;
+						      &cont);
+	if (cont.state != PSCHED_ASSIGNED_NEW || written_old < 0)
+		goto exit;
+	/**
+	 * Second step.
+	 * New file plugin has been scheduled.
+	 * Perform conversion to the new plugin.
+	 */
+	down_read(&reiser4_inode_data(inode)->conv_sem);
+	result = cryptcompress2unixfile(file, inode, &cont);
+	up_read(&reiser4_inode_data(inode)->conv_sem);
+	if (result) {
+		warning("edward-1544", "file conversion failed: %d", result);
+		context_set_commit_async(ctx);
+		goto exit;
+	}
+	reiser4_txn_restart(ctx);
 	/**
-	 * Conversion occurred.
-	 * Back conversion is impossible, so at
-	 * this step protection is not required.
+	 * Third step:
+	 * Finish write with the new file plugin.
 	 */
-	assert("edward-1532",
+	assert("edward-1536",
 	       inode_file_plugin(inode) ==
 	       file_plugin_by_id(UNIX_FILE_PLUGIN_ID));
 
@@ -617,21 +632,12 @@ ssize_t reiser4_write_careful(struct fil
 						      count - written_old,
 						      off,
 						      NULL);
-	return written_old + (written_new < 0 ? 0 : written_new);
-}
-
-int reiser4_setattr_careful(struct dentry *dentry, struct iattr *attr)
-{
-	int result;
-	struct inode * inode = dentry->d_inode;
-	reiser4_context * ctx =	reiser4_init_context(inode->i_sb);
-	if (IS_ERR(ctx))
-		return PTR_ERR(ctx);
-
-	result = PROT_ACTIVE(int, setattr, (dentry, attr),
-			     setattr_conversion_hook(inode, attr));
+ exit:
+	mutex_unlock(&inode->i_mutex);
+	done_psched_context(&cont, inode);
 	reiser4_exit_context(ctx);
-	return result;
+
+	return written_old + (written_new < 0 ? 0 : written_new);
 }
 
 /* Wrappers with passive protection for:
@@ -680,6 +686,16 @@ sector_t reiser4_bmap_careful(struct add
 }
 
 /*
+ * Wrappers without protection for:
+ *
+ * ->setattr()
+ */
+int reiser4_setattr(struct dentry *dentry, struct iattr *attr)
+{
+	return inode_file_plugin(dentry->d_inode)->setattr(dentry, attr);
+}
+
+/*
   Local variables:
   c-indentation-style: "K&R"
   mode-name: "LC"
diff -puN fs/reiser4/plugin/file/tail_conversion.c~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set fs/reiser4/plugin/file/tail_conversion.c
--- a/fs/reiser4/plugin/file/tail_conversion.c~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set
+++ a/fs/reiser4/plugin/file/tail_conversion.c
@@ -646,9 +646,9 @@ int extent2tail(struct file * file, stru
 		while (count) {
 			loff_t pos = start_byte;
 
-			assert("edward-1533",
+			assert("edward-1537",
 			       file != NULL && file->f_dentry != NULL);
-			assert("edward-1534",
+			assert("edward-1538",
 			       file->f_dentry->d_inode == inode);
 
 			result = reiser4_write_tail(file,
diff -puN fs/reiser4/plugin/object.c~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set fs/reiser4/plugin/object.c
--- a/fs/reiser4/plugin/object.c~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set
+++ a/fs/reiser4/plugin/object.c
@@ -91,7 +91,7 @@ static struct address_space_operations n
 /* VFS methods for regular files */
 static struct inode_operations regular_file_i_ops = {
 	.permission = reiser4_permission_common,
-	.setattr = reiser4_setattr_careful,
+	.setattr = reiser4_setattr,
 	.getattr = reiser4_getattr_common
 };
 static struct file_operations regular_file_f_ops = {
diff -puN fs/reiser4/plugin/plugin.h~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set fs/reiser4/plugin/plugin.h
--- a/fs/reiser4/plugin/plugin.h~reiser4-granulate-rw-serialization-when-accessing-file-conversion-set
+++ a/fs/reiser4/plugin/plugin.h
@@ -228,11 +228,12 @@ typedef struct file_plugin {
 	int (*open) (struct inode * inode, struct file * file);
 	ssize_t (*read) (struct file *, char __user *buf, size_t read_amount,
 			loff_t *off);
-	/* write a file;
-	 * perform file plugin conversion (if needed);
-	 * set @*conv to 1, if the conversion occurred */
+	/* write as much as possible bytes from nominated @write_amount
+	 * before plugin scheduling is occurred. Save scheduling state
+	 * in @cont */
 	ssize_t (*write) (struct file *, const char __user *buf,
-			  size_t write_amount, loff_t * off, int * conv);
+			  size_t write_amount, loff_t * off,
+			  struct psched_context * cont);
 	int (*ioctl) (struct inode *inode, struct file *filp,
 		      unsigned int cmd, unsigned long arg);
 	int (*mmap) (struct file *, struct vm_area_struct *);
_

Patches currently in -mm which might be from edward.shishkin@gmail.com are

reiser4-replace-uid==0-check-with-capability.patch
reiser4-specify-splice-file-operations.patch
reiser4-fix-dummy-ioctl_cryptcompress.patch
reiser4-granulate-rw-serialization-when-accessing-file-conversion-set.patch
reiser4-fix-disk-cluster-synchronization.patch
reiser4-use-balance_dirty_pages_ratelimited_nr.patch

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2008-01-07 23:04 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-01-07 23:03 + reiser4-granulate-rw-serialization-when-accessing-file-conversion-set.patch added to -mm tree akpm

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.