aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xfs/xfs_attr.c
diff options
context:
space:
mode:
authorDave Chinner <david@fromorbit.com>2014-05-14 19:39:28 -0400
committerDave Chinner <david@fromorbit.com>2014-05-14 19:39:28 -0400
commit2d6dcc6d7e95cc83046b2f97e179e6bbb7921245 (patch)
treed2fd8f88141001a92c8aeb66706f2b502542ade6 /fs/xfs/xfs_attr.c
parentff14ee42a038cf48263ac8d2eca5d30196554b82 (diff)
parent6c888af0b4ca66565b2aa73147ebc1d139c3bd1b (diff)
Merge branch 'xfs-attr-cleanup' into for-next
Conflicts: fs/xfs/xfs_attr.c
Diffstat (limited to 'fs/xfs/xfs_attr.c')
-rw-r--r--fs/xfs/xfs_attr.c328
1 files changed, 117 insertions, 211 deletions
diff --git a/fs/xfs/xfs_attr.c b/fs/xfs/xfs_attr.c
index abda1124a70f..1fc1f06277da 100644
--- a/fs/xfs/xfs_attr.c
+++ b/fs/xfs/xfs_attr.c
@@ -77,17 +77,26 @@ STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
77 77
78 78
79STATIC int 79STATIC int
80xfs_attr_name_to_xname( 80xfs_attr_args_init(
81 struct xfs_name *xname, 81 struct xfs_da_args *args,
82 const unsigned char *aname) 82 struct xfs_inode *dp,
83 const unsigned char *name,
84 int flags)
83{ 85{
84 if (!aname) 86
87 if (!name)
85 return EINVAL; 88 return EINVAL;
86 xname->name = aname; 89
87 xname->len = strlen((char *)aname); 90 memset(args, 0, sizeof(*args));
88 if (xname->len >= MAXNAMELEN) 91 args->whichfork = XFS_ATTR_FORK;
92 args->dp = dp;
93 args->flags = flags;
94 args->name = name;
95 args->namelen = strlen((const char *)name);
96 if (args->namelen >= MAXNAMELEN)
89 return EFAULT; /* match IRIX behaviour */ 97 return EFAULT; /* match IRIX behaviour */
90 98
99 args->hashval = xfs_da_hashname(args->name, args->namelen);
91 return 0; 100 return 0;
92} 101}
93 102
@@ -106,79 +115,46 @@ xfs_inode_hasattr(
106 * Overall external interface routines. 115 * Overall external interface routines.
107 *========================================================================*/ 116 *========================================================================*/
108 117
109STATIC int 118int
110xfs_attr_get_int( 119xfs_attr_get(
111 struct xfs_inode *ip, 120 struct xfs_inode *ip,
112 struct xfs_name *name, 121 const unsigned char *name,
113 unsigned char *value, 122 unsigned char *value,
114 int *valuelenp, 123 int *valuelenp,
115 int flags) 124 int flags)
116{ 125{
117 xfs_da_args_t args; 126 struct xfs_da_args args;
118 int error; 127 uint lock_mode;
128 int error;
129
130 XFS_STATS_INC(xs_attr_get);
131
132 if (XFS_FORCED_SHUTDOWN(ip->i_mount))
133 return EIO;
119 134
120 if (!xfs_inode_hasattr(ip)) 135 if (!xfs_inode_hasattr(ip))
121 return ENOATTR; 136 return ENOATTR;
122 137
123 /* 138 error = xfs_attr_args_init(&args, ip, name, flags);
124 * Fill in the arg structure for this request. 139 if (error)
125 */ 140 return error;
126 memset((char *)&args, 0, sizeof(args)); 141
127 args.name = name->name;
128 args.namelen = name->len;
129 args.value = value; 142 args.value = value;
130 args.valuelen = *valuelenp; 143 args.valuelen = *valuelenp;
131 args.flags = flags;
132 args.hashval = xfs_da_hashname(args.name, args.namelen);
133 args.dp = ip;
134 args.whichfork = XFS_ATTR_FORK;
135 144
136 /* 145 lock_mode = xfs_ilock_attr_map_shared(ip);
137 * Decide on what work routines to call based on the inode size. 146 if (!xfs_inode_hasattr(ip))
138 */ 147 error = ENOATTR;
139 if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) { 148 else if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL)
140 error = xfs_attr_shortform_getvalue(&args); 149 error = xfs_attr_shortform_getvalue(&args);
141 } else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) { 150 else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK))
142 error = xfs_attr_leaf_get(&args); 151 error = xfs_attr_leaf_get(&args);
143 } else { 152 else
144 error = xfs_attr_node_get(&args); 153 error = xfs_attr_node_get(&args);
145 } 154 xfs_iunlock(ip, lock_mode);
146 155
147 /*
148 * Return the number of bytes in the value to the caller.
149 */
150 *valuelenp = args.valuelen; 156 *valuelenp = args.valuelen;
151 157 return error == EEXIST ? 0 : error;
152 if (error == EEXIST)
153 error = 0;
154 return(error);
155}
156
157int
158xfs_attr_get(
159 xfs_inode_t *ip,
160 const unsigned char *name,
161 unsigned char *value,
162 int *valuelenp,
163 int flags)
164{
165 int error;
166 struct xfs_name xname;
167 uint lock_mode;
168
169 XFS_STATS_INC(xs_attr_get);
170
171 if (XFS_FORCED_SHUTDOWN(ip->i_mount))
172 return(EIO);
173
174 error = xfs_attr_name_to_xname(&xname, name);
175 if (error)
176 return error;
177
178 lock_mode = xfs_ilock_attr_map_shared(ip);
179 error = xfs_attr_get_int(ip, &xname, value, valuelenp, flags);
180 xfs_iunlock(ip, lock_mode);
181 return(error);
182} 158}
183 159
184/* 160/*
@@ -186,12 +162,10 @@ xfs_attr_get(
186 */ 162 */
187STATIC int 163STATIC int
188xfs_attr_calc_size( 164xfs_attr_calc_size(
189 struct xfs_inode *ip, 165 struct xfs_da_args *args,
190 int namelen,
191 int valuelen,
192 int *local) 166 int *local)
193{ 167{
194 struct xfs_mount *mp = ip->i_mount; 168 struct xfs_mount *mp = args->dp->i_mount;
195 int size; 169 int size;
196 int nblks; 170 int nblks;
197 171
@@ -199,7 +173,7 @@ xfs_attr_calc_size(
199 * Determine space new attribute will use, and if it would be 173 * Determine space new attribute will use, and if it would be
200 * "local" or "remote" (note: local != inline). 174 * "local" or "remote" (note: local != inline).
201 */ 175 */
202 size = xfs_attr_leaf_newentsize(namelen, valuelen, 176 size = xfs_attr_leaf_newentsize(args->namelen, args->valuelen,
203 mp->m_sb.sb_blocksize, local); 177 mp->m_sb.sb_blocksize, local);
204 178
205 nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); 179 nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
@@ -213,7 +187,7 @@ xfs_attr_calc_size(
213 * Out of line attribute, cannot double split, but 187 * Out of line attribute, cannot double split, but
214 * make room for the attribute value itself. 188 * make room for the attribute value itself.
215 */ 189 */
216 uint dblocks = xfs_attr3_rmt_blocks(mp, valuelen); 190 uint dblocks = xfs_attr3_rmt_blocks(mp, args->valuelen);
217 nblks += dblocks; 191 nblks += dblocks;
218 nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK); 192 nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);
219 } 193 }
@@ -221,26 +195,38 @@ xfs_attr_calc_size(
221 return nblks; 195 return nblks;
222} 196}
223 197
224STATIC int 198int
225xfs_attr_set_int( 199xfs_attr_set(
226 struct xfs_inode *dp, 200 struct xfs_inode *dp,
227 struct xfs_name *name, 201 const unsigned char *name,
228 unsigned char *value, 202 unsigned char *value,
229 int valuelen, 203 int valuelen,
230 int flags) 204 int flags)
231{ 205{
232 xfs_da_args_t args;
233 xfs_fsblock_t firstblock;
234 xfs_bmap_free_t flist;
235 int error, err2, committed;
236 struct xfs_mount *mp = dp->i_mount; 206 struct xfs_mount *mp = dp->i_mount;
207 struct xfs_da_args args;
208 struct xfs_bmap_free flist;
237 struct xfs_trans_res tres; 209 struct xfs_trans_res tres;
210 xfs_fsblock_t firstblock;
238 int rsvd = (flags & ATTR_ROOT) != 0; 211 int rsvd = (flags & ATTR_ROOT) != 0;
239 int local; 212 int error, err2, committed, local;
213
214 XFS_STATS_INC(xs_attr_set);
215
216 if (XFS_FORCED_SHUTDOWN(dp->i_mount))
217 return EIO;
218
219 error = xfs_attr_args_init(&args, dp, name, flags);
220 if (error)
221 return error;
222
223 args.value = value;
224 args.valuelen = valuelen;
225 args.firstblock = &firstblock;
226 args.flist = &flist;
227 args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
228 args.total = xfs_attr_calc_size(&args, &local);
240 229
241 /*
242 * Attach the dquots to the inode.
243 */
244 error = xfs_qm_dqattach(dp, 0); 230 error = xfs_qm_dqattach(dp, 0);
245 if (error) 231 if (error)
246 return error; 232 return error;
@@ -251,32 +237,14 @@ xfs_attr_set_int(
251 */ 237 */
252 if (XFS_IFORK_Q(dp) == 0) { 238 if (XFS_IFORK_Q(dp) == 0) {
253 int sf_size = sizeof(xfs_attr_sf_hdr_t) + 239 int sf_size = sizeof(xfs_attr_sf_hdr_t) +
254 XFS_ATTR_SF_ENTSIZE_BYNAME(name->len, valuelen); 240 XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
255 241
256 if ((error = xfs_bmap_add_attrfork(dp, sf_size, rsvd))) 242 error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
257 return(error); 243 if (error)
244 return error;
258 } 245 }
259 246
260 /* 247 /*
261 * Fill in the arg structure for this request.
262 */
263 memset((char *)&args, 0, sizeof(args));
264 args.name = name->name;
265 args.namelen = name->len;
266 args.value = value;
267 args.valuelen = valuelen;
268 args.flags = flags;
269 args.hashval = xfs_da_hashname(args.name, args.namelen);
270 args.dp = dp;
271 args.firstblock = &firstblock;
272 args.flist = &flist;
273 args.whichfork = XFS_ATTR_FORK;
274 args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
275
276 /* Size is now blocks for attribute data */
277 args.total = xfs_attr_calc_size(dp, name->len, valuelen, &local);
278
279 /*
280 * Start our first transaction of the day. 248 * Start our first transaction of the day.
281 * 249 *
282 * All future transactions during this code must be "chained" off 250 * All future transactions during this code must be "chained" off
@@ -303,7 +271,7 @@ xfs_attr_set_int(
303 error = xfs_trans_reserve(args.trans, &tres, args.total, 0); 271 error = xfs_trans_reserve(args.trans, &tres, args.total, 0);
304 if (error) { 272 if (error) {
305 xfs_trans_cancel(args.trans, 0); 273 xfs_trans_cancel(args.trans, 0);
306 return(error); 274 return error;
307 } 275 }
308 xfs_ilock(dp, XFS_ILOCK_EXCL); 276 xfs_ilock(dp, XFS_ILOCK_EXCL);
309 277
@@ -313,7 +281,7 @@ xfs_attr_set_int(
313 if (error) { 281 if (error) {
314 xfs_iunlock(dp, XFS_ILOCK_EXCL); 282 xfs_iunlock(dp, XFS_ILOCK_EXCL);
315 xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES); 283 xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
316 return (error); 284 return error;
317 } 285 }
318 286
319 xfs_trans_ijoin(args.trans, dp, 0); 287 xfs_trans_ijoin(args.trans, dp, 0);
@@ -322,9 +290,9 @@ xfs_attr_set_int(
322 * If the attribute list is non-existent or a shortform list, 290 * If the attribute list is non-existent or a shortform list,
323 * upgrade it to a single-leaf-block attribute list. 291 * upgrade it to a single-leaf-block attribute list.
324 */ 292 */
325 if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) || 293 if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL ||
326 ((dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) && 294 (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
327 (dp->i_d.di_anextents == 0))) { 295 dp->i_d.di_anextents == 0)) {
328 296
329 /* 297 /*
330 * Build initial attribute list (if required). 298 * Build initial attribute list (if required).
@@ -349,9 +317,8 @@ xfs_attr_set_int(
349 * the transaction goes to disk before returning 317 * the transaction goes to disk before returning
350 * to the user. 318 * to the user.
351 */ 319 */
352 if (mp->m_flags & XFS_MOUNT_WSYNC) { 320 if (mp->m_flags & XFS_MOUNT_WSYNC)
353 xfs_trans_set_sync(args.trans); 321 xfs_trans_set_sync(args.trans);
354 }
355 322
356 if (!error && (flags & ATTR_KERNOTIME) == 0) { 323 if (!error && (flags & ATTR_KERNOTIME) == 0) {
357 xfs_trans_ichgtime(args.trans, dp, 324 xfs_trans_ichgtime(args.trans, dp,
@@ -361,7 +328,7 @@ xfs_attr_set_int(
361 XFS_TRANS_RELEASE_LOG_RES); 328 XFS_TRANS_RELEASE_LOG_RES);
362 xfs_iunlock(dp, XFS_ILOCK_EXCL); 329 xfs_iunlock(dp, XFS_ILOCK_EXCL);
363 330
364 return(error == 0 ? err2 : error); 331 return error ? error : err2;
365 } 332 }
366 333
367 /* 334 /*
@@ -399,22 +366,19 @@ xfs_attr_set_int(
399 366
400 } 367 }
401 368
402 if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { 369 if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
403 error = xfs_attr_leaf_addname(&args); 370 error = xfs_attr_leaf_addname(&args);
404 } else { 371 else
405 error = xfs_attr_node_addname(&args); 372 error = xfs_attr_node_addname(&args);
406 } 373 if (error)
407 if (error) {
408 goto out; 374 goto out;
409 }
410 375
411 /* 376 /*
412 * If this is a synchronous mount, make sure that the 377 * If this is a synchronous mount, make sure that the
413 * transaction goes to disk before returning to the user. 378 * transaction goes to disk before returning to the user.
414 */ 379 */
415 if (mp->m_flags & XFS_MOUNT_WSYNC) { 380 if (mp->m_flags & XFS_MOUNT_WSYNC)
416 xfs_trans_set_sync(args.trans); 381 xfs_trans_set_sync(args.trans);
417 }
418 382
419 if ((flags & ATTR_KERNOTIME) == 0) 383 if ((flags & ATTR_KERNOTIME) == 0)
420 xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG); 384 xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
@@ -426,65 +390,47 @@ xfs_attr_set_int(
426 error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES); 390 error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
427 xfs_iunlock(dp, XFS_ILOCK_EXCL); 391 xfs_iunlock(dp, XFS_ILOCK_EXCL);
428 392
429 return(error); 393 return error;
430 394
431out: 395out:
432 if (args.trans) 396 if (args.trans) {
433 xfs_trans_cancel(args.trans, 397 xfs_trans_cancel(args.trans,
434 XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); 398 XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
399 }
435 xfs_iunlock(dp, XFS_ILOCK_EXCL); 400 xfs_iunlock(dp, XFS_ILOCK_EXCL);
436 return(error); 401 return error;
437} 402}
438 403
404/*
405 * Generic handler routine to remove a name from an attribute list.
406 * Transitions attribute list from Btree to shortform as necessary.
407 */
439int 408int
440xfs_attr_set( 409xfs_attr_remove(
441 xfs_inode_t *dp, 410 struct xfs_inode *dp,
442 const unsigned char *name, 411 const unsigned char *name,
443 unsigned char *value, 412 int flags)
444 int valuelen,
445 int flags)
446{ 413{
447 int error; 414 struct xfs_mount *mp = dp->i_mount;
448 struct xfs_name xname; 415 struct xfs_da_args args;
416 struct xfs_bmap_free flist;
417 xfs_fsblock_t firstblock;
418 int error;
449 419
450 XFS_STATS_INC(xs_attr_set); 420 XFS_STATS_INC(xs_attr_remove);
451 421
452 if (XFS_FORCED_SHUTDOWN(dp->i_mount)) 422 if (XFS_FORCED_SHUTDOWN(dp->i_mount))
453 return (EIO); 423 return EIO;
454 424
455 error = xfs_attr_name_to_xname(&xname, name); 425 if (!xfs_inode_hasattr(dp))
426 return ENOATTR;
427
428 error = xfs_attr_args_init(&args, dp, name, flags);
456 if (error) 429 if (error)
457 return error; 430 return error;
458 431
459 return xfs_attr_set_int(dp, &xname, value, valuelen, flags);
460}
461
462/*
463 * Generic handler routine to remove a name from an attribute list.
464 * Transitions attribute list from Btree to shortform as necessary.
465 */
466STATIC int
467xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
468{
469 xfs_da_args_t args;
470 xfs_fsblock_t firstblock;
471 xfs_bmap_free_t flist;
472 int error;
473 xfs_mount_t *mp = dp->i_mount;
474
475 /*
476 * Fill in the arg structure for this request.
477 */
478 memset((char *)&args, 0, sizeof(args));
479 args.name = name->name;
480 args.namelen = name->len;
481 args.flags = flags;
482 args.hashval = xfs_da_hashname(args.name, args.namelen);
483 args.dp = dp;
484 args.firstblock = &firstblock; 432 args.firstblock = &firstblock;
485 args.flist = &flist; 433 args.flist = &flist;
486 args.total = 0;
487 args.whichfork = XFS_ATTR_FORK;
488 434
489 /* 435 /*
490 * we have no control over the attribute names that userspace passes us 436 * we have no control over the attribute names that userspace passes us
@@ -493,9 +439,6 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
493 */ 439 */
494 args.op_flags = XFS_DA_OP_OKNOENT; 440 args.op_flags = XFS_DA_OP_OKNOENT;
495 441
496 /*
497 * Attach the dquots to the inode.
498 */
499 error = xfs_qm_dqattach(dp, 0); 442 error = xfs_qm_dqattach(dp, 0);
500 if (error) 443 if (error)
501 return error; 444 return error;
@@ -524,7 +467,7 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
524 XFS_ATTRRM_SPACE_RES(mp), 0); 467 XFS_ATTRRM_SPACE_RES(mp), 0);
525 if (error) { 468 if (error) {
526 xfs_trans_cancel(args.trans, 0); 469 xfs_trans_cancel(args.trans, 0);
527 return(error); 470 return error;
528 } 471 }
529 472
530 xfs_ilock(dp, XFS_ILOCK_EXCL); 473 xfs_ilock(dp, XFS_ILOCK_EXCL);
@@ -534,35 +477,26 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
534 */ 477 */
535 xfs_trans_ijoin(args.trans, dp, 0); 478 xfs_trans_ijoin(args.trans, dp, 0);
536 479
537 /*
538 * Decide on what work routines to call based on the inode size.
539 */
540 if (!xfs_inode_hasattr(dp)) { 480 if (!xfs_inode_hasattr(dp)) {
541 error = XFS_ERROR(ENOATTR); 481 error = XFS_ERROR(ENOATTR);
542 goto out; 482 } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
543 }
544 if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
545 ASSERT(dp->i_afp->if_flags & XFS_IFINLINE); 483 ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
546 error = xfs_attr_shortform_remove(&args); 484 error = xfs_attr_shortform_remove(&args);
547 if (error) {
548 goto out;
549 }
550 } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) { 485 } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
551 error = xfs_attr_leaf_removename(&args); 486 error = xfs_attr_leaf_removename(&args);
552 } else { 487 } else {
553 error = xfs_attr_node_removename(&args); 488 error = xfs_attr_node_removename(&args);
554 } 489 }
555 if (error) { 490
491 if (error)
556 goto out; 492 goto out;
557 }
558 493
559 /* 494 /*
560 * If this is a synchronous mount, make sure that the 495 * If this is a synchronous mount, make sure that the
561 * transaction goes to disk before returning to the user. 496 * transaction goes to disk before returning to the user.
562 */ 497 */
563 if (mp->m_flags & XFS_MOUNT_WSYNC) { 498 if (mp->m_flags & XFS_MOUNT_WSYNC)
564 xfs_trans_set_sync(args.trans); 499 xfs_trans_set_sync(args.trans);
565 }
566 500
567 if ((flags & ATTR_KERNOTIME) == 0) 501 if ((flags & ATTR_KERNOTIME) == 0)
568 xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG); 502 xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
@@ -574,45 +508,17 @@ xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
574 error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES); 508 error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
575 xfs_iunlock(dp, XFS_ILOCK_EXCL); 509 xfs_iunlock(dp, XFS_ILOCK_EXCL);
576 510
577 return(error); 511 return error;
578 512
579out: 513out:
580 if (args.trans) 514 if (args.trans) {
581 xfs_trans_cancel(args.trans, 515 xfs_trans_cancel(args.trans,
582 XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT); 516 XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
583 xfs_iunlock(dp, XFS_ILOCK_EXCL);
584 return(error);
585}
586
587int
588xfs_attr_remove(
589 xfs_inode_t *dp,
590 const unsigned char *name,
591 int flags)
592{
593 int error;
594 struct xfs_name xname;
595
596 XFS_STATS_INC(xs_attr_remove);
597
598 if (XFS_FORCED_SHUTDOWN(dp->i_mount))
599 return (EIO);
600
601 error = xfs_attr_name_to_xname(&xname, name);
602 if (error)
603 return error;
604
605 xfs_ilock(dp, XFS_ILOCK_SHARED);
606 if (!xfs_inode_hasattr(dp)) {
607 xfs_iunlock(dp, XFS_ILOCK_SHARED);
608 return XFS_ERROR(ENOATTR);
609 } 517 }
610 xfs_iunlock(dp, XFS_ILOCK_SHARED); 518 xfs_iunlock(dp, XFS_ILOCK_EXCL);
611 519 return error;
612 return xfs_attr_remove_int(dp, &xname, flags);
613} 520}
614 521
615
616/*======================================================================== 522/*========================================================================
617 * External routines when attribute list is inside the inode 523 * External routines when attribute list is inside the inode
618 *========================================================================*/ 524 *========================================================================*/