revert-mm-fix-blkdev-size-calculation-in-generic_write_checks
[linux-2.6/linux-trees-mm.git] / fs / reiser4 / flush.h
blob29229bc34e235ce41d20dcba4d78e14a50750fa2
1 /* Copyright 2002, 2003 by Hans Reiser, licensing governed by reiser4/README */
3 /* DECLARATIONS: */
5 #if !defined(__REISER4_FLUSH_H__)
6 #define __REISER4_FLUSH_H__
8 #include "plugin/cluster.h"
10 /* The flush_scan data structure maintains the state of an in-progress flush-scan on a
11 single level of the tree. A flush-scan is used for counting the number of adjacent
12 nodes to flush, which is used to determine whether we should relocate, and it is also
13 used to find a starting point for flush. A flush-scan object can scan in both right
14 and left directions via the scan_left() and scan_right() interfaces. The
15 right- and left-variations are similar but perform different functions. When scanning
16 left we (optionally perform rapid scanning and then) longterm-lock the endpoint node.
17 When scanning right we are simply counting the number of adjacent, dirty nodes. */
18 struct flush_scan {
20 /* The current number of nodes scanned on this level. */
21 unsigned count;
23 /* There may be a maximum number of nodes for a scan on any single level. When
24 going leftward, max_count is determined by FLUSH_SCAN_MAXNODES (see reiser4.h) */
25 unsigned max_count;
27 /* Direction: Set to one of the sideof enumeration: { LEFT_SIDE, RIGHT_SIDE }. */
28 sideof direction;
30 /* Initially @stop is set to false then set true once some condition stops the
31 search (e.g., we found a clean node before reaching max_count or we found a
32 node belonging to another atom). */
33 int stop;
35 /* The current scan position. If @node is non-NULL then its reference count has
36 been incremented to reflect this reference. */
37 jnode *node;
39 /* A handle for zload/zrelse of current scan position node. */
40 load_count node_load;
42 /* During left-scan, if the final position (a.k.a. endpoint node) is formatted the
43 node is locked using this lock handle. The endpoint needs to be locked for
44 transfer to the flush_position object after scanning finishes. */
45 lock_handle node_lock;
47 /* When the position is unformatted, its parent, coordinate, and parent
48 zload/zrelse handle. */
49 lock_handle parent_lock;
50 coord_t parent_coord;
51 load_count parent_load;
53 /* The block allocator preceder hint. Sometimes flush_scan determines what the
54 preceder is and if so it sets it here, after which it is copied into the
55 flush_position. Otherwise, the preceder is computed later. */
56 reiser4_block_nr preceder_blk;
59 struct convert_item_info {
60 dc_item_stat d_cur; /* disk cluster state of the current item */
61 dc_item_stat d_next; /* disk cluster state of the next slum item */
62 struct inode *inode;
63 flow_t flow;
66 struct convert_info {
67 int count; /* for squalloc terminating */
68 item_plugin *iplug; /* current item plugin */
69 struct convert_item_info *itm; /* current item info */
70 struct cluster_handle clust; /* transform cluster */
73 typedef enum flush_position_state {
74 POS_INVALID, /* Invalid or stopped pos, do not continue slum
75 * processing */
76 POS_ON_LEAF, /* pos points to already prepped, locked formatted node at
77 * leaf level */
78 POS_ON_EPOINT, /* pos keeps a lock on twig level, "coord" field is used
79 * to traverse unformatted nodes */
80 POS_TO_LEAF, /* pos is being moved to leaf level */
81 POS_TO_TWIG, /* pos is being moved to twig level */
82 POS_END_OF_TWIG, /* special case of POS_ON_TWIG, when coord is after
83 * rightmost unit of the current twig */
84 POS_ON_INTERNAL /* same as POS_ON_LEAF, but points to internal node */
85 } flushpos_state_t;
87 /* An encapsulation of the current flush point and all the parameters that are passed
88 through the entire squeeze-and-allocate stage of the flush routine. A single
89 flush_position object is constructed after left- and right-scanning finishes. */
90 struct flush_position {
91 flushpos_state_t state;
93 coord_t coord; /* coord to traverse unformatted nodes */
94 lock_handle lock; /* current lock we hold */
95 load_count load; /* load status for current locked formatted node */
97 jnode *child; /* for passing a reference to unformatted child
98 * across pos state changes */
100 reiser4_blocknr_hint preceder; /* The flush 'hint' state. */
101 int leaf_relocate; /* True if enough leaf-level nodes were
102 * found to suggest a relocate policy. */
103 int alloc_cnt; /* The number of nodes allocated during squeeze and allococate. */
104 int prep_or_free_cnt; /* The number of nodes prepared for write (allocate) or squeezed and freed. */
105 flush_queue_t *fq;
106 long *nr_written; /* number of nodes submitted to disk */
107 int flags; /* a copy of jnode_flush flags argument */
109 znode *prev_twig; /* previous parent pointer value, used to catch
110 * processing of new twig node */
111 struct convert_info *sq; /* convert info */
113 unsigned long pos_in_unit; /* for extents only. Position
114 within an extent unit of first
115 jnode of slum */
116 long nr_to_write; /* number of unformatted nodes to handle on flush */
119 static inline int item_convert_count(flush_pos_t * pos)
121 return pos->sq->count;
123 static inline void inc_item_convert_count(flush_pos_t * pos)
125 pos->sq->count++;
127 static inline void set_item_convert_count(flush_pos_t * pos, int count)
129 pos->sq->count = count;
131 static inline item_plugin *item_convert_plug(flush_pos_t * pos)
133 return pos->sq->iplug;
136 static inline struct convert_info *convert_data(flush_pos_t * pos)
138 return pos->sq;
141 static inline struct convert_item_info *item_convert_data(flush_pos_t * pos)
143 assert("edward-955", convert_data(pos));
144 return pos->sq->itm;
147 static inline struct tfm_cluster * tfm_cluster_sq(flush_pos_t * pos)
149 return &pos->sq->clust.tc;
152 static inline struct tfm_stream * tfm_stream_sq(flush_pos_t * pos,
153 tfm_stream_id id)
155 assert("edward-854", pos->sq != NULL);
156 return get_tfm_stream(tfm_cluster_sq(pos), id);
159 static inline int chaining_data_present(flush_pos_t * pos)
161 return convert_data(pos) && item_convert_data(pos);
164 /* Returns true if next node contains next item of the disk cluster
165 so item convert data should be moved to the right slum neighbor.
167 static inline int should_chain_next_node(flush_pos_t * pos)
169 int result = 0;
171 assert("edward-1007", chaining_data_present(pos));
173 switch (item_convert_data(pos)->d_next) {
174 case DC_CHAINED_ITEM:
175 result = 1;
176 break;
177 case DC_AFTER_CLUSTER:
178 break;
179 default:
180 impossible("edward-1009", "bad state of next slum item");
182 return result;
185 /* update item state in a disk cluster to assign conversion mode */
186 static inline void
187 move_chaining_data(flush_pos_t * pos, int this_node /* where is next item */ )
190 assert("edward-1010", chaining_data_present(pos));
192 if (this_node == 0) {
193 /* next item is on the right neighbor */
194 assert("edward-1011",
195 item_convert_data(pos)->d_cur == DC_FIRST_ITEM ||
196 item_convert_data(pos)->d_cur == DC_CHAINED_ITEM);
197 assert("edward-1012",
198 item_convert_data(pos)->d_next == DC_CHAINED_ITEM);
200 item_convert_data(pos)->d_cur = DC_CHAINED_ITEM;
201 item_convert_data(pos)->d_next = DC_INVALID_STATE;
202 } else {
203 /* next item is on the same node */
204 assert("edward-1013",
205 item_convert_data(pos)->d_cur == DC_FIRST_ITEM ||
206 item_convert_data(pos)->d_cur == DC_CHAINED_ITEM);
207 assert("edward-1227",
208 item_convert_data(pos)->d_next == DC_AFTER_CLUSTER ||
209 item_convert_data(pos)->d_next == DC_INVALID_STATE);
211 item_convert_data(pos)->d_cur = DC_AFTER_CLUSTER;
212 item_convert_data(pos)->d_next = DC_INVALID_STATE;
216 static inline int should_convert_node(flush_pos_t * pos, znode * node)
218 return znode_convertible(node);
221 /* true if there is attached convert item info */
222 static inline int should_convert_next_node(flush_pos_t * pos)
224 return convert_data(pos) && item_convert_data(pos);
227 #define SQUALLOC_THRESHOLD 256
229 static inline int should_terminate_squalloc(flush_pos_t * pos)
231 return convert_data(pos) &&
232 !item_convert_data(pos) &&
233 item_convert_count(pos) >= SQUALLOC_THRESHOLD;
236 #if 1
237 #define check_convert_info(pos) \
238 do { \
239 if (unlikely(should_convert_next_node(pos))){ \
240 warning("edward-1006", "unprocessed chained data"); \
241 printk("d_cur = %d, d_next = %d, flow.len = %llu\n", \
242 item_convert_data(pos)->d_cur, \
243 item_convert_data(pos)->d_next, \
244 item_convert_data(pos)->flow.length); \
245 printk("inode %llu, size = %llu, cluster %lu\n", \
246 (unsigned long long)get_inode_oid \
247 (item_convert_data(pos)->inode), \
248 i_size_read(item_convert_data(pos)->inode), \
249 convert_data(pos)->clust.index); \
251 } while (0)
252 #else
253 #define check_convert_info(pos)
254 #endif /* REISER4_DEBUG */
256 void free_convert_data(flush_pos_t * pos);
257 /* used in extent.c */
258 int scan_set_current(flush_scan * scan, jnode * node, unsigned add_size,
259 const coord_t * parent);
260 int reiser4_scan_finished(flush_scan * scan);
261 int reiser4_scanning_left(flush_scan * scan);
262 int reiser4_scan_goto(flush_scan * scan, jnode * tonode);
263 txn_atom *atom_locked_by_fq(flush_queue_t * fq);
264 int reiser4_alloc_extent(flush_pos_t *flush_pos);
265 squeeze_result squalloc_extent(znode *left, const coord_t *, flush_pos_t *,
266 reiser4_key *stop_key);
267 extern int reiser4_init_fqs(void);
268 extern void reiser4_done_fqs(void);
270 #if REISER4_DEBUG
272 extern void reiser4_check_fq(const txn_atom *atom);
273 extern atomic_t flush_cnt;
275 #define check_preceder(blk) \
276 assert("nikita-2588", blk < reiser4_block_count(reiser4_get_current_sb()));
277 extern void check_pos(flush_pos_t * pos);
278 #else
279 #define check_preceder(b) noop
280 #define check_pos(pos) noop
281 #endif
283 /* __REISER4_FLUSH_H__ */
284 #endif
286 /* Make Linus happy.
287 Local variables:
288 c-indentation-style: "K&R"
289 mode-name: "LC"
290 c-basic-offset: 8
291 tab-width: 8
292 fill-column: 90
293 LocalWords: preceder
294 End: