Commit | Line | Data |
---|---|---|
0b61f8a4 | 1 | // SPDX-License-Identifier: GPL-2.0 |
1da177e4 | 2 | /* |
7b718769 NS |
3 | * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc. |
4 | * All Rights Reserved. | |
1da177e4 | 5 | */ |
1da177e4 | 6 | #include "xfs.h" |
a844f451 | 7 | #include "xfs_fs.h" |
5467b34b | 8 | #include "xfs_shared.h" |
a4fbe6ab | 9 | #include "xfs_format.h" |
239880ef DC |
10 | #include "xfs_log_format.h" |
11 | #include "xfs_trans_resv.h" | |
1da177e4 | 12 | #include "xfs_mount.h" |
1da177e4 | 13 | #include "xfs_inode.h" |
239880ef | 14 | #include "xfs_trans.h" |
a844f451 | 15 | #include "xfs_inode_item.h" |
0b1b213f | 16 | #include "xfs_trace.h" |
239880ef | 17 | #include "xfs_trans_priv.h" |
d3a304b6 | 18 | #include "xfs_buf_item.h" |
1234351c | 19 | #include "xfs_log.h" |
a5155b87 | 20 | #include "xfs_error.h" |
1da177e4 | 21 | |
f0e28280 | 22 | #include <linux/iversion.h> |
1da177e4 | 23 | |
e7720afa | 24 | struct kmem_cache *xfs_ili_zone; /* inode log item zone */ |
1da177e4 | 25 | |
7bfa31d8 CH |
26 | static inline struct xfs_inode_log_item *INODE_ITEM(struct xfs_log_item *lip) |
27 | { | |
28 | return container_of(lip, struct xfs_inode_log_item, ili_item); | |
29 | } | |
30 | ||
19f4e7cc DC |
31 | /* |
32 | * The logged size of an inode fork is always the current size of the inode | |
33 | * fork. This means that when an inode fork is relogged, the size of the logged | |
34 | * region is determined by the current state, not the combination of the | |
35 | * previously logged state + the current state. This is different relogging | |
36 | * behaviour to most other log items which will retain the size of the | |
37 | * previously logged changes when smaller regions are relogged. | |
38 | * | |
39 | * Hence operations that remove data from the inode fork (e.g. shortform | |
40 | * dir/attr remove, extent form extent removal, etc), the size of the relogged | |
41 | * inode gets -smaller- rather than stays the same size as the previously logged | |
42 | * size and this can result in the committing transaction reducing the amount of | |
43 | * space being consumed by the CIL. | |
44 | */ | |
166d1368 | 45 | STATIC void |
ce9641d6 CH |
46 | xfs_inode_item_data_fork_size( |
47 | struct xfs_inode_log_item *iip, | |
166d1368 DC |
48 | int *nvecs, |
49 | int *nbytes) | |
1da177e4 | 50 | { |
7bfa31d8 | 51 | struct xfs_inode *ip = iip->ili_inode; |
166d1368 | 52 | |
f7e67b20 | 53 | switch (ip->i_df.if_format) { |
1da177e4 | 54 | case XFS_DINODE_FMT_EXTENTS: |
f5d8d5c4 | 55 | if ((iip->ili_fields & XFS_ILOG_DEXT) && |
daf83964 | 56 | ip->i_df.if_nextents > 0 && |
166d1368 DC |
57 | ip->i_df.if_bytes > 0) { |
58 | /* worst case, doesn't subtract delalloc extents */ | |
59 | *nbytes += XFS_IFORK_DSIZE(ip); | |
60 | *nvecs += 1; | |
61 | } | |
1da177e4 | 62 | break; |
1da177e4 | 63 | case XFS_DINODE_FMT_BTREE: |
f5d8d5c4 | 64 | if ((iip->ili_fields & XFS_ILOG_DBROOT) && |
166d1368 DC |
65 | ip->i_df.if_broot_bytes > 0) { |
66 | *nbytes += ip->i_df.if_broot_bytes; | |
67 | *nvecs += 1; | |
68 | } | |
1da177e4 | 69 | break; |
1da177e4 | 70 | case XFS_DINODE_FMT_LOCAL: |
f5d8d5c4 | 71 | if ((iip->ili_fields & XFS_ILOG_DDATA) && |
166d1368 DC |
72 | ip->i_df.if_bytes > 0) { |
73 | *nbytes += roundup(ip->i_df.if_bytes, 4); | |
74 | *nvecs += 1; | |
75 | } | |
1da177e4 LT |
76 | break; |
77 | ||
78 | case XFS_DINODE_FMT_DEV: | |
1da177e4 | 79 | break; |
1da177e4 LT |
80 | default: |
81 | ASSERT(0); | |
82 | break; | |
83 | } | |
ce9641d6 | 84 | } |
1da177e4 | 85 | |
ce9641d6 CH |
86 | STATIC void |
87 | xfs_inode_item_attr_fork_size( | |
88 | struct xfs_inode_log_item *iip, | |
89 | int *nvecs, | |
90 | int *nbytes) | |
91 | { | |
92 | struct xfs_inode *ip = iip->ili_inode; | |
1da177e4 | 93 | |
f7e67b20 | 94 | switch (ip->i_afp->if_format) { |
1da177e4 | 95 | case XFS_DINODE_FMT_EXTENTS: |
f5d8d5c4 | 96 | if ((iip->ili_fields & XFS_ILOG_AEXT) && |
daf83964 | 97 | ip->i_afp->if_nextents > 0 && |
166d1368 DC |
98 | ip->i_afp->if_bytes > 0) { |
99 | /* worst case, doesn't subtract unused space */ | |
100 | *nbytes += XFS_IFORK_ASIZE(ip); | |
101 | *nvecs += 1; | |
102 | } | |
1da177e4 | 103 | break; |
1da177e4 | 104 | case XFS_DINODE_FMT_BTREE: |
f5d8d5c4 | 105 | if ((iip->ili_fields & XFS_ILOG_ABROOT) && |
166d1368 DC |
106 | ip->i_afp->if_broot_bytes > 0) { |
107 | *nbytes += ip->i_afp->if_broot_bytes; | |
108 | *nvecs += 1; | |
109 | } | |
1da177e4 | 110 | break; |
1da177e4 | 111 | case XFS_DINODE_FMT_LOCAL: |
f5d8d5c4 | 112 | if ((iip->ili_fields & XFS_ILOG_ADATA) && |
166d1368 DC |
113 | ip->i_afp->if_bytes > 0) { |
114 | *nbytes += roundup(ip->i_afp->if_bytes, 4); | |
115 | *nvecs += 1; | |
116 | } | |
1da177e4 | 117 | break; |
1da177e4 LT |
118 | default: |
119 | ASSERT(0); | |
120 | break; | |
121 | } | |
1da177e4 LT |
122 | } |
123 | ||
ce9641d6 CH |
124 | /* |
125 | * This returns the number of iovecs needed to log the given inode item. | |
126 | * | |
127 | * We need one iovec for the inode log format structure, one for the | |
128 | * inode core, and possibly one for the inode data/extents/b-tree root | |
129 | * and one for the inode attribute data/extents/b-tree root. | |
130 | */ | |
131 | STATIC void | |
132 | xfs_inode_item_size( | |
133 | struct xfs_log_item *lip, | |
134 | int *nvecs, | |
135 | int *nbytes) | |
136 | { | |
137 | struct xfs_inode_log_item *iip = INODE_ITEM(lip); | |
138 | struct xfs_inode *ip = iip->ili_inode; | |
139 | ||
140 | *nvecs += 2; | |
141 | *nbytes += sizeof(struct xfs_inode_log_format) + | |
e9e2eae8 | 142 | xfs_log_dinode_size(ip->i_mount); |
ce9641d6 CH |
143 | |
144 | xfs_inode_item_data_fork_size(iip, nvecs, nbytes); | |
145 | if (XFS_IFORK_Q(ip)) | |
146 | xfs_inode_item_attr_fork_size(iip, nvecs, nbytes); | |
147 | } | |
148 | ||
1234351c | 149 | STATIC void |
3de559fb CH |
150 | xfs_inode_item_format_data_fork( |
151 | struct xfs_inode_log_item *iip, | |
bde7cff6 CH |
152 | struct xfs_inode_log_format *ilf, |
153 | struct xfs_log_vec *lv, | |
154 | struct xfs_log_iovec **vecp) | |
1da177e4 | 155 | { |
7bfa31d8 | 156 | struct xfs_inode *ip = iip->ili_inode; |
1da177e4 | 157 | size_t data_bytes; |
1da177e4 | 158 | |
f7e67b20 | 159 | switch (ip->i_df.if_format) { |
1da177e4 | 160 | case XFS_DINODE_FMT_EXTENTS: |
f5d8d5c4 | 161 | iip->ili_fields &= |
42b67dc6 | 162 | ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT | XFS_ILOG_DEV); |
339a5f5d | 163 | |
f5d8d5c4 | 164 | if ((iip->ili_fields & XFS_ILOG_DEXT) && |
daf83964 | 165 | ip->i_df.if_nextents > 0 && |
339a5f5d | 166 | ip->i_df.if_bytes > 0) { |
da776503 CH |
167 | struct xfs_bmbt_rec *p; |
168 | ||
5d829300 | 169 | ASSERT(xfs_iext_count(&ip->i_df) > 0); |
da776503 CH |
170 | |
171 | p = xlog_prepare_iovec(lv, vecp, XLOG_REG_TYPE_IEXT); | |
172 | data_bytes = xfs_iextents_copy(ip, p, XFS_DATA_FORK); | |
173 | xlog_finish_iovec(lv, *vecp, data_bytes); | |
174 | ||
175 | ASSERT(data_bytes <= ip->i_df.if_bytes); | |
176 | ||
177 | ilf->ilf_dsize = data_bytes; | |
bde7cff6 | 178 | ilf->ilf_size++; |
339a5f5d | 179 | } else { |
f5d8d5c4 | 180 | iip->ili_fields &= ~XFS_ILOG_DEXT; |
1da177e4 LT |
181 | } |
182 | break; | |
1da177e4 | 183 | case XFS_DINODE_FMT_BTREE: |
f5d8d5c4 | 184 | iip->ili_fields &= |
42b67dc6 | 185 | ~(XFS_ILOG_DDATA | XFS_ILOG_DEXT | XFS_ILOG_DEV); |
339a5f5d | 186 | |
f5d8d5c4 | 187 | if ((iip->ili_fields & XFS_ILOG_DBROOT) && |
339a5f5d | 188 | ip->i_df.if_broot_bytes > 0) { |
1da177e4 | 189 | ASSERT(ip->i_df.if_broot != NULL); |
bde7cff6 | 190 | xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IBROOT, |
1234351c CH |
191 | ip->i_df.if_broot, |
192 | ip->i_df.if_broot_bytes); | |
bde7cff6 CH |
193 | ilf->ilf_dsize = ip->i_df.if_broot_bytes; |
194 | ilf->ilf_size++; | |
339a5f5d | 195 | } else { |
f5d8d5c4 | 196 | ASSERT(!(iip->ili_fields & |
339a5f5d | 197 | XFS_ILOG_DBROOT)); |
f5d8d5c4 | 198 | iip->ili_fields &= ~XFS_ILOG_DBROOT; |
1da177e4 LT |
199 | } |
200 | break; | |
1da177e4 | 201 | case XFS_DINODE_FMT_LOCAL: |
f5d8d5c4 | 202 | iip->ili_fields &= |
42b67dc6 | 203 | ~(XFS_ILOG_DEXT | XFS_ILOG_DBROOT | XFS_ILOG_DEV); |
f5d8d5c4 | 204 | if ((iip->ili_fields & XFS_ILOG_DDATA) && |
339a5f5d | 205 | ip->i_df.if_bytes > 0) { |
1da177e4 LT |
206 | /* |
207 | * Round i_bytes up to a word boundary. | |
b63da6c8 | 208 | * The underlying memory is guaranteed |
1da177e4 LT |
209 | * to be there by xfs_idata_realloc(). |
210 | */ | |
211 | data_bytes = roundup(ip->i_df.if_bytes, 4); | |
1234351c | 212 | ASSERT(ip->i_df.if_u1.if_data != NULL); |
13d2c10b | 213 | ASSERT(ip->i_disk_size > 0); |
bde7cff6 | 214 | xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_ILOCAL, |
1234351c | 215 | ip->i_df.if_u1.if_data, data_bytes); |
bde7cff6 CH |
216 | ilf->ilf_dsize = (unsigned)data_bytes; |
217 | ilf->ilf_size++; | |
339a5f5d | 218 | } else { |
f5d8d5c4 | 219 | iip->ili_fields &= ~XFS_ILOG_DDATA; |
1da177e4 LT |
220 | } |
221 | break; | |
1da177e4 | 222 | case XFS_DINODE_FMT_DEV: |
f5d8d5c4 | 223 | iip->ili_fields &= |
42b67dc6 | 224 | ~(XFS_ILOG_DDATA | XFS_ILOG_DBROOT | XFS_ILOG_DEXT); |
bde7cff6 | 225 | if (iip->ili_fields & XFS_ILOG_DEV) |
66f36464 | 226 | ilf->ilf_u.ilfu_rdev = sysv_encode_dev(VFS_I(ip)->i_rdev); |
1da177e4 | 227 | break; |
1da177e4 LT |
228 | default: |
229 | ASSERT(0); | |
230 | break; | |
231 | } | |
3de559fb CH |
232 | } |
233 | ||
1234351c | 234 | STATIC void |
3de559fb CH |
235 | xfs_inode_item_format_attr_fork( |
236 | struct xfs_inode_log_item *iip, | |
bde7cff6 CH |
237 | struct xfs_inode_log_format *ilf, |
238 | struct xfs_log_vec *lv, | |
239 | struct xfs_log_iovec **vecp) | |
3de559fb CH |
240 | { |
241 | struct xfs_inode *ip = iip->ili_inode; | |
242 | size_t data_bytes; | |
1da177e4 | 243 | |
f7e67b20 | 244 | switch (ip->i_afp->if_format) { |
1da177e4 | 245 | case XFS_DINODE_FMT_EXTENTS: |
f5d8d5c4 | 246 | iip->ili_fields &= |
339a5f5d CH |
247 | ~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT); |
248 | ||
f5d8d5c4 | 249 | if ((iip->ili_fields & XFS_ILOG_AEXT) && |
daf83964 | 250 | ip->i_afp->if_nextents > 0 && |
339a5f5d | 251 | ip->i_afp->if_bytes > 0) { |
da776503 CH |
252 | struct xfs_bmbt_rec *p; |
253 | ||
5d829300 | 254 | ASSERT(xfs_iext_count(ip->i_afp) == |
daf83964 | 255 | ip->i_afp->if_nextents); |
da776503 CH |
256 | |
257 | p = xlog_prepare_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_EXT); | |
258 | data_bytes = xfs_iextents_copy(ip, p, XFS_ATTR_FORK); | |
259 | xlog_finish_iovec(lv, *vecp, data_bytes); | |
260 | ||
261 | ilf->ilf_asize = data_bytes; | |
bde7cff6 | 262 | ilf->ilf_size++; |
339a5f5d | 263 | } else { |
f5d8d5c4 | 264 | iip->ili_fields &= ~XFS_ILOG_AEXT; |
1da177e4 LT |
265 | } |
266 | break; | |
1da177e4 | 267 | case XFS_DINODE_FMT_BTREE: |
f5d8d5c4 | 268 | iip->ili_fields &= |
339a5f5d CH |
269 | ~(XFS_ILOG_ADATA | XFS_ILOG_AEXT); |
270 | ||
f5d8d5c4 | 271 | if ((iip->ili_fields & XFS_ILOG_ABROOT) && |
339a5f5d | 272 | ip->i_afp->if_broot_bytes > 0) { |
1da177e4 | 273 | ASSERT(ip->i_afp->if_broot != NULL); |
339a5f5d | 274 | |
bde7cff6 | 275 | xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_BROOT, |
1234351c CH |
276 | ip->i_afp->if_broot, |
277 | ip->i_afp->if_broot_bytes); | |
bde7cff6 CH |
278 | ilf->ilf_asize = ip->i_afp->if_broot_bytes; |
279 | ilf->ilf_size++; | |
339a5f5d | 280 | } else { |
f5d8d5c4 | 281 | iip->ili_fields &= ~XFS_ILOG_ABROOT; |
1da177e4 LT |
282 | } |
283 | break; | |
1da177e4 | 284 | case XFS_DINODE_FMT_LOCAL: |
f5d8d5c4 | 285 | iip->ili_fields &= |
339a5f5d CH |
286 | ~(XFS_ILOG_AEXT | XFS_ILOG_ABROOT); |
287 | ||
f5d8d5c4 | 288 | if ((iip->ili_fields & XFS_ILOG_ADATA) && |
339a5f5d | 289 | ip->i_afp->if_bytes > 0) { |
1da177e4 LT |
290 | /* |
291 | * Round i_bytes up to a word boundary. | |
b63da6c8 | 292 | * The underlying memory is guaranteed |
1da177e4 LT |
293 | * to be there by xfs_idata_realloc(). |
294 | */ | |
295 | data_bytes = roundup(ip->i_afp->if_bytes, 4); | |
1234351c | 296 | ASSERT(ip->i_afp->if_u1.if_data != NULL); |
bde7cff6 | 297 | xlog_copy_iovec(lv, vecp, XLOG_REG_TYPE_IATTR_LOCAL, |
1234351c CH |
298 | ip->i_afp->if_u1.if_data, |
299 | data_bytes); | |
bde7cff6 CH |
300 | ilf->ilf_asize = (unsigned)data_bytes; |
301 | ilf->ilf_size++; | |
339a5f5d | 302 | } else { |
f5d8d5c4 | 303 | iip->ili_fields &= ~XFS_ILOG_ADATA; |
1da177e4 LT |
304 | } |
305 | break; | |
1da177e4 LT |
306 | default: |
307 | ASSERT(0); | |
308 | break; | |
309 | } | |
3de559fb CH |
310 | } |
311 | ||
30e05599 DW |
312 | /* |
313 | * Convert an incore timestamp to a log timestamp. Note that the log format | |
314 | * specifies host endian format! | |
315 | */ | |
6fc277c7 | 316 | static inline xfs_log_timestamp_t |
30e05599 | 317 | xfs_inode_to_log_dinode_ts( |
f93e5436 | 318 | struct xfs_inode *ip, |
30e05599 DW |
319 | const struct timespec64 tv) |
320 | { | |
732de7db | 321 | struct xfs_log_legacy_timestamp *lits; |
6fc277c7 | 322 | xfs_log_timestamp_t its; |
30e05599 | 323 | |
f93e5436 DW |
324 | if (xfs_inode_has_bigtime(ip)) |
325 | return xfs_inode_encode_bigtime(tv); | |
326 | ||
732de7db | 327 | lits = (struct xfs_log_legacy_timestamp *)&its; |
30e05599 DW |
328 | lits->t_sec = tv.tv_sec; |
329 | lits->t_nsec = tv.tv_nsec; | |
330 | ||
331 | return its; | |
332 | } | |
333 | ||
9b3beb02 CH |
334 | /* |
335 | * The legacy DMAPI fields are only present in the on-disk and in-log inodes, | |
336 | * but not in the in-memory one. But we are guaranteed to have an inode buffer | |
337 | * in memory when logging an inode, so we can just copy it from the on-disk | |
338 | * inode to the in-log inode here so that recovery of file system with these | |
339 | * fields set to non-zero values doesn't lose them. For all other cases we zero | |
340 | * the fields. | |
341 | */ | |
342 | static void | |
343 | xfs_copy_dm_fields_to_log_dinode( | |
344 | struct xfs_inode *ip, | |
345 | struct xfs_log_dinode *to) | |
346 | { | |
347 | struct xfs_dinode *dip; | |
348 | ||
349 | dip = xfs_buf_offset(ip->i_itemp->ili_item.li_buf, | |
350 | ip->i_imap.im_boffset); | |
351 | ||
352 | if (xfs_iflags_test(ip, XFS_IPRESERVE_DM_FIELDS)) { | |
353 | to->di_dmevmask = be32_to_cpu(dip->di_dmevmask); | |
354 | to->di_dmstate = be16_to_cpu(dip->di_dmstate); | |
355 | } else { | |
356 | to->di_dmevmask = 0; | |
357 | to->di_dmstate = 0; | |
358 | } | |
359 | } | |
360 | ||
f8d55aa0 | 361 | static void |
3987848c DC |
362 | xfs_inode_to_log_dinode( |
363 | struct xfs_inode *ip, | |
93f958f9 DC |
364 | struct xfs_log_dinode *to, |
365 | xfs_lsn_t lsn) | |
f8d55aa0 | 366 | { |
3987848c DC |
367 | struct inode *inode = VFS_I(ip); |
368 | ||
93f958f9 | 369 | to->di_magic = XFS_DINODE_MAGIC; |
f7e67b20 | 370 | to->di_format = xfs_ifork_format(&ip->i_df); |
ba8adad5 CH |
371 | to->di_uid = i_uid_read(inode); |
372 | to->di_gid = i_gid_read(inode); | |
ceaf603c CH |
373 | to->di_projid_lo = ip->i_projid & 0xffff; |
374 | to->di_projid_hi = ip->i_projid >> 16; | |
f8d55aa0 | 375 | |
93f958f9 | 376 | memset(to->di_pad, 0, sizeof(to->di_pad)); |
faeb4e47 | 377 | memset(to->di_pad3, 0, sizeof(to->di_pad3)); |
f93e5436 DW |
378 | to->di_atime = xfs_inode_to_log_dinode_ts(ip, inode->i_atime); |
379 | to->di_mtime = xfs_inode_to_log_dinode_ts(ip, inode->i_mtime); | |
380 | to->di_ctime = xfs_inode_to_log_dinode_ts(ip, inode->i_ctime); | |
54d7b5c1 | 381 | to->di_nlink = inode->i_nlink; |
9e9a2674 | 382 | to->di_gen = inode->i_generation; |
c19b3b05 | 383 | to->di_mode = inode->i_mode; |
f8d55aa0 | 384 | |
13d2c10b | 385 | to->di_size = ip->i_disk_size; |
6e73a545 | 386 | to->di_nblocks = ip->i_nblocks; |
031474c2 | 387 | to->di_extsize = ip->i_extsize; |
daf83964 CH |
388 | to->di_nextents = xfs_ifork_nextents(&ip->i_df); |
389 | to->di_anextents = xfs_ifork_nextents(ip->i_afp); | |
7821ea30 | 390 | to->di_forkoff = ip->i_forkoff; |
f7e67b20 | 391 | to->di_aformat = xfs_ifork_format(ip->i_afp); |
db07349d | 392 | to->di_flags = ip->i_diflags; |
f8d55aa0 | 393 | |
9b3beb02 CH |
394 | xfs_copy_dm_fields_to_log_dinode(ip, to); |
395 | ||
20413e37 DC |
396 | /* log a dummy value to ensure log structure is fully initialised */ |
397 | to->di_next_unlinked = NULLAGINO; | |
398 | ||
38c26bfd | 399 | if (xfs_has_v3inodes(ip->i_mount)) { |
6471e9c5 | 400 | to->di_version = 3; |
f0e28280 | 401 | to->di_changecount = inode_peek_iversion(inode); |
e98d5e88 | 402 | to->di_crtime = xfs_inode_to_log_dinode_ts(ip, ip->i_crtime); |
3e09ab8f | 403 | to->di_flags2 = ip->i_diflags2; |
b33ce57d | 404 | to->di_cowextsize = ip->i_cowextsize; |
93f958f9 DC |
405 | to->di_ino = ip->i_ino; |
406 | to->di_lsn = lsn; | |
407 | memset(to->di_pad2, 0, sizeof(to->di_pad2)); | |
408 | uuid_copy(&to->di_uuid, &ip->i_mount->m_sb.sb_meta_uuid); | |
f8d55aa0 DC |
409 | to->di_flushiter = 0; |
410 | } else { | |
6471e9c5 | 411 | to->di_version = 2; |
965e0a1a | 412 | to->di_flushiter = ip->i_flushiter; |
f8d55aa0 DC |
413 | } |
414 | } | |
415 | ||
416 | /* | |
417 | * Format the inode core. Current timestamp data is only in the VFS inode | |
418 | * fields, so we need to grab them from there. Hence rather than just copying | |
419 | * the XFS inode core structure, format the fields directly into the iovec. | |
420 | */ | |
421 | static void | |
422 | xfs_inode_item_format_core( | |
423 | struct xfs_inode *ip, | |
424 | struct xfs_log_vec *lv, | |
425 | struct xfs_log_iovec **vecp) | |
426 | { | |
427 | struct xfs_log_dinode *dic; | |
428 | ||
429 | dic = xlog_prepare_iovec(lv, vecp, XLOG_REG_TYPE_ICORE); | |
93f958f9 | 430 | xfs_inode_to_log_dinode(ip, dic, ip->i_itemp->ili_item.li_lsn); |
e9e2eae8 | 431 | xlog_finish_iovec(lv, *vecp, xfs_log_dinode_size(ip->i_mount)); |
f8d55aa0 DC |
432 | } |
433 | ||
3de559fb CH |
434 | /* |
435 | * This is called to fill in the vector of log iovecs for the given inode | |
436 | * log item. It fills the first item with an inode log format structure, | |
437 | * the second with the on-disk inode structure, and a possible third and/or | |
438 | * fourth with the inode data/extents/b-tree root and inode attributes | |
439 | * data/extents/b-tree root. | |
20413e37 DC |
440 | * |
441 | * Note: Always use the 64 bit inode log format structure so we don't | |
442 | * leave an uninitialised hole in the format item on 64 bit systems. Log | |
443 | * recovery on 32 bit systems handles this just fine, so there's no reason | |
444 | * for not using an initialising the properly padded structure all the time. | |
3de559fb CH |
445 | */ |
446 | STATIC void | |
447 | xfs_inode_item_format( | |
448 | struct xfs_log_item *lip, | |
bde7cff6 | 449 | struct xfs_log_vec *lv) |
3de559fb CH |
450 | { |
451 | struct xfs_inode_log_item *iip = INODE_ITEM(lip); | |
452 | struct xfs_inode *ip = iip->ili_inode; | |
bde7cff6 | 453 | struct xfs_log_iovec *vecp = NULL; |
20413e37 | 454 | struct xfs_inode_log_format *ilf; |
3de559fb | 455 | |
2f251293 CH |
456 | ilf = xlog_prepare_iovec(lv, &vecp, XLOG_REG_TYPE_IFORMAT); |
457 | ilf->ilf_type = XFS_LI_INODE; | |
458 | ilf->ilf_ino = ip->i_ino; | |
459 | ilf->ilf_blkno = ip->i_imap.im_blkno; | |
460 | ilf->ilf_len = ip->i_imap.im_len; | |
461 | ilf->ilf_boffset = ip->i_imap.im_boffset; | |
462 | ilf->ilf_fields = XFS_ILOG_CORE; | |
463 | ilf->ilf_size = 2; /* format + core */ | |
20413e37 DC |
464 | |
465 | /* | |
466 | * make sure we don't leak uninitialised data into the log in the case | |
467 | * when we don't log every field in the inode. | |
468 | */ | |
469 | ilf->ilf_dsize = 0; | |
470 | ilf->ilf_asize = 0; | |
471 | ilf->ilf_pad = 0; | |
42b67dc6 | 472 | memset(&ilf->ilf_u, 0, sizeof(ilf->ilf_u)); |
20413e37 DC |
473 | |
474 | xlog_finish_iovec(lv, vecp, sizeof(*ilf)); | |
3de559fb | 475 | |
f8d55aa0 | 476 | xfs_inode_item_format_core(ip, lv, &vecp); |
bde7cff6 | 477 | xfs_inode_item_format_data_fork(iip, ilf, lv, &vecp); |
3de559fb | 478 | if (XFS_IFORK_Q(ip)) { |
bde7cff6 | 479 | xfs_inode_item_format_attr_fork(iip, ilf, lv, &vecp); |
3de559fb CH |
480 | } else { |
481 | iip->ili_fields &= | |
482 | ~(XFS_ILOG_ADATA | XFS_ILOG_ABROOT | XFS_ILOG_AEXT); | |
483 | } | |
484 | ||
2f251293 CH |
485 | /* update the format with the exact fields we actually logged */ |
486 | ilf->ilf_fields |= (iip->ili_fields & ~XFS_ILOG_TIMESTAMP); | |
1da177e4 LT |
487 | } |
488 | ||
1da177e4 LT |
489 | /* |
490 | * This is called to pin the inode associated with the inode log | |
a14a5ab5 | 491 | * item in memory so it cannot be written out. |
1da177e4 LT |
492 | */ |
493 | STATIC void | |
494 | xfs_inode_item_pin( | |
7bfa31d8 | 495 | struct xfs_log_item *lip) |
1da177e4 | 496 | { |
7bfa31d8 | 497 | struct xfs_inode *ip = INODE_ITEM(lip)->ili_inode; |
a14a5ab5 | 498 | |
7bfa31d8 | 499 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); |
298f7bec | 500 | ASSERT(lip->li_buf); |
7bfa31d8 CH |
501 | |
502 | trace_xfs_inode_pin(ip, _RET_IP_); | |
503 | atomic_inc(&ip->i_pincount); | |
1da177e4 LT |
504 | } |
505 | ||
506 | ||
507 | /* | |
508 | * This is called to unpin the inode associated with the inode log | |
509 | * item which was previously pinned with a call to xfs_inode_item_pin(). | |
a14a5ab5 CH |
510 | * |
511 | * Also wake up anyone in xfs_iunpin_wait() if the count goes to 0. | |
298f7bec DC |
512 | * |
513 | * Note that unpin can race with inode cluster buffer freeing marking the buffer | |
514 | * stale. In that case, flush completions are run from the buffer unpin call, | |
515 | * which may happen before the inode is unpinned. If we lose the race, there | |
516 | * will be no buffer attached to the log item, but the inode will be marked | |
517 | * XFS_ISTALE. | |
1da177e4 | 518 | */ |
1da177e4 LT |
519 | STATIC void |
520 | xfs_inode_item_unpin( | |
7bfa31d8 | 521 | struct xfs_log_item *lip, |
9412e318 | 522 | int remove) |
1da177e4 | 523 | { |
7bfa31d8 | 524 | struct xfs_inode *ip = INODE_ITEM(lip)->ili_inode; |
a14a5ab5 | 525 | |
4aaf15d1 | 526 | trace_xfs_inode_unpin(ip, _RET_IP_); |
298f7bec | 527 | ASSERT(lip->li_buf || xfs_iflags_test(ip, XFS_ISTALE)); |
a14a5ab5 CH |
528 | ASSERT(atomic_read(&ip->i_pincount) > 0); |
529 | if (atomic_dec_and_test(&ip->i_pincount)) | |
f392e631 | 530 | wake_up_bit(&ip->i_flags, __XFS_IPINNED_BIT); |
1da177e4 LT |
531 | } |
532 | ||
1da177e4 | 533 | STATIC uint |
43ff2122 CH |
534 | xfs_inode_item_push( |
535 | struct xfs_log_item *lip, | |
536 | struct list_head *buffer_list) | |
57e80956 MW |
537 | __releases(&lip->li_ailp->ail_lock) |
538 | __acquires(&lip->li_ailp->ail_lock) | |
1da177e4 | 539 | { |
7bfa31d8 CH |
540 | struct xfs_inode_log_item *iip = INODE_ITEM(lip); |
541 | struct xfs_inode *ip = iip->ili_inode; | |
d3a304b6 | 542 | struct xfs_buf *bp = lip->li_buf; |
43ff2122 CH |
543 | uint rval = XFS_ITEM_SUCCESS; |
544 | int error; | |
1da177e4 | 545 | |
90c60e16 DC |
546 | ASSERT(iip->ili_item.li_buf); |
547 | ||
548 | if (xfs_ipincount(ip) > 0 || xfs_buf_ispinned(bp) || | |
549 | (ip->i_flags & XFS_ISTALE)) | |
1da177e4 | 550 | return XFS_ITEM_PINNED; |
1da177e4 | 551 | |
718ecc50 | 552 | if (xfs_iflags_test(ip, XFS_IFLUSHING)) |
90c60e16 | 553 | return XFS_ITEM_FLUSHING; |
1da177e4 | 554 | |
90c60e16 DC |
555 | if (!xfs_buf_trylock(bp)) |
556 | return XFS_ITEM_LOCKED; | |
4c46819a | 557 | |
90c60e16 | 558 | spin_unlock(&lip->li_ailp->ail_lock); |
9a3a5dab | 559 | |
43ff2122 | 560 | /* |
90c60e16 DC |
561 | * We need to hold a reference for flushing the cluster buffer as it may |
562 | * fail the buffer without IO submission. In which case, we better get a | |
563 | * reference for that completion because otherwise we don't get a | |
564 | * reference for IO until we queue the buffer for delwri submission. | |
43ff2122 | 565 | */ |
90c60e16 | 566 | xfs_buf_hold(bp); |
5717ea4d | 567 | error = xfs_iflush_cluster(bp); |
43ff2122 CH |
568 | if (!error) { |
569 | if (!xfs_buf_delwri_queue(bp, buffer_list)) | |
570 | rval = XFS_ITEM_FLUSHING; | |
571 | xfs_buf_relse(bp); | |
90c60e16 | 572 | } else { |
5717ea4d DC |
573 | /* |
574 | * Release the buffer if we were unable to flush anything. On | |
575 | * any other error, the buffer has already been released. | |
576 | */ | |
577 | if (error == -EAGAIN) | |
578 | xfs_buf_relse(bp); | |
d4bc4c5f | 579 | rval = XFS_ITEM_LOCKED; |
90c60e16 | 580 | } |
43ff2122 | 581 | |
57e80956 | 582 | spin_lock(&lip->li_ailp->ail_lock); |
43ff2122 | 583 | return rval; |
1da177e4 LT |
584 | } |
585 | ||
586 | /* | |
587 | * Unlock the inode associated with the inode log item. | |
1da177e4 LT |
588 | */ |
589 | STATIC void | |
ddf92053 | 590 | xfs_inode_item_release( |
7bfa31d8 | 591 | struct xfs_log_item *lip) |
1da177e4 | 592 | { |
7bfa31d8 CH |
593 | struct xfs_inode_log_item *iip = INODE_ITEM(lip); |
594 | struct xfs_inode *ip = iip->ili_inode; | |
898621d5 | 595 | unsigned short lock_flags; |
1da177e4 | 596 | |
f3ca8738 CH |
597 | ASSERT(ip->i_itemp != NULL); |
598 | ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL)); | |
1da177e4 | 599 | |
898621d5 CH |
600 | lock_flags = iip->ili_lock_flags; |
601 | iip->ili_lock_flags = 0; | |
ddc3415a | 602 | if (lock_flags) |
f3ca8738 | 603 | xfs_iunlock(ip, lock_flags); |
1da177e4 LT |
604 | } |
605 | ||
606 | /* | |
de25c181 DC |
607 | * This is called to find out where the oldest active copy of the inode log |
608 | * item in the on disk log resides now that the last log write of it completed | |
609 | * at the given lsn. Since we always re-log all dirty data in an inode, the | |
610 | * latest copy in the on disk log is the only one that matters. Therefore, | |
611 | * simply return the given lsn. | |
612 | * | |
613 | * If the inode has been marked stale because the cluster is being freed, we | |
614 | * don't want to (re-)insert this inode into the AIL. There is a race condition | |
615 | * where the cluster buffer may be unpinned before the inode is inserted into | |
616 | * the AIL during transaction committed processing. If the buffer is unpinned | |
617 | * before the inode item has been committed and inserted, then it is possible | |
1316d4da | 618 | * for the buffer to be written and IO completes before the inode is inserted |
de25c181 DC |
619 | * into the AIL. In that case, we'd be inserting a clean, stale inode into the |
620 | * AIL which will never get removed. It will, however, get reclaimed which | |
621 | * triggers an assert in xfs_inode_free() complaining about freein an inode | |
622 | * still in the AIL. | |
623 | * | |
1316d4da DC |
624 | * To avoid this, just unpin the inode directly and return a LSN of -1 so the |
625 | * transaction committed code knows that it does not need to do any further | |
626 | * processing on the item. | |
1da177e4 | 627 | */ |
1da177e4 LT |
628 | STATIC xfs_lsn_t |
629 | xfs_inode_item_committed( | |
7bfa31d8 | 630 | struct xfs_log_item *lip, |
1da177e4 LT |
631 | xfs_lsn_t lsn) |
632 | { | |
de25c181 DC |
633 | struct xfs_inode_log_item *iip = INODE_ITEM(lip); |
634 | struct xfs_inode *ip = iip->ili_inode; | |
635 | ||
1316d4da DC |
636 | if (xfs_iflags_test(ip, XFS_ISTALE)) { |
637 | xfs_inode_item_unpin(lip, 0); | |
638 | return -1; | |
639 | } | |
7bfa31d8 | 640 | return lsn; |
1da177e4 LT |
641 | } |
642 | ||
1da177e4 LT |
643 | STATIC void |
644 | xfs_inode_item_committing( | |
7bfa31d8 | 645 | struct xfs_log_item *lip, |
5f9b4b0d | 646 | xfs_csn_t seq) |
1da177e4 | 647 | { |
5f9b4b0d | 648 | INODE_ITEM(lip)->ili_commit_seq = seq; |
ddf92053 | 649 | return xfs_inode_item_release(lip); |
1da177e4 LT |
650 | } |
651 | ||
272e42b2 | 652 | static const struct xfs_item_ops xfs_inode_item_ops = { |
7bfa31d8 CH |
653 | .iop_size = xfs_inode_item_size, |
654 | .iop_format = xfs_inode_item_format, | |
655 | .iop_pin = xfs_inode_item_pin, | |
656 | .iop_unpin = xfs_inode_item_unpin, | |
ddf92053 | 657 | .iop_release = xfs_inode_item_release, |
7bfa31d8 CH |
658 | .iop_committed = xfs_inode_item_committed, |
659 | .iop_push = xfs_inode_item_push, | |
ddf92053 | 660 | .iop_committing = xfs_inode_item_committing, |
1da177e4 LT |
661 | }; |
662 | ||
663 | ||
664 | /* | |
665 | * Initialize the inode log item for a newly allocated (in-core) inode. | |
666 | */ | |
667 | void | |
668 | xfs_inode_item_init( | |
7bfa31d8 CH |
669 | struct xfs_inode *ip, |
670 | struct xfs_mount *mp) | |
1da177e4 | 671 | { |
7bfa31d8 | 672 | struct xfs_inode_log_item *iip; |
1da177e4 LT |
673 | |
674 | ASSERT(ip->i_itemp == NULL); | |
32a2b11f CM |
675 | iip = ip->i_itemp = kmem_cache_zalloc(xfs_ili_zone, |
676 | GFP_KERNEL | __GFP_NOFAIL); | |
1da177e4 | 677 | |
1da177e4 | 678 | iip->ili_inode = ip; |
1319ebef | 679 | spin_lock_init(&iip->ili_lock); |
43f5efc5 DC |
680 | xfs_log_item_init(mp, &iip->ili_item, XFS_LI_INODE, |
681 | &xfs_inode_item_ops); | |
1da177e4 LT |
682 | } |
683 | ||
684 | /* | |
685 | * Free the inode log item and any memory hanging off of it. | |
686 | */ | |
687 | void | |
688 | xfs_inode_item_destroy( | |
298f7bec | 689 | struct xfs_inode *ip) |
1da177e4 | 690 | { |
298f7bec DC |
691 | struct xfs_inode_log_item *iip = ip->i_itemp; |
692 | ||
693 | ASSERT(iip->ili_item.li_buf == NULL); | |
694 | ||
695 | ip->i_itemp = NULL; | |
696 | kmem_free(iip->ili_item.li_lv_shadow); | |
697 | kmem_cache_free(xfs_ili_zone, iip); | |
1da177e4 LT |
698 | } |
699 | ||
700 | ||
701 | /* | |
a69a1dc2 DC |
702 | * We only want to pull the item from the AIL if it is actually there |
703 | * and its location in the log has not changed since we started the | |
704 | * flush. Thus, we only bother if the inode's lsn has not changed. | |
1da177e4 | 705 | */ |
a69a1dc2 DC |
706 | static void |
707 | xfs_iflush_ail_updates( | |
708 | struct xfs_ail *ailp, | |
709 | struct list_head *list) | |
1da177e4 | 710 | { |
a69a1dc2 DC |
711 | struct xfs_log_item *lip; |
712 | xfs_lsn_t tail_lsn = 0; | |
30136832 | 713 | |
a69a1dc2 DC |
714 | /* this is an opencoded batch version of xfs_trans_ail_delete */ |
715 | spin_lock(&ailp->ail_lock); | |
716 | list_for_each_entry(lip, list, li_bio_list) { | |
717 | xfs_lsn_t lsn; | |
30136832 | 718 | |
a69a1dc2 DC |
719 | clear_bit(XFS_LI_FAILED, &lip->li_flags); |
720 | if (INODE_ITEM(lip)->ili_flush_lsn != lip->li_lsn) | |
48d55e2a DC |
721 | continue; |
722 | ||
a69a1dc2 DC |
723 | lsn = xfs_ail_delete_one(ailp, lip); |
724 | if (!tail_lsn && lsn) | |
725 | tail_lsn = lsn; | |
30136832 | 726 | } |
a69a1dc2 DC |
727 | xfs_ail_update_finish(ailp, tail_lsn); |
728 | } | |
1da177e4 | 729 | |
a69a1dc2 DC |
730 | /* |
731 | * Walk the list of inodes that have completed their IOs. If they are clean | |
732 | * remove them from the list and dissociate them from the buffer. Buffers that | |
733 | * are still dirty remain linked to the buffer and on the list. Caller must | |
734 | * handle them appropriately. | |
735 | */ | |
736 | static void | |
737 | xfs_iflush_finish( | |
738 | struct xfs_buf *bp, | |
739 | struct list_head *list) | |
740 | { | |
741 | struct xfs_log_item *lip, *n; | |
1da177e4 | 742 | |
a69a1dc2 DC |
743 | list_for_each_entry_safe(lip, n, list, li_bio_list) { |
744 | struct xfs_inode_log_item *iip = INODE_ITEM(lip); | |
298f7bec DC |
745 | bool drop_buffer = false; |
746 | ||
1319ebef | 747 | spin_lock(&iip->ili_lock); |
298f7bec DC |
748 | |
749 | /* | |
750 | * Remove the reference to the cluster buffer if the inode is | |
a69a1dc2 DC |
751 | * clean in memory and drop the buffer reference once we've |
752 | * dropped the locks we hold. | |
298f7bec DC |
753 | */ |
754 | ASSERT(iip->ili_item.li_buf == bp); | |
755 | if (!iip->ili_fields) { | |
756 | iip->ili_item.li_buf = NULL; | |
a69a1dc2 | 757 | list_del_init(&lip->li_bio_list); |
298f7bec DC |
758 | drop_buffer = true; |
759 | } | |
30136832 | 760 | iip->ili_last_fields = 0; |
298f7bec | 761 | iip->ili_flush_lsn = 0; |
1319ebef | 762 | spin_unlock(&iip->ili_lock); |
718ecc50 | 763 | xfs_iflags_clear(iip->ili_inode, XFS_IFLUSHING); |
298f7bec DC |
764 | if (drop_buffer) |
765 | xfs_buf_rele(bp); | |
30136832 | 766 | } |
1da177e4 LT |
767 | } |
768 | ||
a69a1dc2 DC |
769 | /* |
770 | * Inode buffer IO completion routine. It is responsible for removing inodes | |
718ecc50 DC |
771 | * attached to the buffer from the AIL if they have not been re-logged and |
772 | * completing the inode flush. | |
a69a1dc2 DC |
773 | */ |
774 | void | |
664ffb8a | 775 | xfs_buf_inode_iodone( |
a69a1dc2 DC |
776 | struct xfs_buf *bp) |
777 | { | |
778 | struct xfs_log_item *lip, *n; | |
779 | LIST_HEAD(flushed_inodes); | |
780 | LIST_HEAD(ail_updates); | |
781 | ||
782 | /* | |
783 | * Pull the attached inodes from the buffer one at a time and take the | |
784 | * appropriate action on them. | |
785 | */ | |
786 | list_for_each_entry_safe(lip, n, &bp->b_li_list, li_bio_list) { | |
787 | struct xfs_inode_log_item *iip = INODE_ITEM(lip); | |
788 | ||
789 | if (xfs_iflags_test(iip->ili_inode, XFS_ISTALE)) { | |
790 | xfs_iflush_abort(iip->ili_inode); | |
791 | continue; | |
792 | } | |
793 | if (!iip->ili_last_fields) | |
794 | continue; | |
795 | ||
796 | /* Do an unlocked check for needing the AIL lock. */ | |
797 | if (iip->ili_flush_lsn == lip->li_lsn || | |
798 | test_bit(XFS_LI_FAILED, &lip->li_flags)) | |
799 | list_move_tail(&lip->li_bio_list, &ail_updates); | |
800 | else | |
801 | list_move_tail(&lip->li_bio_list, &flushed_inodes); | |
802 | } | |
803 | ||
804 | if (!list_empty(&ail_updates)) { | |
805 | xfs_iflush_ail_updates(bp->b_mount->m_ail, &ail_updates); | |
806 | list_splice_tail(&ail_updates, &flushed_inodes); | |
807 | } | |
808 | ||
809 | xfs_iflush_finish(bp, &flushed_inodes); | |
810 | if (!list_empty(&flushed_inodes)) | |
811 | list_splice_tail(&flushed_inodes, &bp->b_li_list); | |
812 | } | |
813 | ||
664ffb8a CH |
814 | void |
815 | xfs_buf_inode_io_fail( | |
816 | struct xfs_buf *bp) | |
817 | { | |
818 | struct xfs_log_item *lip; | |
819 | ||
820 | list_for_each_entry(lip, &bp->b_li_list, li_bio_list) | |
821 | set_bit(XFS_LI_FAILED, &lip->li_flags); | |
822 | } | |
823 | ||
1da177e4 | 824 | /* |
718ecc50 | 825 | * This is the inode flushing abort routine. It is called when |
04913fdd DC |
826 | * the filesystem is shutting down to clean up the inode state. It is |
827 | * responsible for removing the inode item from the AIL if it has not been | |
718ecc50 | 828 | * re-logged and clearing the inode's flush state. |
1da177e4 LT |
829 | */ |
830 | void | |
831 | xfs_iflush_abort( | |
298f7bec | 832 | struct xfs_inode *ip) |
1da177e4 | 833 | { |
298f7bec DC |
834 | struct xfs_inode_log_item *iip = ip->i_itemp; |
835 | struct xfs_buf *bp = NULL; | |
1da177e4 | 836 | |
1da177e4 | 837 | if (iip) { |
298f7bec DC |
838 | /* |
839 | * Clear the failed bit before removing the item from the AIL so | |
840 | * xfs_trans_ail_delete() doesn't try to clear and release the | |
841 | * buffer attached to the log item before we are done with it. | |
842 | */ | |
843 | clear_bit(XFS_LI_FAILED, &iip->ili_item.li_flags); | |
2b3cf093 | 844 | xfs_trans_ail_delete(&iip->ili_item, 0); |
298f7bec | 845 | |
1da177e4 LT |
846 | /* |
847 | * Clear the inode logging fields so no more flushes are | |
848 | * attempted. | |
849 | */ | |
1319ebef | 850 | spin_lock(&iip->ili_lock); |
1dfde687 | 851 | iip->ili_last_fields = 0; |
f5d8d5c4 | 852 | iip->ili_fields = 0; |
fc0561ce | 853 | iip->ili_fsync_fields = 0; |
298f7bec DC |
854 | iip->ili_flush_lsn = 0; |
855 | bp = iip->ili_item.li_buf; | |
856 | iip->ili_item.li_buf = NULL; | |
48d55e2a | 857 | list_del_init(&iip->ili_item.li_bio_list); |
1319ebef | 858 | spin_unlock(&iip->ili_lock); |
1da177e4 | 859 | } |
718ecc50 | 860 | xfs_iflags_clear(ip, XFS_IFLUSHING); |
298f7bec DC |
861 | if (bp) |
862 | xfs_buf_rele(bp); | |
1da177e4 LT |
863 | } |
864 | ||
6d192a9b | 865 | /* |
20413e37 DC |
866 | * convert an xfs_inode_log_format struct from the old 32 bit version |
867 | * (which can have different field alignments) to the native 64 bit version | |
6d192a9b TS |
868 | */ |
869 | int | |
870 | xfs_inode_item_format_convert( | |
20413e37 DC |
871 | struct xfs_log_iovec *buf, |
872 | struct xfs_inode_log_format *in_f) | |
6d192a9b | 873 | { |
20413e37 DC |
874 | struct xfs_inode_log_format_32 *in_f32 = buf->i_addr; |
875 | ||
a5155b87 DW |
876 | if (buf->i_len != sizeof(*in_f32)) { |
877 | XFS_ERROR_REPORT(__func__, XFS_ERRLEVEL_LOW, NULL); | |
20413e37 | 878 | return -EFSCORRUPTED; |
a5155b87 | 879 | } |
20413e37 DC |
880 | |
881 | in_f->ilf_type = in_f32->ilf_type; | |
882 | in_f->ilf_size = in_f32->ilf_size; | |
883 | in_f->ilf_fields = in_f32->ilf_fields; | |
884 | in_f->ilf_asize = in_f32->ilf_asize; | |
885 | in_f->ilf_dsize = in_f32->ilf_dsize; | |
886 | in_f->ilf_ino = in_f32->ilf_ino; | |
42b67dc6 | 887 | memcpy(&in_f->ilf_u, &in_f32->ilf_u, sizeof(in_f->ilf_u)); |
20413e37 DC |
888 | in_f->ilf_blkno = in_f32->ilf_blkno; |
889 | in_f->ilf_len = in_f32->ilf_len; | |
890 | in_f->ilf_boffset = in_f32->ilf_boffset; | |
891 | return 0; | |
6d192a9b | 892 | } |