@@ -203,6 +203,66 @@ xfs_attr_try_sf_addname(
203
203
return error ;
204
204
}
205
205
206
+ /*
207
+ * Check to see if the attr should be upgraded from non-existent or shortform to
208
+ * single-leaf-block attribute list.
209
+ */
210
+ static inline bool
211
+ xfs_attr_is_shortform (
212
+ struct xfs_inode * ip )
213
+ {
214
+ return ip -> i_afp -> if_format == XFS_DINODE_FMT_LOCAL ||
215
+ (ip -> i_afp -> if_format == XFS_DINODE_FMT_EXTENTS &&
216
+ ip -> i_afp -> if_nextents == 0 );
217
+ }
218
+
219
+ /*
220
+ * Attempts to set an attr in shortform, or converts short form to leaf form if
221
+ * there is not enough room. If the attr is set, the transaction is committed
222
+ * and set to NULL.
223
+ */
224
+ STATIC int
225
+ xfs_attr_set_shortform (
226
+ struct xfs_da_args * args ,
227
+ struct xfs_buf * * leaf_bp )
228
+ {
229
+ struct xfs_inode * dp = args -> dp ;
230
+ int error , error2 = 0 ;
231
+
232
+ /*
233
+ * Try to add the attr to the attribute list in the inode.
234
+ */
235
+ error = xfs_attr_try_sf_addname (dp , args );
236
+ if (error != - ENOSPC ) {
237
+ error2 = xfs_trans_commit (args -> trans );
238
+ args -> trans = NULL ;
239
+ return error ? error : error2 ;
240
+ }
241
+ /*
242
+ * It won't fit in the shortform, transform to a leaf block. GROT:
243
+ * another possible req'mt for a double-split btree op.
244
+ */
245
+ error = xfs_attr_shortform_to_leaf (args , leaf_bp );
246
+ if (error )
247
+ return error ;
248
+
249
+ /*
250
+ * Prevent the leaf buffer from being unlocked so that a concurrent AIL
251
+ * push cannot grab the half-baked leaf buffer and run into problems
252
+ * with the write verifier. Once we're done rolling the transaction we
253
+ * can release the hold and add the attr to the leaf.
254
+ */
255
+ xfs_trans_bhold (args -> trans , * leaf_bp );
256
+ error = xfs_defer_finish (& args -> trans );
257
+ xfs_trans_bhold_release (args -> trans , * leaf_bp );
258
+ if (error ) {
259
+ xfs_trans_brelse (args -> trans , * leaf_bp );
260
+ return error ;
261
+ }
262
+
263
+ return 0 ;
264
+ }
265
+
206
266
/*
207
267
* Set the attribute specified in @args.
208
268
*/
@@ -212,48 +272,25 @@ xfs_attr_set_args(
212
272
{
213
273
struct xfs_inode * dp = args -> dp ;
214
274
struct xfs_buf * leaf_bp = NULL ;
215
- int error , error2 = 0 ;
275
+ int error = 0 ;
216
276
217
277
/*
218
- * If the attribute list is non-existent or a shortform list,
219
- * upgrade it to a single-leaf-block attribute list.
278
+ * If the attribute list is already in leaf format, jump straight to
279
+ * leaf handling. Otherwise, try to add the attribute to the shortform
280
+ * list; if there's no room then convert the list to leaf format and try
281
+ * again.
220
282
*/
221
- if (dp -> i_afp -> if_format == XFS_DINODE_FMT_LOCAL ||
222
- (dp -> i_afp -> if_format == XFS_DINODE_FMT_EXTENTS &&
223
- dp -> i_afp -> if_nextents == 0 )) {
283
+ if (xfs_attr_is_shortform (dp )) {
224
284
225
285
/*
226
- * Try to add the attr to the attribute list in the inode.
286
+ * If the attr was successfully set in shortform, the
287
+ * transaction is committed and set to NULL. Otherwise, is it
288
+ * converted from shortform to leaf, and the transaction is
289
+ * retained.
227
290
*/
228
- error = xfs_attr_try_sf_addname (dp , args );
229
- if (error != - ENOSPC ) {
230
- error2 = xfs_trans_commit (args -> trans );
231
- args -> trans = NULL ;
232
- return error ? error : error2 ;
233
- }
234
-
235
- /*
236
- * It won't fit in the shortform, transform to a leaf block.
237
- * GROT: another possible req'mt for a double-split btree op.
238
- */
239
- error = xfs_attr_shortform_to_leaf (args , & leaf_bp );
240
- if (error )
241
- return error ;
242
-
243
- /*
244
- * Prevent the leaf buffer from being unlocked so that a
245
- * concurrent AIL push cannot grab the half-baked leaf
246
- * buffer and run into problems with the write verifier.
247
- * Once we're done rolling the transaction we can release
248
- * the hold and add the attr to the leaf.
249
- */
250
- xfs_trans_bhold (args -> trans , leaf_bp );
251
- error = xfs_defer_finish (& args -> trans );
252
- xfs_trans_bhold_release (args -> trans , leaf_bp );
253
- if (error ) {
254
- xfs_trans_brelse (args -> trans , leaf_bp );
291
+ error = xfs_attr_set_shortform (args , & leaf_bp );
292
+ if (error || !args -> trans )
255
293
return error ;
256
- }
257
294
}
258
295
259
296
if (xfs_bmap_one_block (dp , XFS_ATTR_FORK )) {
0 commit comments