Line data Source code
1 : // SPDX-License-Identifier: GPL-2.0-or-later
2 : /*
3 : * Copyright (C) 2018-2023 Oracle. All Rights Reserved.
4 : * Author: Darrick J. Wong <djwong@kernel.org>
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_da_format.h"
12 : #include "xfs_trans_resv.h"
13 : #include "xfs_trans_space.h"
14 : #include "xfs_mount.h"
15 : #include "xfs_trans.h"
16 : #include "xfs_inode.h"
17 : #include "xfs_da_btree.h"
18 : #include "xfs_bmap_btree.h"
19 : #include "xfs_bit.h"
20 : #include "xfs_sb.h"
21 : #include "xfs_quota.h"
22 : #include "xfs_imeta.h"
23 : #include "xfs_imeta_utils.h"
24 : #include "xfs_trace.h"
25 : #include "xfs_parent.h"
26 : #include "xfs_health.h"
27 :
28 : static inline int
29 86762 : xfs_imeta_init(
30 : struct xfs_mount *mp,
31 : const struct xfs_imeta_path *path,
32 : struct xfs_imeta_update *upd)
33 : {
34 86762 : int error;
35 :
36 86762 : memset(upd, 0, sizeof(struct xfs_imeta_update));
37 86762 : upd->mp = mp;
38 86762 : upd->path = path;
39 :
40 86762 : if (!xfs_has_metadir(mp))
41 : return 0;
42 :
43 : /*
44 : * Find the parent of the last path component. If the parent path does
45 : * not exist, we consider this corruption because paths are supposed
46 : * to exist. For example, if the path is /quota/user, we require that
47 : * /quota already exists.
48 : */
49 82658 : error = xfs_imeta_dir_parent(mp, upd->path, &upd->dp);
50 82658 : if (error == -ENOENT) {
51 0 : xfs_fs_mark_sick(mp, XFS_SICK_FS_METADIR);
52 0 : return -EFSCORRUPTED;
53 : }
54 82658 : if (error)
55 : return error;
56 :
57 82658 : return xfs_parent_start(mp, &upd->parent);
58 : }
59 :
60 : /*
61 : * Begin the process of creating a metadata file by allocating transactions
62 : * and taking whatever resources we're going to need.
63 : */
64 : int
65 86762 : xfs_imeta_start_create(
66 : struct xfs_mount *mp,
67 : const struct xfs_imeta_path *path,
68 : struct xfs_imeta_update *upd)
69 : {
70 86762 : int error;
71 :
72 86762 : error = xfs_imeta_init(mp, path, upd);
73 86762 : if (error)
74 : return error;
75 :
76 : /*
77 : * If we ever need the ability to create rt metadata files on a
78 : * pre-metadir filesystem, we'll need to dqattach the parent here.
79 : * Currently we assume that mkfs will create the files and quotacheck
80 : * will account for them.
81 : */
82 :
83 86762 : error = xfs_trans_alloc(mp, &M_RES(mp)->tr_imeta_create,
84 : xfs_create_space_res(mp, MAXNAMELEN), 0, 0, &upd->tp);
85 86762 : if (error)
86 : return error;
87 :
88 : /*
89 : * Lock the parent directory if there is one. We can't ijoin it to
90 : * the transaction until after the child file has been created.
91 : */
92 86755 : if (upd->dp) {
93 82658 : xfs_ilock(upd->dp, XFS_ILOCK_EXCL | XFS_ILOCK_PARENT);
94 82658 : upd->dp_locked = true;
95 : }
96 :
97 86755 : trace_xfs_imeta_start_create(upd);
98 86755 : return 0;
99 : }
100 :
101 : /*
102 : * Begin the process of linking a metadata file by allocating transactions
103 : * and locking whatever resources we're going to need.
104 : */
105 : static inline int
106 0 : xfs_imeta_start_dir_update(
107 : struct xfs_mount *mp,
108 : const struct xfs_imeta_path *path,
109 : struct xfs_inode *ip,
110 : struct xfs_trans_res *tr_resv,
111 : unsigned int resblks,
112 : struct xfs_imeta_update *upd)
113 : {
114 0 : int error;
115 :
116 0 : error = xfs_imeta_init(mp, path, upd);
117 0 : if (error)
118 : return error;
119 :
120 0 : upd->ip = ip;
121 :
122 0 : if (upd->dp) {
123 0 : int nospace_error = 0;
124 :
125 0 : error = xfs_trans_alloc_dir(upd->dp, tr_resv, upd->ip,
126 : &resblks, &upd->tp, &nospace_error);
127 0 : if (error)
128 0 : return error;
129 0 : if (!resblks) {
130 : /* We don't allow reservationless updates. */
131 0 : xfs_trans_cancel(upd->tp);
132 0 : upd->tp = NULL;
133 0 : xfs_iunlock(upd->dp, XFS_ILOCK_EXCL);
134 0 : xfs_iunlock(upd->ip, XFS_ILOCK_EXCL);
135 0 : return nospace_error;
136 : }
137 :
138 0 : upd->dp_locked = true;
139 : } else {
140 0 : error = xfs_trans_alloc_inode(upd->ip, tr_resv, resblks, 0,
141 : false, &upd->tp);
142 0 : if (error)
143 : return error;
144 : }
145 :
146 0 : upd->ip_locked = true;
147 0 : return 0;
148 : }
149 :
150 : /*
151 : * Begin the process of linking a metadata file by allocating transactions
152 : * and locking whatever resources we're going to need.
153 : */
154 : int
155 0 : xfs_imeta_start_link(
156 : struct xfs_mount *mp,
157 : const struct xfs_imeta_path *path,
158 : struct xfs_inode *ip,
159 : struct xfs_imeta_update *upd)
160 : {
161 0 : int error;
162 :
163 0 : error = xfs_imeta_start_dir_update(mp, path, ip,
164 : &M_RES(mp)->tr_imeta_link,
165 : xfs_link_space_res(mp, MAXNAMELEN), upd);
166 0 : if (error)
167 : return error;
168 :
169 0 : trace_xfs_imeta_start_link(upd);
170 0 : return 0;
171 : }
172 :
173 : /*
174 : * Begin the process of unlinking a metadata file by allocating transactions
175 : * and locking whatever resources we're going to need.
176 : */
177 : int
178 0 : xfs_imeta_start_unlink(
179 : struct xfs_mount *mp,
180 : const struct xfs_imeta_path *path,
181 : struct xfs_inode *ip,
182 : struct xfs_imeta_update *upd)
183 : {
184 0 : int error;
185 :
186 0 : error = xfs_imeta_start_dir_update(mp, path, ip,
187 : &M_RES(mp)->tr_imeta_unlink,
188 : xfs_remove_space_res(mp, MAXNAMELEN), upd);
189 0 : if (error)
190 : return error;
191 :
192 0 : trace_xfs_imeta_start_unlink(upd);
193 0 : return 0;
194 : }
195 :
196 : /*
197 : * Unlock and release resources after committing (or cancelling) a metadata
198 : * directory tree operation. The caller retains its reference to @upd->ip
199 : * and must release it explicitly.
200 : */
201 : static inline void
202 86766 : xfs_imeta_end_update(
203 : struct xfs_imeta_update *upd,
204 : int error)
205 : {
206 86766 : trace_xfs_imeta_end_update(upd, error);
207 :
208 86766 : if (upd->ip) {
209 57423 : if (upd->ip_locked)
210 57423 : xfs_iunlock(upd->ip, XFS_ILOCK_EXCL);
211 57423 : upd->ip_locked = false;
212 : }
213 :
214 86766 : if (upd->dp) {
215 82658 : if (upd->dp_locked)
216 82658 : xfs_iunlock(upd->dp, XFS_ILOCK_EXCL);
217 82658 : upd->dp_locked = false;
218 :
219 82658 : xfs_imeta_irele(upd->dp);
220 82658 : upd->dp = NULL;
221 : }
222 :
223 86766 : xfs_parent_finish(upd->mp, upd->parent);
224 86766 : }
225 :
226 : /* Commit a metadir update and unlock/drop all resources. */
227 : int
228 57434 : xfs_imeta_commit_update(
229 : struct xfs_imeta_update *upd)
230 : {
231 57434 : int error;
232 :
233 57434 : trace_xfs_imeta_update_commit(upd);
234 :
235 57434 : error = xfs_trans_commit(upd->tp);
236 57434 : upd->tp = NULL;
237 :
238 57434 : xfs_imeta_end_update(upd, error);
239 57434 : return error;
240 : }
241 :
242 : /* Cancel a metadir update and unlock/drop all resources. */
243 : void
244 29332 : xfs_imeta_cancel_update(
245 : struct xfs_imeta_update *upd,
246 : int error)
247 : {
248 29332 : trace_xfs_imeta_update_cancel(upd);
249 :
250 29332 : xfs_trans_cancel(upd->tp);
251 29332 : upd->tp = NULL;
252 :
253 29332 : xfs_imeta_end_update(upd, error);
254 29332 : }
255 :
256 : /* Create a metadata for the last component of the path. */
257 : STATIC int
258 41396 : xfs_imeta_mkdir(
259 : struct xfs_mount *mp,
260 : const struct xfs_imeta_path *path)
261 : {
262 41396 : struct xfs_imeta_update upd;
263 41396 : struct xfs_inode *ip = NULL;
264 41396 : int error;
265 :
266 82792 : if (xfs_is_shutdown(mp))
267 : return -EIO;
268 :
269 : /* Allocate a transaction to create the last directory. */
270 41329 : error = xfs_imeta_start_create(mp, path, &upd);
271 41329 : if (error)
272 : return error;
273 :
274 : /* Create the subdirectory and take our reference. */
275 41329 : error = xfs_imeta_create(&upd, S_IFDIR, &ip);
276 41329 : if (error)
277 29332 : goto out_cancel;
278 :
279 11997 : error = xfs_imeta_commit_update(&upd);
280 :
281 : /*
282 : * We don't pass the directory we just created to the caller, so finish
283 : * setting up the inode, then release the dir and the dquots.
284 : */
285 11997 : goto out_irele;
286 :
287 : out_cancel:
288 29332 : xfs_imeta_cancel_update(&upd, error);
289 41329 : out_irele:
290 : /* Have to finish setting up the inode to ensure it's deleted. */
291 41329 : if (ip) {
292 11997 : xfs_finish_inode_setup(ip);
293 11997 : xfs_irele(ip);
294 : }
295 : return error;
296 : }
297 :
298 : /*
299 : * Make sure that every metadata directory path component exists and is a
300 : * directory.
301 : */
302 : int
303 41396 : xfs_imeta_ensure_dirpath(
304 : struct xfs_mount *mp,
305 : const struct xfs_imeta_path *path)
306 : {
307 41396 : struct xfs_imeta_path temp_path = {
308 41396 : .im_path = path->im_path,
309 : .im_depth = 1,
310 : .im_ftype = XFS_DIR3_FT_DIR,
311 : };
312 41396 : unsigned int i;
313 41396 : int error = 0;
314 :
315 41396 : if (!xfs_has_metadir(mp))
316 : return 0;
317 :
318 82725 : for (i = 0; i < path->im_depth - 1; i++, temp_path.im_depth++) {
319 41396 : error = xfs_imeta_mkdir(mp, &temp_path);
320 41396 : if (error && error != -EEXIST)
321 67 : return error;
322 : }
323 :
324 : return 0;
325 : }
|