From: Edward Shishkin 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 Signed-off-by: Andrew Morton --- 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 *); _