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
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
17 The protection means serialization of critical sections (readers and writers
21 #include "../../inode.h"
22 #include "../cluster.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) \
52 struct rw_semaphore * guard = \
53 &reiser4_inode_data(inode)->conv_sem; \
55 if (should_protect(inode)) { \
57 if (!should_protect(inode)) \
60 if (inode_file_plugin(inode) == \
61 file_plugin_by_id(UNIX_FILE_PLUGIN_ID)) \
62 _result = method ## _unix_file args; \
64 _result = method ## _cryptcompress args; \
65 if (should_protect(inode)) \
70 #define PROT_PASSIVE_VOID(method, args) \
72 struct rw_semaphore * guard = \
73 &reiser4_inode_data(inode)->conv_sem; \
75 if (should_protect(inode)) { \
77 if (!should_protect(inode)) \
80 if (inode_file_plugin(inode) == \
81 file_plugin_by_id(UNIX_FILE_PLUGIN_ID)) \
82 method ## _unix_file args; \
84 method ## _cryptcompress args; \
85 if (should_protect(inode)) \
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) \
95 struct rw_semaphore * guard = \
96 &reiser4_inode_data(inode)->conv_sem; \
97 reiser4_context * ctx = reiser4_init_context(inode->i_sb); \
99 return PTR_ERR(ctx); \
101 if (should_protect(inode)) { \
103 if (should_protect(inode)) \
104 _result = active_expr; \
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; \
112 _result = method ## _cryptcompress args; \
114 reiser4_exit_context(ctx); \
118 /* Pass management to the unix-file plugin with "notail" policy */
119 static int __cryptcompress2unixfile(struct file
*file
, struct inode
* inode
)
123 struct unix_file_info
* uf
;
124 info
= reiser4_inode_data(inode
);
126 result
= aset_set_unsafe(&info
->pset
,
129 file_plugin_by_id(UNIX_FILE_PLUGIN_ID
));
132 result
= aset_set_unsafe(&info
->pset
,
135 formatting_plugin_by_id(NEVER_TAILS_FORMATTING_ID
));
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;
155 atomic_set(&uf
->nr_neas
, 0);
158 &file_plugin_by_id(UNIX_FILE_PLUGIN_ID
)->inode_ops
;
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
;
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
)));
181 /* Assign another mode that will control
182 compression at flush time only */
183 static int disable_conversion_no_update_sd(struct inode
* inode
)
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
)));
196 /* Disable future attempts to check/convert. This function is called by
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 */
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
));
235 static void start_check_compressibility(struct inode
* inode
,
236 struct cluster_handle
* clust
,
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
);
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
,
257 reiser4_unset_hint(clust
->hint
);
263 static int prepped_dclust_ok(hint_t
* hint
)
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
)));
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
,
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
);
300 /* Read page cluster here */
301 for (i
= 0; i
< clust
->nr_pages
; i
++) {
302 struct page
*page
= clust
->pages
[i
];
304 result
= do_readpage_ctail(inode
, clust
, page
,
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
);
324 struct tfm_cluster
* tc
= &clust
->tc
;
325 compression_plugin
* cplug
= inode_compression_plugin(inode
);
326 result
= grab_tfm_stream(inode
, tc
, INPUT_STREAM
);
329 for (i
= 0; i
< clust
->nr_pages
; i
++) {
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
);
342 result
= grab_coa(tc
, cplug
);
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
));
359 put_page_cluster(clust
, inode
, READ_OP
);
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
);
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
;
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
403 return reiser4_grab_space
406 unformatted_nodes
* estimate_one_insert_into_item(tree
) +
407 1 + estimate_one_insert_item(tree
) +
408 inode_file_plugin(inode
)->estimate
.update(inode
),
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
)
420 reiser4_grab_space(inode_file_plugin(inode
)->estimate
.update(inode
),
423 reiser4_inode_clr_flag(inode
, REISER4_FILE_CONV_IN_PROGRESS
);
424 result
= reiser4_update_sd(inode
);
427 warning("edward-1452",
428 "Converting %llu to unix-file: update sd failed (%i)",
429 (unsigned long long)get_inode_oid(inode
), result
);
435 static int cryptcompress2unixfile(struct file
* file
, struct inode
* inode
,
436 struct cluster_handle
* clust
)
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
);
451 reiser4_inode_set_flag(inode
, REISER4_FILE_CONV_IN_PROGRESS
);
452 reiser4_unset_hint(clust
->hint
);
453 result
= cut_disk_cluster(inode
, 0);
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
);
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
]);
479 uf_info
->container
= UF_CONTAINER_EXTENTS
;
480 complete_file_conversion(inode
);
485 warning("edward-1453", "Failed to convert file %llu: ret=%i",
486 (unsigned long long)get_inode_oid(inode
), 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
)
495 int check_compress
= 0;
496 int compressible
= 0;
498 if (!conversion_enabled(inode
))
500 result
= check_position(inode
, pos
, clust
, &check_compress
);
501 if (result
|| !check_compress
)
503 result
= read_check_compressibility(inode
, clust
, &compressible
);
507 /* At this point page cluster is grabbed and uptodate */
509 result
= cryptcompress2unixfile(file
, inode
, clust
);
514 result
= disable_conversion(inode
);
516 reiser4_txn_restart_current();
517 put_page_cluster(clust
, inode
, READ_OP
);
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
)
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
)) {
548 written_cr
= write_cryptcompress(file
, buf
, count
, off
, &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
));
592 c-indentation-style: "K&R"