Merge tag 'drm-msm-fixes-2019-01-24' of git://people.freedesktop.org/~robclark/linux...
[linux-2.6-block.git] / fs / xfs / xfs_trans_bmap.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2016 Oracle.  All Rights Reserved.
4  * Author: Darrick J. Wong <darrick.wong@oracle.com>
5  */
6 #include "xfs.h"
7 #include "xfs_fs.h"
8 #include "xfs_shared.h"
9 #include "xfs_format.h"
10 #include "xfs_log_format.h"
11 #include "xfs_trans_resv.h"
12 #include "xfs_mount.h"
13 #include "xfs_defer.h"
14 #include "xfs_trans.h"
15 #include "xfs_trans_priv.h"
16 #include "xfs_bmap_item.h"
17 #include "xfs_alloc.h"
18 #include "xfs_bmap.h"
19 #include "xfs_inode.h"
20 #include "xfs_defer.h"
21
22 /*
23  * This routine is called to allocate a "bmap update done"
24  * log item.
25  */
26 struct xfs_bud_log_item *
27 xfs_trans_get_bud(
28         struct xfs_trans                *tp,
29         struct xfs_bui_log_item         *buip)
30 {
31         struct xfs_bud_log_item         *budp;
32
33         budp = xfs_bud_init(tp->t_mountp, buip);
34         xfs_trans_add_item(tp, &budp->bud_item);
35         return budp;
36 }
37
38 /*
39  * Finish an bmap update and log it to the BUD. Note that the
40  * transaction is marked dirty regardless of whether the bmap update
41  * succeeds or fails to support the BUI/BUD lifecycle rules.
42  */
43 int
44 xfs_trans_log_finish_bmap_update(
45         struct xfs_trans                *tp,
46         struct xfs_bud_log_item         *budp,
47         enum xfs_bmap_intent_type       type,
48         struct xfs_inode                *ip,
49         int                             whichfork,
50         xfs_fileoff_t                   startoff,
51         xfs_fsblock_t                   startblock,
52         xfs_filblks_t                   *blockcount,
53         xfs_exntst_t                    state)
54 {
55         int                             error;
56
57         error = xfs_bmap_finish_one(tp, ip, type, whichfork, startoff,
58                         startblock, blockcount, state);
59
60         /*
61          * Mark the transaction dirty, even on error. This ensures the
62          * transaction is aborted, which:
63          *
64          * 1.) releases the BUI and frees the BUD
65          * 2.) shuts down the filesystem
66          */
67         tp->t_flags |= XFS_TRANS_DIRTY;
68         set_bit(XFS_LI_DIRTY, &budp->bud_item.li_flags);
69
70         return error;
71 }
72
73 /* Sort bmap intents by inode. */
74 static int
75 xfs_bmap_update_diff_items(
76         void                            *priv,
77         struct list_head                *a,
78         struct list_head                *b)
79 {
80         struct xfs_bmap_intent          *ba;
81         struct xfs_bmap_intent          *bb;
82
83         ba = container_of(a, struct xfs_bmap_intent, bi_list);
84         bb = container_of(b, struct xfs_bmap_intent, bi_list);
85         return ba->bi_owner->i_ino - bb->bi_owner->i_ino;
86 }
87
88 /* Get an BUI. */
89 STATIC void *
90 xfs_bmap_update_create_intent(
91         struct xfs_trans                *tp,
92         unsigned int                    count)
93 {
94         struct xfs_bui_log_item         *buip;
95
96         ASSERT(count == XFS_BUI_MAX_FAST_EXTENTS);
97         ASSERT(tp != NULL);
98
99         buip = xfs_bui_init(tp->t_mountp);
100         ASSERT(buip != NULL);
101
102         /*
103          * Get a log_item_desc to point at the new item.
104          */
105         xfs_trans_add_item(tp, &buip->bui_item);
106         return buip;
107 }
108
109 /* Set the map extent flags for this mapping. */
110 static void
111 xfs_trans_set_bmap_flags(
112         struct xfs_map_extent           *bmap,
113         enum xfs_bmap_intent_type       type,
114         int                             whichfork,
115         xfs_exntst_t                    state)
116 {
117         bmap->me_flags = 0;
118         switch (type) {
119         case XFS_BMAP_MAP:
120         case XFS_BMAP_UNMAP:
121                 bmap->me_flags = type;
122                 break;
123         default:
124                 ASSERT(0);
125         }
126         if (state == XFS_EXT_UNWRITTEN)
127                 bmap->me_flags |= XFS_BMAP_EXTENT_UNWRITTEN;
128         if (whichfork == XFS_ATTR_FORK)
129                 bmap->me_flags |= XFS_BMAP_EXTENT_ATTR_FORK;
130 }
131
132 /* Log bmap updates in the intent item. */
133 STATIC void
134 xfs_bmap_update_log_item(
135         struct xfs_trans                *tp,
136         void                            *intent,
137         struct list_head                *item)
138 {
139         struct xfs_bui_log_item         *buip = intent;
140         struct xfs_bmap_intent          *bmap;
141         uint                            next_extent;
142         struct xfs_map_extent           *map;
143
144         bmap = container_of(item, struct xfs_bmap_intent, bi_list);
145
146         tp->t_flags |= XFS_TRANS_DIRTY;
147         set_bit(XFS_LI_DIRTY, &buip->bui_item.li_flags);
148
149         /*
150          * atomic_inc_return gives us the value after the increment;
151          * we want to use it as an array index so we need to subtract 1 from
152          * it.
153          */
154         next_extent = atomic_inc_return(&buip->bui_next_extent) - 1;
155         ASSERT(next_extent < buip->bui_format.bui_nextents);
156         map = &buip->bui_format.bui_extents[next_extent];
157         map->me_owner = bmap->bi_owner->i_ino;
158         map->me_startblock = bmap->bi_bmap.br_startblock;
159         map->me_startoff = bmap->bi_bmap.br_startoff;
160         map->me_len = bmap->bi_bmap.br_blockcount;
161         xfs_trans_set_bmap_flags(map, bmap->bi_type, bmap->bi_whichfork,
162                         bmap->bi_bmap.br_state);
163 }
164
165 /* Get an BUD so we can process all the deferred rmap updates. */
166 STATIC void *
167 xfs_bmap_update_create_done(
168         struct xfs_trans                *tp,
169         void                            *intent,
170         unsigned int                    count)
171 {
172         return xfs_trans_get_bud(tp, intent);
173 }
174
175 /* Process a deferred rmap update. */
176 STATIC int
177 xfs_bmap_update_finish_item(
178         struct xfs_trans                *tp,
179         struct list_head                *item,
180         void                            *done_item,
181         void                            **state)
182 {
183         struct xfs_bmap_intent          *bmap;
184         xfs_filblks_t                   count;
185         int                             error;
186
187         bmap = container_of(item, struct xfs_bmap_intent, bi_list);
188         count = bmap->bi_bmap.br_blockcount;
189         error = xfs_trans_log_finish_bmap_update(tp, done_item,
190                         bmap->bi_type,
191                         bmap->bi_owner, bmap->bi_whichfork,
192                         bmap->bi_bmap.br_startoff,
193                         bmap->bi_bmap.br_startblock,
194                         &count,
195                         bmap->bi_bmap.br_state);
196         if (!error && count > 0) {
197                 ASSERT(bmap->bi_type == XFS_BMAP_UNMAP);
198                 bmap->bi_bmap.br_blockcount = count;
199                 return -EAGAIN;
200         }
201         kmem_free(bmap);
202         return error;
203 }
204
205 /* Abort all pending BUIs. */
206 STATIC void
207 xfs_bmap_update_abort_intent(
208         void                            *intent)
209 {
210         xfs_bui_release(intent);
211 }
212
213 /* Cancel a deferred rmap update. */
214 STATIC void
215 xfs_bmap_update_cancel_item(
216         struct list_head                *item)
217 {
218         struct xfs_bmap_intent          *bmap;
219
220         bmap = container_of(item, struct xfs_bmap_intent, bi_list);
221         kmem_free(bmap);
222 }
223
224 const struct xfs_defer_op_type xfs_bmap_update_defer_type = {
225         .max_items      = XFS_BUI_MAX_FAST_EXTENTS,
226         .diff_items     = xfs_bmap_update_diff_items,
227         .create_intent  = xfs_bmap_update_create_intent,
228         .abort_intent   = xfs_bmap_update_abort_intent,
229         .log_item       = xfs_bmap_update_log_item,
230         .create_done    = xfs_bmap_update_create_done,
231         .finish_item    = xfs_bmap_update_finish_item,
232         .cancel_item    = xfs_bmap_update_cancel_item,
233 };