]>
Commit | Line | Data |
---|---|---|
77d61fe4 DW |
1 | /* |
2 | * Copyright (C) 2016 Oracle. All Rights Reserved. | |
3 | * | |
4 | * Author: Darrick J. Wong <[email protected]> | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU General Public License | |
8 | * as published by the Free Software Foundation; either version 2 | |
9 | * of the License, or (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it would be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write the Free Software Foundation, | |
18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. | |
19 | */ | |
20 | #include "xfs.h" | |
21 | #include "xfs_fs.h" | |
22 | #include "xfs_shared.h" | |
23 | #include "xfs_format.h" | |
24 | #include "xfs_log_format.h" | |
25 | #include "xfs_trans_resv.h" | |
26 | #include "xfs_mount.h" | |
27 | #include "xfs_defer.h" | |
28 | #include "xfs_trans.h" | |
29 | #include "xfs_trans_priv.h" | |
30 | #include "xfs_bmap_item.h" | |
31 | #include "xfs_alloc.h" | |
32 | #include "xfs_bmap.h" | |
33 | #include "xfs_inode.h" | |
34 | ||
35 | /* | |
36 | * This routine is called to allocate a "bmap update done" | |
37 | * log item. | |
38 | */ | |
39 | struct xfs_bud_log_item * | |
40 | xfs_trans_get_bud( | |
41 | struct xfs_trans *tp, | |
42 | struct xfs_bui_log_item *buip) | |
43 | { | |
44 | struct xfs_bud_log_item *budp; | |
45 | ||
46 | budp = xfs_bud_init(tp->t_mountp, buip); | |
47 | xfs_trans_add_item(tp, &budp->bud_item); | |
48 | return budp; | |
49 | } | |
50 | ||
51 | /* | |
52 | * Finish an bmap update and log it to the BUD. Note that the | |
53 | * transaction is marked dirty regardless of whether the bmap update | |
54 | * succeeds or fails to support the BUI/BUD lifecycle rules. | |
55 | */ | |
56 | int | |
57 | xfs_trans_log_finish_bmap_update( | |
58 | struct xfs_trans *tp, | |
59 | struct xfs_bud_log_item *budp, | |
60 | struct xfs_defer_ops *dop, | |
61 | enum xfs_bmap_intent_type type, | |
62 | struct xfs_inode *ip, | |
63 | int whichfork, | |
64 | xfs_fileoff_t startoff, | |
65 | xfs_fsblock_t startblock, | |
e1a4e37c | 66 | xfs_filblks_t *blockcount, |
77d61fe4 DW |
67 | xfs_exntst_t state) |
68 | { | |
69 | int error; | |
70 | ||
9f3afb57 DW |
71 | error = xfs_bmap_finish_one(tp, dop, ip, type, whichfork, startoff, |
72 | startblock, blockcount, state); | |
77d61fe4 DW |
73 | |
74 | /* | |
75 | * Mark the transaction dirty, even on error. This ensures the | |
76 | * transaction is aborted, which: | |
77 | * | |
78 | * 1.) releases the BUI and frees the BUD | |
79 | * 2.) shuts down the filesystem | |
80 | */ | |
81 | tp->t_flags |= XFS_TRANS_DIRTY; | |
82 | budp->bud_item.li_desc->lid_flags |= XFS_LID_DIRTY; | |
83 | ||
84 | return error; | |
85 | } | |
9f3afb57 DW |
86 | |
87 | /* Sort bmap intents by inode. */ | |
88 | static int | |
89 | xfs_bmap_update_diff_items( | |
90 | void *priv, | |
91 | struct list_head *a, | |
92 | struct list_head *b) | |
93 | { | |
94 | struct xfs_bmap_intent *ba; | |
95 | struct xfs_bmap_intent *bb; | |
96 | ||
97 | ba = container_of(a, struct xfs_bmap_intent, bi_list); | |
98 | bb = container_of(b, struct xfs_bmap_intent, bi_list); | |
99 | return ba->bi_owner->i_ino - bb->bi_owner->i_ino; | |
100 | } | |
101 | ||
102 | /* Get an BUI. */ | |
103 | STATIC void * | |
104 | xfs_bmap_update_create_intent( | |
105 | struct xfs_trans *tp, | |
106 | unsigned int count) | |
107 | { | |
108 | struct xfs_bui_log_item *buip; | |
109 | ||
110 | ASSERT(count == XFS_BUI_MAX_FAST_EXTENTS); | |
111 | ASSERT(tp != NULL); | |
112 | ||
113 | buip = xfs_bui_init(tp->t_mountp); | |
114 | ASSERT(buip != NULL); | |
115 | ||
116 | /* | |
117 | * Get a log_item_desc to point at the new item. | |
118 | */ | |
119 | xfs_trans_add_item(tp, &buip->bui_item); | |
120 | return buip; | |
121 | } | |
122 | ||
123 | /* Set the map extent flags for this mapping. */ | |
124 | static void | |
125 | xfs_trans_set_bmap_flags( | |
126 | struct xfs_map_extent *bmap, | |
127 | enum xfs_bmap_intent_type type, | |
128 | int whichfork, | |
129 | xfs_exntst_t state) | |
130 | { | |
131 | bmap->me_flags = 0; | |
132 | switch (type) { | |
133 | case XFS_BMAP_MAP: | |
134 | case XFS_BMAP_UNMAP: | |
135 | bmap->me_flags = type; | |
136 | break; | |
137 | default: | |
138 | ASSERT(0); | |
139 | } | |
140 | if (state == XFS_EXT_UNWRITTEN) | |
141 | bmap->me_flags |= XFS_BMAP_EXTENT_UNWRITTEN; | |
142 | if (whichfork == XFS_ATTR_FORK) | |
143 | bmap->me_flags |= XFS_BMAP_EXTENT_ATTR_FORK; | |
144 | } | |
145 | ||
146 | /* Log bmap updates in the intent item. */ | |
147 | STATIC void | |
148 | xfs_bmap_update_log_item( | |
149 | struct xfs_trans *tp, | |
150 | void *intent, | |
151 | struct list_head *item) | |
152 | { | |
153 | struct xfs_bui_log_item *buip = intent; | |
154 | struct xfs_bmap_intent *bmap; | |
155 | uint next_extent; | |
156 | struct xfs_map_extent *map; | |
157 | ||
158 | bmap = container_of(item, struct xfs_bmap_intent, bi_list); | |
159 | ||
160 | tp->t_flags |= XFS_TRANS_DIRTY; | |
161 | buip->bui_item.li_desc->lid_flags |= XFS_LID_DIRTY; | |
162 | ||
163 | /* | |
164 | * atomic_inc_return gives us the value after the increment; | |
165 | * we want to use it as an array index so we need to subtract 1 from | |
166 | * it. | |
167 | */ | |
168 | next_extent = atomic_inc_return(&buip->bui_next_extent) - 1; | |
169 | ASSERT(next_extent < buip->bui_format.bui_nextents); | |
170 | map = &buip->bui_format.bui_extents[next_extent]; | |
171 | map->me_owner = bmap->bi_owner->i_ino; | |
172 | map->me_startblock = bmap->bi_bmap.br_startblock; | |
173 | map->me_startoff = bmap->bi_bmap.br_startoff; | |
174 | map->me_len = bmap->bi_bmap.br_blockcount; | |
175 | xfs_trans_set_bmap_flags(map, bmap->bi_type, bmap->bi_whichfork, | |
176 | bmap->bi_bmap.br_state); | |
177 | } | |
178 | ||
179 | /* Get an BUD so we can process all the deferred rmap updates. */ | |
180 | STATIC void * | |
181 | xfs_bmap_update_create_done( | |
182 | struct xfs_trans *tp, | |
183 | void *intent, | |
184 | unsigned int count) | |
185 | { | |
186 | return xfs_trans_get_bud(tp, intent); | |
187 | } | |
188 | ||
189 | /* Process a deferred rmap update. */ | |
190 | STATIC int | |
191 | xfs_bmap_update_finish_item( | |
192 | struct xfs_trans *tp, | |
193 | struct xfs_defer_ops *dop, | |
194 | struct list_head *item, | |
195 | void *done_item, | |
196 | void **state) | |
197 | { | |
198 | struct xfs_bmap_intent *bmap; | |
e1a4e37c | 199 | xfs_filblks_t count; |
9f3afb57 DW |
200 | int error; |
201 | ||
202 | bmap = container_of(item, struct xfs_bmap_intent, bi_list); | |
e1a4e37c | 203 | count = bmap->bi_bmap.br_blockcount; |
9f3afb57 DW |
204 | error = xfs_trans_log_finish_bmap_update(tp, done_item, dop, |
205 | bmap->bi_type, | |
206 | bmap->bi_owner, bmap->bi_whichfork, | |
207 | bmap->bi_bmap.br_startoff, | |
208 | bmap->bi_bmap.br_startblock, | |
e1a4e37c | 209 | &count, |
9f3afb57 | 210 | bmap->bi_bmap.br_state); |
e1a4e37c DW |
211 | if (!error && count > 0) { |
212 | ASSERT(bmap->bi_type == XFS_BMAP_UNMAP); | |
213 | bmap->bi_bmap.br_blockcount = count; | |
214 | return -EAGAIN; | |
215 | } | |
9f3afb57 DW |
216 | kmem_free(bmap); |
217 | return error; | |
218 | } | |
219 | ||
220 | /* Abort all pending BUIs. */ | |
221 | STATIC void | |
222 | xfs_bmap_update_abort_intent( | |
223 | void *intent) | |
224 | { | |
225 | xfs_bui_release(intent); | |
226 | } | |
227 | ||
228 | /* Cancel a deferred rmap update. */ | |
229 | STATIC void | |
230 | xfs_bmap_update_cancel_item( | |
231 | struct list_head *item) | |
232 | { | |
233 | struct xfs_bmap_intent *bmap; | |
234 | ||
235 | bmap = container_of(item, struct xfs_bmap_intent, bi_list); | |
236 | kmem_free(bmap); | |
237 | } | |
238 | ||
239 | static const struct xfs_defer_op_type xfs_bmap_update_defer_type = { | |
240 | .type = XFS_DEFER_OPS_TYPE_BMAP, | |
241 | .max_items = XFS_BUI_MAX_FAST_EXTENTS, | |
242 | .diff_items = xfs_bmap_update_diff_items, | |
243 | .create_intent = xfs_bmap_update_create_intent, | |
244 | .abort_intent = xfs_bmap_update_abort_intent, | |
245 | .log_item = xfs_bmap_update_log_item, | |
246 | .create_done = xfs_bmap_update_create_done, | |
247 | .finish_item = xfs_bmap_update_finish_item, | |
248 | .cancel_item = xfs_bmap_update_cancel_item, | |
249 | }; | |
250 | ||
251 | /* Register the deferred op type. */ | |
252 | void | |
253 | xfs_bmap_update_init_defer_op(void) | |
254 | { | |
255 | xfs_defer_init_op_type(&xfs_bmap_update_defer_type); | |
256 | } |