revert-mm-fix-blkdev-size-calculation-in-generic_write_checks
[linux-2.6/linux-trees-mm.git] / fs / reiser4 / plugin / file / file_conversion.c
blobd9b510bc27d529790bc2acc36860192c927f7b87
1 /* Copyright 2001, 2002, 2003 by Hans Reiser,
2 licensing governed by reiser4/README */
4 /* This file contains hooks that converts (*) cryptcompress files to unix-files,
5 and a set of protected (**) methods of a cryptcompress file plugin to perform
6 such conversion.
8 (*)
9 The conversion is performed for incompressible files to reduce cpu and memory
10 usage. If first logical cluster (64K by default) of a file is incompressible,
11 then we make a desicion, that the whole file is incompressible.
12 The conversion can be enabled via installing a special compression mode
13 plugin (CONVX_COMPRESSION_MODE_ID, see plugin/compress/compress_mode.c for
14 details).
16 (**)
17 The protection means serialization of critical sections (readers and writers
18 of @pset->file)
21 #include "../../inode.h"
22 #include "../cluster.h"
23 #include "file.h"
25 #define conversion_enabled(inode) \
26 (inode_compression_mode_plugin(inode) == \
27 compression_mode_plugin_by_id(CONVX_COMPRESSION_MODE_ID))
30 /* Located sections (readers and writers of @pset->file) are not
31 permanently critical: cryptcompress file can be converted only
32 if the conversion is enabled (see the macrio above). And we don't
33 convert unix files at all.
34 The following helper macro is a sanity check to decide if we
35 need to protect a located section.
37 #define should_protect(inode) \
38 (inode_file_plugin(inode) == \
39 file_plugin_by_id(CRYPTCOMPRESS_FILE_PLUGIN_ID) && \
40 conversion_enabled(inode))
42 /* All protected methods have prefix "prot" in their names.
43 It is convenient to construct them by usual (unprotected) ones
44 using the following common macros:
47 /* Macro for passive protection.
48 method_cryptcompress contains only readers */
49 #define PROT_PASSIVE(type, method, args) \
50 ({ \
51 type _result; \
52 struct rw_semaphore * guard = \
53 &reiser4_inode_data(inode)->conv_sem; \
55 if (should_protect(inode)) { \
56 down_read(guard); \
57 if (!should_protect(inode)) \
58 up_read(guard); \
59 } \
60 if (inode_file_plugin(inode) == \
61 file_plugin_by_id(UNIX_FILE_PLUGIN_ID)) \
62 _result = method ## _unix_file args; \
63 else \
64 _result = method ## _cryptcompress args; \
65 if (should_protect(inode)) \
66 up_read(guard); \
67 _result; \
70 #define PROT_PASSIVE_VOID(method, args) \
71 ({ \
72 struct rw_semaphore * guard = \
73 &reiser4_inode_data(inode)->conv_sem; \
75 if (should_protect(inode)) { \
76 down_read(guard); \
77 if (!should_protect(inode)) \
78 up_read(guard); \
79 } \
80 if (inode_file_plugin(inode) == \
81 file_plugin_by_id(UNIX_FILE_PLUGIN_ID)) \
82 method ## _unix_file args; \
83 else \
84 method ## _cryptcompress args; \
85 if (should_protect(inode)) \
86 up_read(guard); \
89 /* Macro for active protection.
90 active_expr contains readers and writers; after its
91 evaluation conversion should be disabled */
92 #define PROT_ACTIVE(type, method, args, active_expr) \
93 ({ \
94 type _result = 0; \
95 struct rw_semaphore * guard = \
96 &reiser4_inode_data(inode)->conv_sem; \
97 reiser4_context * ctx = reiser4_init_context(inode->i_sb); \
98 if (IS_ERR(ctx)) \
99 return PTR_ERR(ctx); \
101 if (should_protect(inode)) { \
102 down_write(guard); \
103 if (should_protect(inode)) \
104 _result = active_expr; \
105 up_write(guard); \
107 if (_result == 0) { \
108 if (inode_file_plugin(inode) == \
109 file_plugin_by_id(UNIX_FILE_PLUGIN_ID)) \
110 _result = method ## _unix_file args; \
111 else \
112 _result = method ## _cryptcompress args; \
114 reiser4_exit_context(ctx); \
115 _result; \
118 /* Pass management to the unix-file plugin with "notail" policy */
119 static int __cryptcompress2unixfile(struct file *file, struct inode * inode)
121 int result;
122 reiser4_inode *info;
123 struct unix_file_info * uf;
124 info = reiser4_inode_data(inode);
126 result = aset_set_unsafe(&info->pset,
127 PSET_FILE,
128 (reiser4_plugin *)
129 file_plugin_by_id(UNIX_FILE_PLUGIN_ID));
130 if (result)
131 return result;
132 result = aset_set_unsafe(&info->pset,
133 PSET_FORMATTING,
134 (reiser4_plugin *)
135 formatting_plugin_by_id(NEVER_TAILS_FORMATTING_ID));
136 if (result)
137 return result;
138 /* get rid of non-standard plugins */
139 info->plugin_mask &= ~cryptcompress_mask;
140 /* get rid of plugin stat-data extension */
141 info->extmask &= ~(1 << PLUGIN_STAT);
143 reiser4_inode_clr_flag(inode, REISER4_SDLEN_KNOWN);
145 /* FIXME use init_inode_data_unix_file() instead,
146 but aviod init_inode_ordering() */
147 /* Init unix-file specific part of inode */
148 uf = unix_file_inode_data(inode);
149 uf->container = UF_CONTAINER_UNKNOWN;
150 init_rwsem(&uf->latch);
151 uf->tplug = inode_formatting_plugin(inode);
152 uf->exclusive_use = 0;
153 #if REISER4_DEBUG
154 uf->ea_owner = NULL;
155 atomic_set(&uf->nr_neas, 0);
156 #endif
157 inode->i_op =
158 &file_plugin_by_id(UNIX_FILE_PLUGIN_ID)->inode_ops;
159 inode->i_fop =
160 &file_plugin_by_id(UNIX_FILE_PLUGIN_ID)->file_ops;
161 inode->i_mapping->a_ops =
162 &file_plugin_by_id(UNIX_FILE_PLUGIN_ID)->as_ops;
163 file->f_op = inode->i_fop;
164 return 0;
167 #if REISER4_DEBUG
168 static int disabled_conversion_inode_ok(struct inode * inode)
170 __u64 extmask = reiser4_inode_data(inode)->extmask;
171 __u16 plugin_mask = reiser4_inode_data(inode)->plugin_mask;
173 return ((extmask & (1 << LIGHT_WEIGHT_STAT)) &&
174 (extmask & (1 << UNIX_STAT)) &&
175 (extmask & (1 << LARGE_TIMES_STAT)) &&
176 (extmask & (1 << PLUGIN_STAT)) &&
177 (plugin_mask & (1 << PSET_COMPRESSION_MODE)));
179 #endif
181 /* Assign another mode that will control
182 compression at flush time only */
183 static int disable_conversion_no_update_sd(struct inode * inode)
185 int result;
186 result =
187 force_plugin_pset(inode,
188 PSET_COMPRESSION_MODE,
189 (reiser4_plugin *)compression_mode_plugin_by_id
190 (LATTD_COMPRESSION_MODE_ID));
191 assert("edward-1500",
192 ergo(!result, disabled_conversion_inode_ok(inode)));
193 return result;
196 /* Disable future attempts to check/convert. This function is called by
197 conversion hooks. */
198 static int disable_conversion(struct inode * inode)
200 return disable_conversion_no_update_sd(inode);
203 static int check_position(struct inode * inode,
204 loff_t pos /* position in the file to write from */,
205 struct cluster_handle * clust,
206 int * check_compress)
208 assert("edward-1505", conversion_enabled(inode));
210 * if file size is more then cluster size, then compressible
211 * status must be figured out (i.e. compression was disabled,
212 * or file plugin was converted to unix_file)
214 assert("edward-1506", inode->i_size <= inode_cluster_size(inode));
216 if (pos > inode->i_size)
217 /* first logical cluster will contain a (partial) hole */
218 return disable_conversion(inode);
219 if (pos < inode_cluster_size(inode))
220 /* writing to the first logical cluster */
221 return 0;
223 * here we have:
224 * cluster_size <= pos <= i_size <= cluster_size,
225 * and, hence, pos == i_size == cluster_size
227 assert("edward-1498",
228 pos == inode->i_size &&
229 pos == inode_cluster_size(inode));
231 *check_compress = 1;
232 return 0;
235 static void start_check_compressibility(struct inode * inode,
236 struct cluster_handle * clust,
237 hint_t * hint)
239 assert("edward-1507", clust->index == 1);
240 assert("edward-1508", !tfm_cluster_is_uptodate(&clust->tc));
241 assert("edward-1509", cluster_get_tfm_act(&clust->tc) == TFMA_READ);
243 hint_init_zero(hint);
244 clust->hint = hint;
245 clust->index --;
246 clust->nr_pages = size_in_pages(lbytes(clust->index, inode));
248 /* first logical cluster (of index #0) must be complete */
249 assert("edward-1510", lbytes(clust->index, inode) ==
250 inode_cluster_size(inode));
253 static void finish_check_compressibility(struct inode * inode,
254 struct cluster_handle * clust,
255 hint_t * hint)
257 reiser4_unset_hint(clust->hint);
258 clust->hint = hint;
259 clust->index ++;
262 #if REISER4_DEBUG
263 static int prepped_dclust_ok(hint_t * hint)
265 reiser4_key key;
266 coord_t * coord = &hint->ext_coord.coord;
268 item_key_by_coord(coord, &key);
269 return (item_id_by_coord(coord) == CTAIL_ID &&
270 !coord_is_unprepped_ctail(coord) &&
271 (get_key_offset(&key) + nr_units_ctail(coord) ==
272 dclust_get_extension_dsize(hint)));
274 #endif
276 #define fifty_persent(size) (size >> 1)
277 /* evaluation of data compressibility */
278 #define data_is_compressible(osize, isize) \
279 (osize < fifty_persent(isize))
281 /* This is called only once per file life.
282 Read first logical cluster (of index #0) and estimate its compressibility.
283 Save estimation result in @compressible */
284 static int read_check_compressibility(struct inode * inode,
285 struct cluster_handle * clust,
286 int * compressible)
288 int i;
289 int result;
290 __u32 dst_len;
291 hint_t tmp_hint;
292 hint_t * cur_hint = clust->hint;
294 start_check_compressibility(inode, clust, &tmp_hint);
296 reset_cluster_pgset(clust, cluster_nrpages(inode));
297 result = grab_page_cluster(inode, clust, READ_OP);
298 if (result)
299 return result;
300 /* Read page cluster here */
301 for (i = 0; i < clust->nr_pages; i++) {
302 struct page *page = clust->pages[i];
303 lock_page(page);
304 result = do_readpage_ctail(inode, clust, page,
305 ZNODE_READ_LOCK);
306 unlock_page(page);
307 if (result)
308 goto error;
310 tfm_cluster_clr_uptodate(&clust->tc);
312 cluster_set_tfm_act(&clust->tc, TFMA_WRITE);
314 if (hint_is_valid(&tmp_hint) && !hint_is_unprepped_dclust(&tmp_hint)) {
315 /* lenght of compressed data is known, no need to compress */
316 assert("edward-1511",
317 znode_is_any_locked(tmp_hint.lh.node));
318 assert("edward-1512",
319 WITH_DATA(tmp_hint.ext_coord.coord.node,
320 prepped_dclust_ok(&tmp_hint)));
321 dst_len = dclust_get_extension_dsize(&tmp_hint);
323 else {
324 struct tfm_cluster * tc = &clust->tc;
325 compression_plugin * cplug = inode_compression_plugin(inode);
326 result = grab_tfm_stream(inode, tc, INPUT_STREAM);
327 if (result)
328 goto error;
329 for (i = 0; i < clust->nr_pages; i++) {
330 char *data;
331 lock_page(clust->pages[i]);
332 BUG_ON(!PageUptodate(clust->pages[i]));
333 data = kmap(clust->pages[i]);
334 memcpy(tfm_stream_data(tc, INPUT_STREAM) + pg_to_off(i),
335 data, PAGE_CACHE_SIZE);
336 kunmap(clust->pages[i]);
337 unlock_page(clust->pages[i]);
339 result = grab_tfm_stream(inode, tc, OUTPUT_STREAM);
340 if (result)
341 goto error;
342 result = grab_coa(tc, cplug);
343 if (result)
344 goto error;
345 tc->len = tc->lsize = lbytes(clust->index, inode);
346 assert("edward-1513", tc->len == inode_cluster_size(inode));
347 dst_len = tfm_stream_size(tc, OUTPUT_STREAM);
348 cplug->compress(get_coa(tc, cplug->h.id, tc->act),
349 tfm_input_data(clust), tc->len,
350 tfm_output_data(clust), &dst_len);
351 assert("edward-1514",
352 dst_len <= tfm_stream_size(tc, OUTPUT_STREAM));
354 finish_check_compressibility(inode, clust, cur_hint);
355 *compressible = data_is_compressible(dst_len,
356 inode_cluster_size(inode));
357 return 0;
358 error:
359 put_page_cluster(clust, inode, READ_OP);
360 return result;
363 /* Cut disk cluster of index @idx */
364 static int cut_disk_cluster(struct inode * inode, cloff_t idx)
366 reiser4_key from, to;
367 assert("edward-1515", inode_file_plugin(inode) ==
368 file_plugin_by_id(CRYPTCOMPRESS_FILE_PLUGIN_ID));
369 key_by_inode_cryptcompress(inode, clust_to_off(idx, inode), &from);
370 to = from;
371 set_key_offset(&to,
372 get_key_offset(&from) + inode_cluster_size(inode) - 1);
373 return reiser4_cut_tree(reiser4_tree_by_inode(inode),
374 &from, &to, inode, 0);
377 static int reserve_cryptcompress2unixfile(struct inode *inode)
379 reiser4_block_nr unformatted_nodes;
380 reiser4_tree *tree;
382 tree = reiser4_tree_by_inode(inode);
384 /* number of unformatted nodes which will be created */
385 unformatted_nodes = cluster_nrpages(inode); /* N */
388 * space required for one iteration of extent->tail conversion:
390 * 1. kill ctail items
392 * 2. insert N unformatted nodes
394 * 3. insert N (worst-case single-block
395 * extents) extent units.
397 * 4. drilling to the leaf level by coord_by_key()
399 * 5. possible update of stat-data
402 grab_space_enable();
403 return reiser4_grab_space
404 (2 * tree->height +
405 unformatted_nodes +
406 unformatted_nodes * estimate_one_insert_into_item(tree) +
407 1 + estimate_one_insert_item(tree) +
408 inode_file_plugin(inode)->estimate.update(inode),
409 BA_CAN_COMMIT);
412 /* clear flag that indicated conversion and update
413 stat-data with new (unix-file - specific) info */
414 static int complete_file_conversion(struct inode *inode)
416 int result;
418 grab_space_enable();
419 result =
420 reiser4_grab_space(inode_file_plugin(inode)->estimate.update(inode),
421 BA_CAN_COMMIT);
422 if (result == 0) {
423 reiser4_inode_clr_flag(inode, REISER4_FILE_CONV_IN_PROGRESS);
424 result = reiser4_update_sd(inode);
426 if (result)
427 warning("edward-1452",
428 "Converting %llu to unix-file: update sd failed (%i)",
429 (unsigned long long)get_inode_oid(inode), result);
430 return 0;
434 /* do conversion */
435 static int cryptcompress2unixfile(struct file * file, struct inode * inode,
436 struct cluster_handle * clust)
438 int i;
439 int result = 0;
440 struct cryptcompress_info *cr_info;
441 struct unix_file_info *uf_info;
443 assert("edward-1516", clust->pages[0]->index == 0);
444 assert("edward-1517", clust->hint != NULL);
446 /* release all cryptcompress-specific recources */
447 cr_info = cryptcompress_inode_data(inode);
448 result = reserve_cryptcompress2unixfile(inode);
449 if (result)
450 goto out;
451 reiser4_inode_set_flag(inode, REISER4_FILE_CONV_IN_PROGRESS);
452 reiser4_unset_hint(clust->hint);
453 result = cut_disk_cluster(inode, 0);
454 if (result)
455 goto out;
456 /* captured jnode of cluster and assotiated resources (pages,
457 reserved disk space) were released by ->kill_hook() method
458 of the item plugin */
460 result = __cryptcompress2unixfile(file, inode);
461 if (result)
462 goto out;
463 /* At this point file is managed by unix file plugin */
465 uf_info = unix_file_inode_data(inode);
467 assert("edward-1518",
468 ergo(jprivate(clust->pages[0]),
469 !jnode_is_cluster_page(jprivate(clust->pages[0]))));
470 for(i = 0; i < clust->nr_pages; i++) {
471 assert("edward-1519", clust->pages[i]);
472 assert("edward-1520", PageUptodate(clust->pages[i]));
474 result = find_or_create_extent(clust->pages[i]);
475 if (result)
476 break;
478 if (!result) {
479 uf_info->container = UF_CONTAINER_EXTENTS;
480 complete_file_conversion(inode);
482 out:
483 all_grabbed2free();
484 if (result)
485 warning("edward-1453", "Failed to convert file %llu: ret=%i",
486 (unsigned long long)get_inode_oid(inode), result);
487 return result;
490 /* Check, then perform or disable conversion if needed */
491 int write_conversion_hook(struct file * file, struct inode * inode, loff_t pos,
492 struct cluster_handle * clust, int * progress)
494 int result;
495 int check_compress = 0;
496 int compressible = 0;
498 if (!conversion_enabled(inode))
499 return 0;
500 result = check_position(inode, pos, clust, &check_compress);
501 if (result || !check_compress)
502 return result;
503 result = read_check_compressibility(inode, clust, &compressible);
504 if (result)
505 return result;
507 /* At this point page cluster is grabbed and uptodate */
508 if (!compressible) {
509 result = cryptcompress2unixfile(file, inode, clust);
510 if (result == 0)
511 *progress = 1;
513 else
514 result = disable_conversion(inode);
516 reiser4_txn_restart_current();
517 put_page_cluster(clust, inode, READ_OP);
518 return result;
521 static int setattr_conversion_hook(struct inode * inode, struct iattr *attr)
523 return (attr->ia_valid & ATTR_SIZE ? disable_conversion(inode) : 0);
526 /* Protected methods of cryptcompress file plugin constructed
527 by the macros above */
529 /* Wrappers with active protection for:
530 . write_cryptcompress;
531 . setattr_cryptcompress;
534 ssize_t prot_write_cryptcompress(struct file *file, const char __user *buf,
535 size_t count, loff_t *off)
537 int prot = 0;
538 int conv = 0;
539 ssize_t written_cr = 0;
540 ssize_t written_uf = 0;
541 struct inode * inode = file->f_dentry->d_inode;
542 struct rw_semaphore * guard = &reiser4_inode_data(inode)->conv_sem;
544 if (should_protect(inode)) {
545 prot = 1;
546 down_write(guard);
548 written_cr = write_cryptcompress(file, buf, count, off, &conv);
549 if (prot)
550 up_write(guard);
551 if (written_cr < 0)
552 return written_cr;
553 if (conv)
554 written_uf = write_unix_file(file, buf + written_cr,
555 count - written_cr, off);
556 return written_cr + (written_uf < 0 ? 0 : written_uf);
559 int prot_setattr_cryptcompress(struct dentry *dentry, struct iattr *attr)
561 struct inode * inode = dentry->d_inode;
562 return PROT_ACTIVE(int, setattr, (dentry, attr),
563 setattr_conversion_hook(inode, attr));
566 /* Wrappers with passive protection for:
567 . read_cryptcomperess;
568 . mmap_cryptcompress;
569 . release_cryptcompress;
570 . delete_object_cryptcompress.
572 ssize_t prot_read_cryptcompress(struct file * file, char __user * buf,
573 size_t size, loff_t * off)
575 struct inode * inode = file->f_dentry->d_inode;
576 return PROT_PASSIVE(ssize_t, read, (file, buf, size, off));
579 int prot_mmap_cryptcompress(struct file *file, struct vm_area_struct *vma)
581 struct inode *inode = file->f_dentry->d_inode;
582 return PROT_PASSIVE(int, mmap, (file, vma));
585 int prot_release_cryptcompress(struct inode *inode, struct file *file)
587 return PROT_PASSIVE(int, release, (inode, file));
591 Local variables:
592 c-indentation-style: "K&R"
593 mode-name: "LC"
594 c-basic-offset: 8
595 tab-width: 8
596 fill-column: 80
597 scroll-step: 1
598 End: