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 | |
| 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')
| -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, |
