diff options
author | Allison Henderson <allison.henderson@oracle.com> | 2018-10-18 02:21:16 -0400 |
---|---|---|
committer | Dave Chinner <david@fromorbit.com> | 2018-10-18 02:21:16 -0400 |
commit | 2f3cd8091963810d85e6a5dd6ed1247e10e9e6f2 (patch) | |
tree | eef93c41ff1cf4ccac705ab04b93e39a07019c43 /fs/xfs/libxfs | |
parent | 4c74a56b9de76bb6b581274b76b52535ad77c2a7 (diff) |
xfs: Add attibute set and helper functions
This patch adds xfs_attr_set_args and xfs_bmap_set_attrforkoff.
These sub-routines set the attributes specified in @args.
We will use this later for setting parent pointers as a deferred
attribute operation.
[dgc: remove attr fork init code from xfs_attr_set_args().]
[dgc: xfs_attr_try_sf_addname() NULLs args.trans after commit.]
[dgc: correct sf add error handling.]
Signed-off-by: Allison Henderson <allison.henderson@oracle.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
Diffstat (limited to 'fs/xfs/libxfs')
-rw-r--r-- | fs/xfs/libxfs/xfs_attr.c | 151 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_attr.h | 1 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_bmap.c | 49 | ||||
-rw-r--r-- | fs/xfs/libxfs/xfs_bmap.h | 1 |
4 files changed, 115 insertions, 87 deletions
diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c index c15a1debec90..25431ddba1fa 100644 --- a/fs/xfs/libxfs/xfs_attr.c +++ b/fs/xfs/libxfs/xfs_attr.c | |||
@@ -215,9 +215,80 @@ xfs_attr_try_sf_addname( | |||
215 | xfs_trans_set_sync(args->trans); | 215 | xfs_trans_set_sync(args->trans); |
216 | 216 | ||
217 | error2 = xfs_trans_commit(args->trans); | 217 | error2 = xfs_trans_commit(args->trans); |
218 | args->trans = NULL; | ||
218 | return error ? error : error2; | 219 | return error ? error : error2; |
219 | } | 220 | } |
220 | 221 | ||
222 | /* | ||
223 | * Set the attribute specified in @args. | ||
224 | */ | ||
225 | int | ||
226 | xfs_attr_set_args( | ||
227 | struct xfs_da_args *args, | ||
228 | struct xfs_buf **leaf_bp) | ||
229 | { | ||
230 | struct xfs_inode *dp = args->dp; | ||
231 | int error; | ||
232 | |||
233 | /* | ||
234 | * If the attribute list is non-existent or a shortform list, | ||
235 | * upgrade it to a single-leaf-block attribute list. | ||
236 | */ | ||
237 | if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL || | ||
238 | (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
239 | dp->i_d.di_anextents == 0)) { | ||
240 | |||
241 | /* | ||
242 | * Build initial attribute list (if required). | ||
243 | */ | ||
244 | if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) | ||
245 | xfs_attr_shortform_create(args); | ||
246 | |||
247 | /* | ||
248 | * Try to add the attr to the attribute list in the inode. | ||
249 | */ | ||
250 | error = xfs_attr_try_sf_addname(dp, args); | ||
251 | if (error != -ENOSPC) | ||
252 | return error; | ||
253 | |||
254 | /* | ||
255 | * It won't fit in the shortform, transform to a leaf block. | ||
256 | * GROT: another possible req'mt for a double-split btree op. | ||
257 | */ | ||
258 | error = xfs_attr_shortform_to_leaf(args, leaf_bp); | ||
259 | if (error) | ||
260 | return error; | ||
261 | |||
262 | /* | ||
263 | * Prevent the leaf buffer from being unlocked so that a | ||
264 | * concurrent AIL push cannot grab the half-baked leaf | ||
265 | * buffer and run into problems with the write verifier. | ||
266 | */ | ||
267 | xfs_trans_bhold(args->trans, *leaf_bp); | ||
268 | |||
269 | error = xfs_defer_finish(&args->trans); | ||
270 | if (error) | ||
271 | return error; | ||
272 | |||
273 | /* | ||
274 | * Commit the leaf transformation. We'll need another | ||
275 | * (linked) transaction to add the new attribute to the | ||
276 | * leaf. | ||
277 | */ | ||
278 | error = xfs_trans_roll_inode(&args->trans, dp); | ||
279 | if (error) | ||
280 | return error; | ||
281 | xfs_trans_bjoin(args->trans, *leaf_bp); | ||
282 | *leaf_bp = NULL; | ||
283 | } | ||
284 | |||
285 | if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) | ||
286 | error = xfs_attr_leaf_addname(args); | ||
287 | else | ||
288 | error = xfs_attr_node_addname(args); | ||
289 | return error; | ||
290 | } | ||
291 | |||
221 | int | 292 | int |
222 | xfs_attr_set( | 293 | xfs_attr_set( |
223 | struct xfs_inode *dp, | 294 | struct xfs_inode *dp, |
@@ -282,73 +353,17 @@ xfs_attr_set( | |||
282 | error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0, | 353 | error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0, |
283 | rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : | 354 | rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES : |
284 | XFS_QMOPT_RES_REGBLKS); | 355 | XFS_QMOPT_RES_REGBLKS); |
285 | if (error) { | 356 | if (error) |
286 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 357 | goto out_trans_cancel; |
287 | xfs_trans_cancel(args.trans); | ||
288 | return error; | ||
289 | } | ||
290 | 358 | ||
291 | xfs_trans_ijoin(args.trans, dp, 0); | 359 | xfs_trans_ijoin(args.trans, dp, 0); |
292 | 360 | error = xfs_attr_set_args(&args, &leaf_bp); | |
293 | /* | ||
294 | * If the attribute list is non-existent or a shortform list, | ||
295 | * upgrade it to a single-leaf-block attribute list. | ||
296 | */ | ||
297 | if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL || | ||
298 | (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS && | ||
299 | dp->i_d.di_anextents == 0)) { | ||
300 | |||
301 | /* | ||
302 | * Build initial attribute list (if required). | ||
303 | */ | ||
304 | if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) | ||
305 | xfs_attr_shortform_create(&args); | ||
306 | |||
307 | /* | ||
308 | * Try to add the attr to the attribute list in | ||
309 | * the inode. | ||
310 | */ | ||
311 | error = xfs_attr_try_sf_addname(dp, &args); | ||
312 | if (error != -ENOSPC) { | ||
313 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | ||
314 | return error; | ||
315 | } | ||
316 | |||
317 | /* | ||
318 | * It won't fit in the shortform, transform to a leaf block. | ||
319 | * GROT: another possible req'mt for a double-split btree op. | ||
320 | */ | ||
321 | error = xfs_attr_shortform_to_leaf(&args, &leaf_bp); | ||
322 | if (error) | ||
323 | goto out; | ||
324 | /* | ||
325 | * Prevent the leaf buffer from being unlocked so that a | ||
326 | * concurrent AIL push cannot grab the half-baked leaf | ||
327 | * buffer and run into problems with the write verifier. | ||
328 | */ | ||
329 | xfs_trans_bhold(args.trans, leaf_bp); | ||
330 | error = xfs_defer_finish(&args.trans); | ||
331 | if (error) | ||
332 | goto out; | ||
333 | |||
334 | /* | ||
335 | * Commit the leaf transformation. We'll need another (linked) | ||
336 | * transaction to add the new attribute to the leaf, which | ||
337 | * means that we have to hold & join the leaf buffer here too. | ||
338 | */ | ||
339 | error = xfs_trans_roll_inode(&args.trans, dp); | ||
340 | if (error) | ||
341 | goto out; | ||
342 | xfs_trans_bjoin(args.trans, leaf_bp); | ||
343 | leaf_bp = NULL; | ||
344 | } | ||
345 | |||
346 | if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) | ||
347 | error = xfs_attr_leaf_addname(&args); | ||
348 | else | ||
349 | error = xfs_attr_node_addname(&args); | ||
350 | if (error) | 361 | if (error) |
351 | goto out; | 362 | goto out_release_leaf; |
363 | if (!args.trans) { | ||
364 | /* shortform attribute has already been committed */ | ||
365 | goto out_unlock; | ||
366 | } | ||
352 | 367 | ||
353 | /* | 368 | /* |
354 | * If this is a synchronous mount, make sure that the | 369 | * If this is a synchronous mount, make sure that the |
@@ -365,17 +380,17 @@ xfs_attr_set( | |||
365 | */ | 380 | */ |
366 | xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); | 381 | xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE); |
367 | error = xfs_trans_commit(args.trans); | 382 | error = xfs_trans_commit(args.trans); |
383 | out_unlock: | ||
368 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 384 | xfs_iunlock(dp, XFS_ILOCK_EXCL); |
369 | |||
370 | return error; | 385 | return error; |
371 | 386 | ||
372 | out: | 387 | out_release_leaf: |
373 | if (leaf_bp) | 388 | if (leaf_bp) |
374 | xfs_trans_brelse(args.trans, leaf_bp); | 389 | xfs_trans_brelse(args.trans, leaf_bp); |
390 | out_trans_cancel: | ||
375 | if (args.trans) | 391 | if (args.trans) |
376 | xfs_trans_cancel(args.trans); | 392 | xfs_trans_cancel(args.trans); |
377 | xfs_iunlock(dp, XFS_ILOCK_EXCL); | 393 | goto out_unlock; |
378 | return error; | ||
379 | } | 394 | } |
380 | 395 | ||
381 | /* | 396 | /* |
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h index 033ff8c478e2..f608ac8f306f 100644 --- a/fs/xfs/libxfs/xfs_attr.h +++ b/fs/xfs/libxfs/xfs_attr.h | |||
@@ -140,6 +140,7 @@ int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name, | |||
140 | unsigned char *value, int *valuelenp, int flags); | 140 | unsigned char *value, int *valuelenp, int flags); |
141 | int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name, | 141 | int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name, |
142 | unsigned char *value, int valuelen, int flags); | 142 | unsigned char *value, int valuelen, int flags); |
143 | int xfs_attr_set_args(struct xfs_da_args *args, struct xfs_buf **leaf_bp); | ||
143 | int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags); | 144 | int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags); |
144 | int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize, | 145 | int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize, |
145 | int flags, struct attrlist_cursor_kern *cursor); | 146 | int flags, struct attrlist_cursor_kern *cursor); |
diff --git a/fs/xfs/libxfs/xfs_bmap.c b/fs/xfs/libxfs/xfs_bmap.c index da6b768664e3..74d7228e755b 100644 --- a/fs/xfs/libxfs/xfs_bmap.c +++ b/fs/xfs/libxfs/xfs_bmap.c | |||
@@ -1019,6 +1019,34 @@ xfs_bmap_add_attrfork_local( | |||
1019 | return -EFSCORRUPTED; | 1019 | return -EFSCORRUPTED; |
1020 | } | 1020 | } |
1021 | 1021 | ||
1022 | /* Set an inode attr fork off based on the format */ | ||
1023 | int | ||
1024 | xfs_bmap_set_attrforkoff( | ||
1025 | struct xfs_inode *ip, | ||
1026 | int size, | ||
1027 | int *version) | ||
1028 | { | ||
1029 | switch (ip->i_d.di_format) { | ||
1030 | case XFS_DINODE_FMT_DEV: | ||
1031 | ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3; | ||
1032 | break; | ||
1033 | case XFS_DINODE_FMT_LOCAL: | ||
1034 | case XFS_DINODE_FMT_EXTENTS: | ||
1035 | case XFS_DINODE_FMT_BTREE: | ||
1036 | ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size); | ||
1037 | if (!ip->i_d.di_forkoff) | ||
1038 | ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3; | ||
1039 | else if ((ip->i_mount->m_flags & XFS_MOUNT_ATTR2) && version) | ||
1040 | *version = 2; | ||
1041 | break; | ||
1042 | default: | ||
1043 | ASSERT(0); | ||
1044 | return -EINVAL; | ||
1045 | } | ||
1046 | |||
1047 | return 0; | ||
1048 | } | ||
1049 | |||
1022 | /* | 1050 | /* |
1023 | * Convert inode from non-attributed to attributed. | 1051 | * Convert inode from non-attributed to attributed. |
1024 | * Must not be in a transaction, ip must not be locked. | 1052 | * Must not be in a transaction, ip must not be locked. |
@@ -1070,26 +1098,9 @@ xfs_bmap_add_attrfork( | |||
1070 | 1098 | ||
1071 | xfs_trans_ijoin(tp, ip, 0); | 1099 | xfs_trans_ijoin(tp, ip, 0); |
1072 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); | 1100 | xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); |
1073 | 1101 | error = xfs_bmap_set_attrforkoff(ip, size, &version); | |
1074 | switch (ip->i_d.di_format) { | 1102 | if (error) |
1075 | case XFS_DINODE_FMT_DEV: | ||
1076 | ip->i_d.di_forkoff = roundup(sizeof(xfs_dev_t), 8) >> 3; | ||
1077 | break; | ||
1078 | case XFS_DINODE_FMT_LOCAL: | ||
1079 | case XFS_DINODE_FMT_EXTENTS: | ||
1080 | case XFS_DINODE_FMT_BTREE: | ||
1081 | ip->i_d.di_forkoff = xfs_attr_shortform_bytesfit(ip, size); | ||
1082 | if (!ip->i_d.di_forkoff) | ||
1083 | ip->i_d.di_forkoff = xfs_default_attroffset(ip) >> 3; | ||
1084 | else if (mp->m_flags & XFS_MOUNT_ATTR2) | ||
1085 | version = 2; | ||
1086 | break; | ||
1087 | default: | ||
1088 | ASSERT(0); | ||
1089 | error = -EINVAL; | ||
1090 | goto trans_cancel; | 1103 | goto trans_cancel; |
1091 | } | ||
1092 | |||
1093 | ASSERT(ip->i_afp == NULL); | 1104 | ASSERT(ip->i_afp == NULL); |
1094 | ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP); | 1105 | ip->i_afp = kmem_zone_zalloc(xfs_ifork_zone, KM_SLEEP); |
1095 | ip->i_afp->if_flags = XFS_IFEXTENTS; | 1106 | ip->i_afp->if_flags = XFS_IFEXTENTS; |
diff --git a/fs/xfs/libxfs/xfs_bmap.h b/fs/xfs/libxfs/xfs_bmap.h index b6e9b639e731..488dc8860fd7 100644 --- a/fs/xfs/libxfs/xfs_bmap.h +++ b/fs/xfs/libxfs/xfs_bmap.h | |||
@@ -183,6 +183,7 @@ void xfs_trim_extent(struct xfs_bmbt_irec *irec, xfs_fileoff_t bno, | |||
183 | xfs_filblks_t len); | 183 | xfs_filblks_t len); |
184 | void xfs_trim_extent_eof(struct xfs_bmbt_irec *, struct xfs_inode *); | 184 | void xfs_trim_extent_eof(struct xfs_bmbt_irec *, struct xfs_inode *); |
185 | int xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd); | 185 | int xfs_bmap_add_attrfork(struct xfs_inode *ip, int size, int rsvd); |
186 | int xfs_bmap_set_attrforkoff(struct xfs_inode *ip, int size, int *version); | ||
186 | void xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork); | 187 | void xfs_bmap_local_to_extents_empty(struct xfs_inode *ip, int whichfork); |
187 | void __xfs_bmap_add_free(struct xfs_trans *tp, xfs_fsblock_t bno, | 188 | void __xfs_bmap_add_free(struct xfs_trans *tp, xfs_fsblock_t bno, |
188 | xfs_filblks_t len, struct xfs_owner_info *oinfo, | 189 | xfs_filblks_t len, struct xfs_owner_info *oinfo, |