blob: e9fd5acb43053c3b7ab3ae8890deebf630ed9024 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
Nathan Scott7b718762005-11-02 14:58:39 +11002 * Copyright (c) 2000-2005 Silicon Graphics, Inc.
3 * All Rights Reserved.
Linus Torvalds1da177e2005-04-16 15:20:36 -07004 *
Nathan Scott7b718762005-11-02 14:58:39 +11005 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
Linus Torvalds1da177e2005-04-16 15:20:36 -07007 * published by the Free Software Foundation.
8 *
Nathan Scott7b718762005-11-02 14:58:39 +11009 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
Linus Torvalds1da177e2005-04-16 15:20:36 -070013 *
Nathan Scott7b718762005-11-02 14:58:39 +110014 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write the Free Software Foundation,
16 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Linus Torvalds1da177e2005-04-16 15:20:36 -070017 */
Linus Torvalds1da177e2005-04-16 15:20:36 -070018#include "xfs.h"
Nathan Scotta844f452005-11-02 14:38:42 +110019#include "xfs_fs.h"
Dave Chinner6ca1c902013-08-12 20:49:26 +100020#include "xfs_format.h"
Nathan Scotta844f452005-11-02 14:38:42 +110021#include "xfs_bit.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include "xfs_log.h"
23#include "xfs_trans.h"
Dave Chinnerd386b322013-08-12 20:49:31 +100024#include "xfs_trans_priv.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070025#include "xfs_sb.h"
26#include "xfs_ag.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070027#include "xfs_mount.h"
Nathan Scotta844f452005-11-02 14:38:42 +110028#include "xfs_da_btree.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070029#include "xfs_bmap_btree.h"
Nathan Scotta844f452005-11-02 14:38:42 +110030#include "xfs_attr_sf.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070031#include "xfs_dinode.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070032#include "xfs_inode.h"
Nathan Scotta844f452005-11-02 14:38:42 +110033#include "xfs_alloc.h"
Nathan Scotta844f452005-11-02 14:38:42 +110034#include "xfs_inode_item.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070035#include "xfs_bmap.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070036#include "xfs_attr.h"
37#include "xfs_attr_leaf.h"
Dave Chinner95920cd2013-04-03 16:11:27 +110038#include "xfs_attr_remote.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070039#include "xfs_error.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070040#include "xfs_quota.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include "xfs_trans_space.h"
Christoph Hellwig739bfb22007-08-29 10:58:01 +100042#include "xfs_vnodeops.h"
Christoph Hellwig0b1b2132009-12-14 23:14:59 +000043#include "xfs_trace.h"
Linus Torvalds1da177e2005-04-16 15:20:36 -070044
45/*
46 * xfs_attr.c
47 *
48 * Provide the external interfaces to manage attribute lists.
49 */
50
51/*========================================================================
52 * Function prototypes for the kernel.
53 *========================================================================*/
54
55/*
56 * Internal routines when attribute list fits inside the inode.
57 */
58STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
59
60/*
61 * Internal routines when attribute list is one block.
62 */
Christoph Hellwigba0f32d2005-06-21 15:36:52 +100063STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
Linus Torvalds1da177e2005-04-16 15:20:36 -070064STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
65STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
Linus Torvalds1da177e2005-04-16 15:20:36 -070066
67/*
68 * Internal routines when attribute list is more than one block.
69 */
Christoph Hellwigba0f32d2005-06-21 15:36:52 +100070STATIC int xfs_attr_node_get(xfs_da_args_t *args);
Linus Torvalds1da177e2005-04-16 15:20:36 -070071STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
72STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
Linus Torvalds1da177e2005-04-16 15:20:36 -070073STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
74STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
75
Linus Torvalds1da177e2005-04-16 15:20:36 -070076
Barry Naujoke8b0eba2008-04-22 17:34:31 +100077STATIC int
78xfs_attr_name_to_xname(
79 struct xfs_name *xname,
Dave Chinnera9273ca2010-01-20 10:47:48 +110080 const unsigned char *aname)
Barry Naujoke8b0eba2008-04-22 17:34:31 +100081{
82 if (!aname)
83 return EINVAL;
84 xname->name = aname;
Dave Chinnera9273ca2010-01-20 10:47:48 +110085 xname->len = strlen((char *)aname);
Barry Naujoke8b0eba2008-04-22 17:34:31 +100086 if (xname->len >= MAXNAMELEN)
87 return EFAULT; /* match IRIX behaviour */
88
89 return 0;
90}
Linus Torvalds1da177e2005-04-16 15:20:36 -070091
Dave Chinnerabec5f22013-08-12 20:49:38 +100092int
Christoph Hellwigcaf8aab2008-06-23 13:23:41 +100093xfs_inode_hasattr(
94 struct xfs_inode *ip)
95{
96 if (!XFS_IFORK_Q(ip) ||
97 (ip->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS &&
98 ip->i_d.di_anextents == 0))
99 return 0;
100 return 1;
101}
102
Linus Torvalds1da177e2005-04-16 15:20:36 -0700103/*========================================================================
104 * Overall external interface routines.
105 *========================================================================*/
106
Christoph Hellwige82fa0c2009-11-14 16:17:20 +0000107STATIC int
108xfs_attr_get_int(
109 struct xfs_inode *ip,
110 struct xfs_name *name,
Dave Chinnera9273ca2010-01-20 10:47:48 +1100111 unsigned char *value,
Christoph Hellwige82fa0c2009-11-14 16:17:20 +0000112 int *valuelenp,
113 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700114{
115 xfs_da_args_t args;
116 int error;
117
Christoph Hellwigcaf8aab2008-06-23 13:23:41 +1000118 if (!xfs_inode_hasattr(ip))
119 return ENOATTR;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700120
Linus Torvalds1da177e2005-04-16 15:20:36 -0700121 /*
122 * Fill in the arg structure for this request.
123 */
124 memset((char *)&args, 0, sizeof(args));
Barry Naujoke8b0eba2008-04-22 17:34:31 +1000125 args.name = name->name;
126 args.namelen = name->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700127 args.value = value;
128 args.valuelen = *valuelenp;
129 args.flags = flags;
130 args.hashval = xfs_da_hashname(args.name, args.namelen);
131 args.dp = ip;
132 args.whichfork = XFS_ATTR_FORK;
133
134 /*
135 * Decide on what work routines to call based on the inode size.
136 */
Christoph Hellwigcaf8aab2008-06-23 13:23:41 +1000137 if (ip->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700138 error = xfs_attr_shortform_getvalue(&args);
139 } else if (xfs_bmap_one_block(ip, XFS_ATTR_FORK)) {
140 error = xfs_attr_leaf_get(&args);
141 } else {
142 error = xfs_attr_node_get(&args);
143 }
144
145 /*
146 * Return the number of bytes in the value to the caller.
147 */
148 *valuelenp = args.valuelen;
149
150 if (error == EEXIST)
151 error = 0;
152 return(error);
153}
154
155int
Christoph Hellwig993386c2007-08-28 16:12:30 +1000156xfs_attr_get(
157 xfs_inode_t *ip,
Dave Chinnera9273ca2010-01-20 10:47:48 +1100158 const unsigned char *name,
159 unsigned char *value,
Christoph Hellwig993386c2007-08-28 16:12:30 +1000160 int *valuelenp,
Barry Naujoke8b0eba2008-04-22 17:34:31 +1000161 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700162{
Barry Naujoke8b0eba2008-04-22 17:34:31 +1000163 int error;
164 struct xfs_name xname;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700165
166 XFS_STATS_INC(xs_attr_get);
167
Linus Torvalds1da177e2005-04-16 15:20:36 -0700168 if (XFS_FORCED_SHUTDOWN(ip->i_mount))
169 return(EIO);
170
Barry Naujoke8b0eba2008-04-22 17:34:31 +1000171 error = xfs_attr_name_to_xname(&xname, name);
172 if (error)
173 return error;
174
Linus Torvalds1da177e2005-04-16 15:20:36 -0700175 xfs_ilock(ip, XFS_ILOCK_SHARED);
Christoph Hellwige82fa0c2009-11-14 16:17:20 +0000176 error = xfs_attr_get_int(ip, &xname, value, valuelenp, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700177 xfs_iunlock(ip, XFS_ILOCK_SHARED);
178 return(error);
179}
180
Niv Sardi5e9da7b2008-08-13 16:03:35 +1000181/*
182 * Calculate how many blocks we need for the new attribute,
183 */
Eric Sandeen5d77c0d2009-11-19 15:52:00 +0000184STATIC int
Niv Sardi5e9da7b2008-08-13 16:03:35 +1000185xfs_attr_calc_size(
186 struct xfs_inode *ip,
187 int namelen,
188 int valuelen,
189 int *local)
190{
191 struct xfs_mount *mp = ip->i_mount;
192 int size;
193 int nblks;
194
195 /*
196 * Determine space new attribute will use, and if it would be
197 * "local" or "remote" (note: local != inline).
198 */
199 size = xfs_attr_leaf_newentsize(namelen, valuelen,
200 mp->m_sb.sb_blocksize, local);
201
202 nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK);
203 if (*local) {
204 if (size > (mp->m_sb.sb_blocksize >> 1)) {
205 /* Double split possible */
206 nblks *= 2;
207 }
208 } else {
209 /*
210 * Out of line attribute, cannot double split, but
211 * make room for the attribute value itself.
212 */
213 uint dblocks = XFS_B_TO_FSB(mp, valuelen);
214 nblks += dblocks;
215 nblks += XFS_NEXTENTADD_SPACE_RES(mp, dblocks, XFS_ATTR_FORK);
216 }
217
218 return nblks;
219}
220
Barry Naujoke8b0eba2008-04-22 17:34:31 +1000221STATIC int
Dave Chinnera9273ca2010-01-20 10:47:48 +1100222xfs_attr_set_int(
223 struct xfs_inode *dp,
224 struct xfs_name *name,
225 unsigned char *value,
226 int valuelen,
227 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700228{
229 xfs_da_args_t args;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700230 xfs_fsblock_t firstblock;
231 xfs_bmap_free_t flist;
232 int error, err2, committed;
Nathan Scottaa82daa2005-11-02 10:33:33 +1100233 xfs_mount_t *mp = dp->i_mount;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700234 int rsvd = (flags & ATTR_ROOT) != 0;
Niv Sardi5e9da7b2008-08-13 16:03:35 +1000235 int local;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700236
237 /*
238 * Attach the dquots to the inode.
239 */
Christoph Hellwig7d095252009-06-08 15:33:32 +0200240 error = xfs_qm_dqattach(dp, 0);
241 if (error)
242 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244 /*
245 * If the inode doesn't have an attribute fork, add one.
246 * (inode must not be locked when we call this routine)
247 */
248 if (XFS_IFORK_Q(dp) == 0) {
Barry Naujoke5889e92007-02-10 18:35:58 +1100249 int sf_size = sizeof(xfs_attr_sf_hdr_t) +
Barry Naujoke8b0eba2008-04-22 17:34:31 +1000250 XFS_ATTR_SF_ENTSIZE_BYNAME(name->len, valuelen);
Barry Naujoke5889e92007-02-10 18:35:58 +1100251
252 if ((error = xfs_bmap_add_attrfork(dp, sf_size, rsvd)))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700253 return(error);
254 }
255
256 /*
257 * Fill in the arg structure for this request.
258 */
259 memset((char *)&args, 0, sizeof(args));
Barry Naujoke8b0eba2008-04-22 17:34:31 +1000260 args.name = name->name;
261 args.namelen = name->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700262 args.value = value;
263 args.valuelen = valuelen;
264 args.flags = flags;
265 args.hashval = xfs_da_hashname(args.name, args.namelen);
266 args.dp = dp;
267 args.firstblock = &firstblock;
268 args.flist = &flist;
269 args.whichfork = XFS_ATTR_FORK;
Barry Naujok6a178102008-05-21 16:42:05 +1000270 args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700271
Linus Torvalds1da177e2005-04-16 15:20:36 -0700272 /* Size is now blocks for attribute data */
Niv Sardi5e9da7b2008-08-13 16:03:35 +1000273 args.total = xfs_attr_calc_size(dp, name->len, valuelen, &local);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700274
275 /*
276 * Start our first transaction of the day.
277 *
278 * All future transactions during this code must be "chained" off
279 * this one via the trans_dup() call. All transactions will contain
280 * the inode, and the inode will always be marked with trans_ihold().
281 * Since the inode will be locked in all transactions, we must log
282 * the inode in every transaction to let it float upward through
283 * the log.
284 */
285 args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_SET);
286
287 /*
288 * Root fork attributes can use reserved data blocks for this
289 * operation if necessary
290 */
291
292 if (rsvd)
293 args.trans->t_flags |= XFS_TRANS_RESERVE;
294
Jeff Liua21cd502013-01-28 21:27:53 +0800295 error = xfs_trans_reserve(args.trans, args.total,
296 XFS_ATTRSETM_LOG_RES(mp) +
297 XFS_ATTRSETRT_LOG_RES(mp) * args.total,
298 0, XFS_TRANS_PERM_LOG_RES,
299 XFS_ATTRSET_LOG_COUNT);
300 if (error) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700301 xfs_trans_cancel(args.trans, 0);
302 return(error);
303 }
304 xfs_ilock(dp, XFS_ILOCK_EXCL);
305
Christoph Hellwig7d095252009-06-08 15:33:32 +0200306 error = xfs_trans_reserve_quota_nblks(args.trans, dp, args.total, 0,
Niv Sardi5e9da7b2008-08-13 16:03:35 +1000307 rsvd ? XFS_QMOPT_RES_REGBLKS | XFS_QMOPT_FORCE_RES :
308 XFS_QMOPT_RES_REGBLKS);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700309 if (error) {
310 xfs_iunlock(dp, XFS_ILOCK_EXCL);
311 xfs_trans_cancel(args.trans, XFS_TRANS_RELEASE_LOG_RES);
312 return (error);
313 }
314
Christoph Hellwigddc34152011-09-19 15:00:54 +0000315 xfs_trans_ijoin(args.trans, dp, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700316
317 /*
Nathan Scottc41564b2006-03-29 08:55:14 +1000318 * If the attribute list is non-existent or a shortform list,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700319 * upgrade it to a single-leaf-block attribute list.
320 */
321 if ((dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) ||
322 ((dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS) &&
323 (dp->i_d.di_anextents == 0))) {
324
325 /*
326 * Build initial attribute list (if required).
327 */
328 if (dp->i_d.di_aformat == XFS_DINODE_FMT_EXTENTS)
Nathan Scottd8cc8902005-11-02 10:34:53 +1100329 xfs_attr_shortform_create(&args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700330
331 /*
332 * Try to add the attr to the attribute list in
333 * the inode.
334 */
335 error = xfs_attr_shortform_addname(&args);
336 if (error != ENOSPC) {
337 /*
338 * Commit the shortform mods, and we're done.
339 * NOTE: this is also the error path (EEXIST, etc).
340 */
341 ASSERT(args.trans != NULL);
342
343 /*
344 * If this is a synchronous mount, make sure that
345 * the transaction goes to disk before returning
346 * to the user.
347 */
348 if (mp->m_flags & XFS_MOUNT_WSYNC) {
349 xfs_trans_set_sync(args.trans);
350 }
Dave Chinnerdcd79a12010-09-28 12:27:25 +1000351
352 if (!error && (flags & ATTR_KERNOTIME) == 0) {
353 xfs_trans_ichgtime(args.trans, dp,
354 XFS_ICHGTIME_CHG);
355 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700356 err2 = xfs_trans_commit(args.trans,
Eric Sandeen1c72bf92007-05-08 13:48:42 +1000357 XFS_TRANS_RELEASE_LOG_RES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700358 xfs_iunlock(dp, XFS_ILOCK_EXCL);
359
Linus Torvalds1da177e2005-04-16 15:20:36 -0700360 return(error == 0 ? err2 : error);
361 }
362
363 /*
364 * It won't fit in the shortform, transform to a leaf block.
365 * GROT: another possible req'mt for a double-split btree op.
366 */
Eric Sandeen9d87c312009-01-14 23:22:07 -0600367 xfs_bmap_init(args.flist, args.firstblock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700368 error = xfs_attr_shortform_to_leaf(&args);
369 if (!error) {
370 error = xfs_bmap_finish(&args.trans, args.flist,
Eric Sandeenf7c99b62007-02-10 18:37:16 +1100371 &committed);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700372 }
373 if (error) {
374 ASSERT(committed);
375 args.trans = NULL;
376 xfs_bmap_cancel(&flist);
377 goto out;
378 }
379
380 /*
381 * bmap_finish() may have committed the last trans and started
382 * a new one. We need the inode to be in all transactions.
383 */
Christoph Hellwig898621d2010-06-24 11:36:58 +1000384 if (committed)
Christoph Hellwigddc34152011-09-19 15:00:54 +0000385 xfs_trans_ijoin(args.trans, dp, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700386
387 /*
388 * Commit the leaf transformation. We'll need another (linked)
389 * transaction to add the new attribute to the leaf.
390 */
Niv Sardi322ff6b2008-08-13 16:05:49 +1000391
392 error = xfs_trans_roll(&args.trans, dp);
393 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700394 goto out;
395
396 }
397
398 if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
399 error = xfs_attr_leaf_addname(&args);
400 } else {
401 error = xfs_attr_node_addname(&args);
402 }
403 if (error) {
404 goto out;
405 }
406
407 /*
408 * If this is a synchronous mount, make sure that the
409 * transaction goes to disk before returning to the user.
410 */
411 if (mp->m_flags & XFS_MOUNT_WSYNC) {
412 xfs_trans_set_sync(args.trans);
413 }
414
Dave Chinnerdcd79a12010-09-28 12:27:25 +1000415 if ((flags & ATTR_KERNOTIME) == 0)
416 xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
417
Linus Torvalds1da177e2005-04-16 15:20:36 -0700418 /*
419 * Commit the last in the sequence of transactions.
420 */
421 xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
Eric Sandeen1c72bf92007-05-08 13:48:42 +1000422 error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700423 xfs_iunlock(dp, XFS_ILOCK_EXCL);
424
Linus Torvalds1da177e2005-04-16 15:20:36 -0700425 return(error);
426
427out:
428 if (args.trans)
429 xfs_trans_cancel(args.trans,
430 XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
431 xfs_iunlock(dp, XFS_ILOCK_EXCL);
432 return(error);
433}
434
Nathan Scottaa82daa2005-11-02 10:33:33 +1100435int
Christoph Hellwig993386c2007-08-28 16:12:30 +1000436xfs_attr_set(
437 xfs_inode_t *dp,
Dave Chinnera9273ca2010-01-20 10:47:48 +1100438 const unsigned char *name,
439 unsigned char *value,
Christoph Hellwig993386c2007-08-28 16:12:30 +1000440 int valuelen,
441 int flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700442{
Barry Naujoke8b0eba2008-04-22 17:34:31 +1000443 int error;
444 struct xfs_name xname;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700445
Nathan Scottaa82daa2005-11-02 10:33:33 +1100446 XFS_STATS_INC(xs_attr_set);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700447
Nathan Scottaa82daa2005-11-02 10:33:33 +1100448 if (XFS_FORCED_SHUTDOWN(dp->i_mount))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700449 return (EIO);
450
Barry Naujoke8b0eba2008-04-22 17:34:31 +1000451 error = xfs_attr_name_to_xname(&xname, name);
452 if (error)
453 return error;
454
455 return xfs_attr_set_int(dp, &xname, value, valuelen, flags);
Nathan Scottaa82daa2005-11-02 10:33:33 +1100456}
457
458/*
459 * Generic handler routine to remove a name from an attribute list.
460 * Transitions attribute list from Btree to shortform as necessary.
461 */
Barry Naujoke8b0eba2008-04-22 17:34:31 +1000462STATIC int
463xfs_attr_remove_int(xfs_inode_t *dp, struct xfs_name *name, int flags)
Nathan Scottaa82daa2005-11-02 10:33:33 +1100464{
465 xfs_da_args_t args;
466 xfs_fsblock_t firstblock;
467 xfs_bmap_free_t flist;
468 int error;
469 xfs_mount_t *mp = dp->i_mount;
470
Linus Torvalds1da177e2005-04-16 15:20:36 -0700471 /*
472 * Fill in the arg structure for this request.
473 */
474 memset((char *)&args, 0, sizeof(args));
Barry Naujoke8b0eba2008-04-22 17:34:31 +1000475 args.name = name->name;
476 args.namelen = name->len;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700477 args.flags = flags;
478 args.hashval = xfs_da_hashname(args.name, args.namelen);
479 args.dp = dp;
480 args.firstblock = &firstblock;
481 args.flist = &flist;
482 args.total = 0;
483 args.whichfork = XFS_ATTR_FORK;
484
485 /*
Dave Chinner4a338212011-06-23 01:35:01 +0000486 * we have no control over the attribute names that userspace passes us
487 * to remove, so we have to allow the name lookup prior to attribute
488 * removal to fail.
489 */
490 args.op_flags = XFS_DA_OP_OKNOENT;
491
492 /*
Linus Torvalds1da177e2005-04-16 15:20:36 -0700493 * Attach the dquots to the inode.
494 */
Christoph Hellwig7d095252009-06-08 15:33:32 +0200495 error = xfs_qm_dqattach(dp, 0);
496 if (error)
497 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700498
499 /*
500 * Start our first transaction of the day.
501 *
502 * All future transactions during this code must be "chained" off
503 * this one via the trans_dup() call. All transactions will contain
504 * the inode, and the inode will always be marked with trans_ihold().
505 * Since the inode will be locked in all transactions, we must log
506 * the inode in every transaction to let it float upward through
507 * the log.
508 */
509 args.trans = xfs_trans_alloc(mp, XFS_TRANS_ATTR_RM);
510
511 /*
512 * Root fork attributes can use reserved data blocks for this
513 * operation if necessary
514 */
515
516 if (flags & ATTR_ROOT)
517 args.trans->t_flags |= XFS_TRANS_RESERVE;
518
519 if ((error = xfs_trans_reserve(args.trans,
520 XFS_ATTRRM_SPACE_RES(mp),
521 XFS_ATTRRM_LOG_RES(mp),
522 0, XFS_TRANS_PERM_LOG_RES,
523 XFS_ATTRRM_LOG_COUNT))) {
524 xfs_trans_cancel(args.trans, 0);
525 return(error);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700526 }
527
528 xfs_ilock(dp, XFS_ILOCK_EXCL);
529 /*
530 * No need to make quota reservations here. We expect to release some
531 * blocks not allocate in the common case.
532 */
Christoph Hellwigddc34152011-09-19 15:00:54 +0000533 xfs_trans_ijoin(args.trans, dp, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700534
535 /*
536 * Decide on what work routines to call based on the inode size.
537 */
Christoph Hellwigcaf8aab2008-06-23 13:23:41 +1000538 if (!xfs_inode_hasattr(dp)) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700539 error = XFS_ERROR(ENOATTR);
540 goto out;
541 }
542 if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
543 ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
544 error = xfs_attr_shortform_remove(&args);
545 if (error) {
546 goto out;
547 }
548 } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
549 error = xfs_attr_leaf_removename(&args);
550 } else {
551 error = xfs_attr_node_removename(&args);
552 }
553 if (error) {
554 goto out;
555 }
556
557 /*
558 * If this is a synchronous mount, make sure that the
559 * transaction goes to disk before returning to the user.
560 */
561 if (mp->m_flags & XFS_MOUNT_WSYNC) {
562 xfs_trans_set_sync(args.trans);
563 }
564
Dave Chinnerdcd79a12010-09-28 12:27:25 +1000565 if ((flags & ATTR_KERNOTIME) == 0)
566 xfs_trans_ichgtime(args.trans, dp, XFS_ICHGTIME_CHG);
567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 /*
569 * Commit the last in the sequence of transactions.
570 */
571 xfs_trans_log_inode(args.trans, dp, XFS_ILOG_CORE);
Eric Sandeen1c72bf92007-05-08 13:48:42 +1000572 error = xfs_trans_commit(args.trans, XFS_TRANS_RELEASE_LOG_RES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700573 xfs_iunlock(dp, XFS_ILOCK_EXCL);
574
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575 return(error);
576
577out:
578 if (args.trans)
579 xfs_trans_cancel(args.trans,
580 XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
581 xfs_iunlock(dp, XFS_ILOCK_EXCL);
582 return(error);
583}
584
Nathan Scottaa82daa2005-11-02 10:33:33 +1100585int
Christoph Hellwig993386c2007-08-28 16:12:30 +1000586xfs_attr_remove(
587 xfs_inode_t *dp,
Dave Chinnera9273ca2010-01-20 10:47:48 +1100588 const unsigned char *name,
Christoph Hellwig993386c2007-08-28 16:12:30 +1000589 int flags)
Nathan Scottaa82daa2005-11-02 10:33:33 +1100590{
Barry Naujoke8b0eba2008-04-22 17:34:31 +1000591 int error;
592 struct xfs_name xname;
Nathan Scottaa82daa2005-11-02 10:33:33 +1100593
594 XFS_STATS_INC(xs_attr_remove);
595
Nathan Scottaa82daa2005-11-02 10:33:33 +1100596 if (XFS_FORCED_SHUTDOWN(dp->i_mount))
597 return (EIO);
598
Barry Naujoke8b0eba2008-04-22 17:34:31 +1000599 error = xfs_attr_name_to_xname(&xname, name);
600 if (error)
601 return error;
602
Nathan Scottaa82daa2005-11-02 10:33:33 +1100603 xfs_ilock(dp, XFS_ILOCK_SHARED);
Christoph Hellwigcaf8aab2008-06-23 13:23:41 +1000604 if (!xfs_inode_hasattr(dp)) {
Nathan Scottaa82daa2005-11-02 10:33:33 +1100605 xfs_iunlock(dp, XFS_ILOCK_SHARED);
Christoph Hellwigcaf8aab2008-06-23 13:23:41 +1000606 return XFS_ERROR(ENOATTR);
Nathan Scottaa82daa2005-11-02 10:33:33 +1100607 }
608 xfs_iunlock(dp, XFS_ILOCK_SHARED);
609
Barry Naujoke8b0eba2008-04-22 17:34:31 +1000610 return xfs_attr_remove_int(dp, &xname, flags);
Nathan Scottaa82daa2005-11-02 10:33:33 +1100611}
612
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613int /* error */
614xfs_attr_inactive(xfs_inode_t *dp)
615{
616 xfs_trans_t *trans;
617 xfs_mount_t *mp;
618 int error;
619
620 mp = dp->i_mount;
621 ASSERT(! XFS_NOT_DQATTACHED(mp, dp));
622
623 xfs_ilock(dp, XFS_ILOCK_SHARED);
Christoph Hellwigcaf8aab2008-06-23 13:23:41 +1000624 if (!xfs_inode_hasattr(dp) ||
625 dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700626 xfs_iunlock(dp, XFS_ILOCK_SHARED);
Christoph Hellwigcaf8aab2008-06-23 13:23:41 +1000627 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700628 }
629 xfs_iunlock(dp, XFS_ILOCK_SHARED);
630
631 /*
632 * Start our first transaction of the day.
633 *
634 * All future transactions during this code must be "chained" off
635 * this one via the trans_dup() call. All transactions will contain
636 * the inode, and the inode will always be marked with trans_ihold().
637 * Since the inode will be locked in all transactions, we must log
638 * the inode in every transaction to let it float upward through
639 * the log.
640 */
641 trans = xfs_trans_alloc(mp, XFS_TRANS_ATTRINVAL);
642 if ((error = xfs_trans_reserve(trans, 0, XFS_ATTRINVAL_LOG_RES(mp), 0,
643 XFS_TRANS_PERM_LOG_RES,
644 XFS_ATTRINVAL_LOG_COUNT))) {
645 xfs_trans_cancel(trans, 0);
646 return(error);
647 }
648 xfs_ilock(dp, XFS_ILOCK_EXCL);
649
650 /*
651 * No need to make quota reservations here. We expect to release some
652 * blocks, not allocate, in the common case.
653 */
Christoph Hellwigddc34152011-09-19 15:00:54 +0000654 xfs_trans_ijoin(trans, dp, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700655
656 /*
657 * Decide on what work routines to call based on the inode size.
658 */
Christoph Hellwigcaf8aab2008-06-23 13:23:41 +1000659 if (!xfs_inode_hasattr(dp) ||
660 dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700661 error = 0;
662 goto out;
663 }
Dave Chinner517c2222013-04-24 18:58:55 +1000664 error = xfs_attr3_root_inactive(&trans, dp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700665 if (error)
666 goto out;
Christoph Hellwig8f04c472011-07-08 14:34:34 +0200667
Christoph Hellwig8f04c472011-07-08 14:34:34 +0200668 error = xfs_itruncate_extents(&trans, dp, XFS_ATTR_FORK, 0);
669 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700670 goto out;
671
Eric Sandeen1c72bf92007-05-08 13:48:42 +1000672 error = xfs_trans_commit(trans, XFS_TRANS_RELEASE_LOG_RES);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673 xfs_iunlock(dp, XFS_ILOCK_EXCL);
674
675 return(error);
676
677out:
678 xfs_trans_cancel(trans, XFS_TRANS_RELEASE_LOG_RES|XFS_TRANS_ABORT);
679 xfs_iunlock(dp, XFS_ILOCK_EXCL);
680 return(error);
681}
682
683
684
685/*========================================================================
686 * External routines when attribute list is inside the inode
687 *========================================================================*/
688
689/*
690 * Add a name to the shortform attribute list structure
691 * This is the external routine.
692 */
693STATIC int
694xfs_attr_shortform_addname(xfs_da_args_t *args)
695{
Nathan Scottd8cc8902005-11-02 10:34:53 +1100696 int newsize, forkoff, retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700697
Dave Chinner5a5881c2012-03-22 05:15:13 +0000698 trace_xfs_attr_sf_addname(args);
699
Linus Torvalds1da177e2005-04-16 15:20:36 -0700700 retval = xfs_attr_shortform_lookup(args);
701 if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
702 return(retval);
703 } else if (retval == EEXIST) {
704 if (args->flags & ATTR_CREATE)
705 return(retval);
706 retval = xfs_attr_shortform_remove(args);
707 ASSERT(retval == 0);
708 }
709
Nathan Scottd8cc8902005-11-02 10:34:53 +1100710 if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
711 args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)
712 return(XFS_ERROR(ENOSPC));
713
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714 newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
715 newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
Nathan Scottd8cc8902005-11-02 10:34:53 +1100716
717 forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);
718 if (!forkoff)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700719 return(XFS_ERROR(ENOSPC));
Nathan Scottd8cc8902005-11-02 10:34:53 +1100720
721 xfs_attr_shortform_add(args, forkoff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700722 return(0);
723}
724
725
726/*========================================================================
727 * External routines when attribute list is one block
728 *========================================================================*/
729
730/*
731 * Add a name to the leaf attribute list structure
732 *
733 * This leaf block cannot have a "remote" value, we only call this routine
734 * if bmap_one_block() says there is only one block (ie: no remote blks).
735 */
David Chinnera8272ce2007-11-23 16:28:09 +1100736STATIC int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700737xfs_attr_leaf_addname(xfs_da_args_t *args)
738{
739 xfs_inode_t *dp;
Dave Chinner1d9025e2012-06-22 18:50:14 +1000740 struct xfs_buf *bp;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100741 int retval, error, committed, forkoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700742
Dave Chinner5a5881c2012-03-22 05:15:13 +0000743 trace_xfs_attr_leaf_addname(args);
744
Linus Torvalds1da177e2005-04-16 15:20:36 -0700745 /*
746 * Read the (only) block in the attribute list in.
747 */
748 dp = args->dp;
749 args->blkno = 0;
Dave Chinner517c2222013-04-24 18:58:55 +1000750 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751 if (error)
Dave Chinnerad14c332012-11-12 22:54:16 +1100752 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700753
754 /*
755 * Look up the given attribute in the leaf block. Figure out if
756 * the given flags produce an error or call for an atomic rename.
757 */
Dave Chinner517c2222013-04-24 18:58:55 +1000758 retval = xfs_attr3_leaf_lookup_int(bp, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700759 if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
Dave Chinner1d9025e2012-06-22 18:50:14 +1000760 xfs_trans_brelse(args->trans, bp);
Dave Chinner517c2222013-04-24 18:58:55 +1000761 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700762 } else if (retval == EEXIST) {
763 if (args->flags & ATTR_CREATE) { /* pure create op */
Dave Chinner1d9025e2012-06-22 18:50:14 +1000764 xfs_trans_brelse(args->trans, bp);
Dave Chinner517c2222013-04-24 18:58:55 +1000765 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700766 }
Dave Chinner5a5881c2012-03-22 05:15:13 +0000767
768 trace_xfs_attr_leaf_replace(args);
769
Barry Naujok6a178102008-05-21 16:42:05 +1000770 args->op_flags |= XFS_DA_OP_RENAME; /* an atomic rename */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700771 args->blkno2 = args->blkno; /* set 2nd entry info*/
772 args->index2 = args->index;
773 args->rmtblkno2 = args->rmtblkno;
774 args->rmtblkcnt2 = args->rmtblkcnt;
775 }
776
777 /*
778 * Add the attribute to the leaf block, transitioning to a Btree
779 * if required.
780 */
Dave Chinner517c2222013-04-24 18:58:55 +1000781 retval = xfs_attr3_leaf_add(bp, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700782 if (retval == ENOSPC) {
783 /*
784 * Promote the attribute list to the Btree format, then
785 * Commit that transaction so that the node_addname() call
786 * can manage its own transactions.
787 */
Eric Sandeen9d87c312009-01-14 23:22:07 -0600788 xfs_bmap_init(args->flist, args->firstblock);
Dave Chinner517c2222013-04-24 18:58:55 +1000789 error = xfs_attr3_leaf_to_node(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700790 if (!error) {
791 error = xfs_bmap_finish(&args->trans, args->flist,
Eric Sandeenf7c99b62007-02-10 18:37:16 +1100792 &committed);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700793 }
794 if (error) {
795 ASSERT(committed);
796 args->trans = NULL;
797 xfs_bmap_cancel(args->flist);
798 return(error);
799 }
800
801 /*
802 * bmap_finish() may have committed the last trans and started
803 * a new one. We need the inode to be in all transactions.
804 */
Christoph Hellwig898621d2010-06-24 11:36:58 +1000805 if (committed)
Christoph Hellwigddc34152011-09-19 15:00:54 +0000806 xfs_trans_ijoin(args->trans, dp, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700807
808 /*
809 * Commit the current trans (including the inode) and start
810 * a new one.
811 */
Niv Sardi322ff6b2008-08-13 16:05:49 +1000812 error = xfs_trans_roll(&args->trans, dp);
813 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700814 return (error);
815
816 /*
817 * Fob the whole rest of the problem off on the Btree code.
818 */
819 error = xfs_attr_node_addname(args);
820 return(error);
821 }
822
823 /*
824 * Commit the transaction that added the attr name so that
825 * later routines can manage their own transactions.
826 */
Niv Sardi322ff6b2008-08-13 16:05:49 +1000827 error = xfs_trans_roll(&args->trans, dp);
828 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700829 return (error);
830
831 /*
832 * If there was an out-of-line value, allocate the blocks we
833 * identified for its storage and copy the value. This is done
834 * after we create the attribute so that we don't overflow the
835 * maximum size of a transaction and/or hit a deadlock.
836 */
837 if (args->rmtblkno > 0) {
838 error = xfs_attr_rmtval_set(args);
839 if (error)
840 return(error);
841 }
842
843 /*
844 * If this is an atomic rename operation, we must "flip" the
845 * incomplete flags on the "new" and "old" attribute/value pairs
846 * so that one disappears and one appears atomically. Then we
847 * must remove the "old" attribute/value pair.
848 */
Barry Naujok6a178102008-05-21 16:42:05 +1000849 if (args->op_flags & XFS_DA_OP_RENAME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700850 /*
851 * In a separate transaction, set the incomplete flag on the
852 * "old" attr and clear the incomplete flag on the "new" attr.
853 */
Dave Chinner517c2222013-04-24 18:58:55 +1000854 error = xfs_attr3_leaf_flipflags(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700855 if (error)
856 return(error);
857
858 /*
859 * Dismantle the "old" attribute/value pair by removing
860 * a "remote" value (if it exists).
861 */
862 args->index = args->index2;
863 args->blkno = args->blkno2;
864 args->rmtblkno = args->rmtblkno2;
865 args->rmtblkcnt = args->rmtblkcnt2;
866 if (args->rmtblkno) {
867 error = xfs_attr_rmtval_remove(args);
868 if (error)
869 return(error);
870 }
871
872 /*
873 * Read in the block containing the "old" attr, then
874 * remove the "old" attr from that block (neat, huh!)
875 */
Dave Chinner517c2222013-04-24 18:58:55 +1000876 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
Dave Chinnerad14c332012-11-12 22:54:16 +1100877 -1, &bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878 if (error)
Dave Chinnerad14c332012-11-12 22:54:16 +1100879 return error;
880
Dave Chinner517c2222013-04-24 18:58:55 +1000881 xfs_attr3_leaf_remove(bp, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882
883 /*
884 * If the result is small enough, shrink it all into the inode.
885 */
Nathan Scottd8cc8902005-11-02 10:34:53 +1100886 if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
Eric Sandeen9d87c312009-01-14 23:22:07 -0600887 xfs_bmap_init(args->flist, args->firstblock);
Dave Chinner517c2222013-04-24 18:58:55 +1000888 error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 /* bp is gone due to xfs_da_shrink_inode */
890 if (!error) {
891 error = xfs_bmap_finish(&args->trans,
892 args->flist,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700893 &committed);
894 }
895 if (error) {
896 ASSERT(committed);
897 args->trans = NULL;
898 xfs_bmap_cancel(args->flist);
899 return(error);
900 }
901
902 /*
903 * bmap_finish() may have committed the last trans
904 * and started a new one. We need the inode to be
905 * in all transactions.
906 */
Christoph Hellwig898621d2010-06-24 11:36:58 +1000907 if (committed)
Christoph Hellwigddc34152011-09-19 15:00:54 +0000908 xfs_trans_ijoin(args->trans, dp, 0);
Dave Chinner1d9025e2012-06-22 18:50:14 +1000909 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910
911 /*
912 * Commit the remove and start the next trans in series.
913 */
Niv Sardi322ff6b2008-08-13 16:05:49 +1000914 error = xfs_trans_roll(&args->trans, dp);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700915
916 } else if (args->rmtblkno > 0) {
917 /*
918 * Added a "remote" value, just clear the incomplete flag.
919 */
Dave Chinner517c2222013-04-24 18:58:55 +1000920 error = xfs_attr3_leaf_clearflag(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700921 }
Dave Chinner517c2222013-04-24 18:58:55 +1000922 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700923}
924
925/*
926 * Remove a name from the leaf attribute list structure
927 *
928 * This leaf block cannot have a "remote" value, we only call this routine
929 * if bmap_one_block() says there is only one block (ie: no remote blks).
930 */
931STATIC int
932xfs_attr_leaf_removename(xfs_da_args_t *args)
933{
934 xfs_inode_t *dp;
Dave Chinner1d9025e2012-06-22 18:50:14 +1000935 struct xfs_buf *bp;
Nathan Scottd8cc8902005-11-02 10:34:53 +1100936 int error, committed, forkoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700937
Dave Chinner5a5881c2012-03-22 05:15:13 +0000938 trace_xfs_attr_leaf_removename(args);
939
Linus Torvalds1da177e2005-04-16 15:20:36 -0700940 /*
941 * Remove the attribute.
942 */
943 dp = args->dp;
944 args->blkno = 0;
Dave Chinner517c2222013-04-24 18:58:55 +1000945 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
Dave Chinnerad14c332012-11-12 22:54:16 +1100946 if (error)
947 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700948
Dave Chinner517c2222013-04-24 18:58:55 +1000949 error = xfs_attr3_leaf_lookup_int(bp, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700950 if (error == ENOATTR) {
Dave Chinner1d9025e2012-06-22 18:50:14 +1000951 xfs_trans_brelse(args->trans, bp);
Dave Chinner517c2222013-04-24 18:58:55 +1000952 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700953 }
954
Dave Chinner517c2222013-04-24 18:58:55 +1000955 xfs_attr3_leaf_remove(bp, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700956
957 /*
958 * If the result is small enough, shrink it all into the inode.
959 */
Nathan Scottd8cc8902005-11-02 10:34:53 +1100960 if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
Eric Sandeen9d87c312009-01-14 23:22:07 -0600961 xfs_bmap_init(args->flist, args->firstblock);
Dave Chinner517c2222013-04-24 18:58:55 +1000962 error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700963 /* bp is gone due to xfs_da_shrink_inode */
964 if (!error) {
965 error = xfs_bmap_finish(&args->trans, args->flist,
Eric Sandeenf7c99b62007-02-10 18:37:16 +1100966 &committed);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700967 }
968 if (error) {
969 ASSERT(committed);
970 args->trans = NULL;
971 xfs_bmap_cancel(args->flist);
Dave Chinner517c2222013-04-24 18:58:55 +1000972 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700973 }
974
975 /*
976 * bmap_finish() may have committed the last trans and started
977 * a new one. We need the inode to be in all transactions.
978 */
Christoph Hellwig898621d2010-06-24 11:36:58 +1000979 if (committed)
Christoph Hellwigddc34152011-09-19 15:00:54 +0000980 xfs_trans_ijoin(args->trans, dp, 0);
Dave Chinner1d9025e2012-06-22 18:50:14 +1000981 }
Dave Chinner517c2222013-04-24 18:58:55 +1000982 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700983}
984
985/*
986 * Look up a name in a leaf attribute list structure.
987 *
988 * This leaf block cannot have a "remote" value, we only call this routine
989 * if bmap_one_block() says there is only one block (ie: no remote blks).
990 */
Christoph Hellwigba0f32d2005-06-21 15:36:52 +1000991STATIC int
Linus Torvalds1da177e2005-04-16 15:20:36 -0700992xfs_attr_leaf_get(xfs_da_args_t *args)
993{
Dave Chinner1d9025e2012-06-22 18:50:14 +1000994 struct xfs_buf *bp;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700995 int error;
996
Dave Chinneree732592012-11-12 22:53:53 +1100997 trace_xfs_attr_leaf_get(args);
998
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999 args->blkno = 0;
Dave Chinner517c2222013-04-24 18:58:55 +10001000 error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001001 if (error)
Dave Chinnerad14c332012-11-12 22:54:16 +11001002 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001003
Dave Chinner517c2222013-04-24 18:58:55 +10001004 error = xfs_attr3_leaf_lookup_int(bp, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001005 if (error != EEXIST) {
Dave Chinner1d9025e2012-06-22 18:50:14 +10001006 xfs_trans_brelse(args->trans, bp);
Dave Chinner517c2222013-04-24 18:58:55 +10001007 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001008 }
Dave Chinner517c2222013-04-24 18:58:55 +10001009 error = xfs_attr3_leaf_getvalue(bp, args);
Dave Chinner1d9025e2012-06-22 18:50:14 +10001010 xfs_trans_brelse(args->trans, bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001011 if (!error && (args->rmtblkno > 0) && !(args->flags & ATTR_KERNOVAL)) {
1012 error = xfs_attr_rmtval_get(args);
1013 }
Dave Chinner517c2222013-04-24 18:58:55 +10001014 return error;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001015}
1016
Linus Torvalds1da177e2005-04-16 15:20:36 -07001017/*========================================================================
1018 * External routines when attribute list size > XFS_LBSIZE(mp).
1019 *========================================================================*/
1020
1021/*
1022 * Add a name to a Btree-format attribute list.
1023 *
1024 * This will involve walking down the Btree, and may involve splitting
1025 * leaf nodes and even splitting intermediate nodes up to and including
1026 * the root node (a special case of an intermediate node).
1027 *
1028 * "Remote" attribute values confuse the issue and atomic rename operations
1029 * add a whole extra layer of confusion on top of that.
1030 */
1031STATIC int
1032xfs_attr_node_addname(xfs_da_args_t *args)
1033{
1034 xfs_da_state_t *state;
1035 xfs_da_state_blk_t *blk;
1036 xfs_inode_t *dp;
1037 xfs_mount_t *mp;
1038 int committed, retval, error;
1039
Dave Chinner5a5881c2012-03-22 05:15:13 +00001040 trace_xfs_attr_node_addname(args);
1041
Linus Torvalds1da177e2005-04-16 15:20:36 -07001042 /*
1043 * Fill in bucket of arguments/results/context to carry around.
1044 */
1045 dp = args->dp;
1046 mp = dp->i_mount;
1047restart:
1048 state = xfs_da_state_alloc();
1049 state->args = args;
1050 state->mp = mp;
1051 state->blocksize = state->mp->m_sb.sb_blocksize;
1052 state->node_ents = state->mp->m_attr_node_ents;
1053
1054 /*
1055 * Search to see if name already exists, and get back a pointer
1056 * to where it should go.
1057 */
Dave Chinnerf5ea1102013-04-24 18:58:02 +10001058 error = xfs_da3_node_lookup_int(state, &retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001059 if (error)
1060 goto out;
1061 blk = &state->path.blk[ state->path.active-1 ];
1062 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1063 if ((args->flags & ATTR_REPLACE) && (retval == ENOATTR)) {
1064 goto out;
1065 } else if (retval == EEXIST) {
1066 if (args->flags & ATTR_CREATE)
1067 goto out;
Dave Chinner5a5881c2012-03-22 05:15:13 +00001068
1069 trace_xfs_attr_node_replace(args);
1070
Barry Naujok6a178102008-05-21 16:42:05 +10001071 args->op_flags |= XFS_DA_OP_RENAME; /* atomic rename op */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001072 args->blkno2 = args->blkno; /* set 2nd entry info*/
1073 args->index2 = args->index;
1074 args->rmtblkno2 = args->rmtblkno;
1075 args->rmtblkcnt2 = args->rmtblkcnt;
1076 args->rmtblkno = 0;
1077 args->rmtblkcnt = 0;
1078 }
1079
Dave Chinner517c2222013-04-24 18:58:55 +10001080 retval = xfs_attr3_leaf_add(blk->bp, state->args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001081 if (retval == ENOSPC) {
1082 if (state->path.active == 1) {
1083 /*
1084 * Its really a single leaf node, but it had
1085 * out-of-line values so it looked like it *might*
1086 * have been a b-tree.
1087 */
1088 xfs_da_state_free(state);
Eric Sandeen9d87c312009-01-14 23:22:07 -06001089 xfs_bmap_init(args->flist, args->firstblock);
Dave Chinner517c2222013-04-24 18:58:55 +10001090 error = xfs_attr3_leaf_to_node(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001091 if (!error) {
1092 error = xfs_bmap_finish(&args->trans,
1093 args->flist,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001094 &committed);
1095 }
1096 if (error) {
1097 ASSERT(committed);
1098 args->trans = NULL;
1099 xfs_bmap_cancel(args->flist);
1100 goto out;
1101 }
1102
1103 /*
1104 * bmap_finish() may have committed the last trans
1105 * and started a new one. We need the inode to be
1106 * in all transactions.
1107 */
Christoph Hellwig898621d2010-06-24 11:36:58 +10001108 if (committed)
Christoph Hellwigddc34152011-09-19 15:00:54 +00001109 xfs_trans_ijoin(args->trans, dp, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001110
1111 /*
1112 * Commit the node conversion and start the next
1113 * trans in the chain.
1114 */
Niv Sardi322ff6b2008-08-13 16:05:49 +10001115 error = xfs_trans_roll(&args->trans, dp);
1116 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001117 goto out;
1118
1119 goto restart;
1120 }
1121
1122 /*
1123 * Split as many Btree elements as required.
1124 * This code tracks the new and old attr's location
1125 * in the index/blkno/rmtblkno/rmtblkcnt fields and
1126 * in the index2/blkno2/rmtblkno2/rmtblkcnt2 fields.
1127 */
Eric Sandeen9d87c312009-01-14 23:22:07 -06001128 xfs_bmap_init(args->flist, args->firstblock);
Dave Chinnerf5ea1102013-04-24 18:58:02 +10001129 error = xfs_da3_split(state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001130 if (!error) {
1131 error = xfs_bmap_finish(&args->trans, args->flist,
Eric Sandeenf7c99b62007-02-10 18:37:16 +11001132 &committed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001133 }
1134 if (error) {
1135 ASSERT(committed);
1136 args->trans = NULL;
1137 xfs_bmap_cancel(args->flist);
1138 goto out;
1139 }
1140
1141 /*
1142 * bmap_finish() may have committed the last trans and started
1143 * a new one. We need the inode to be in all transactions.
1144 */
Christoph Hellwig898621d2010-06-24 11:36:58 +10001145 if (committed)
Christoph Hellwigddc34152011-09-19 15:00:54 +00001146 xfs_trans_ijoin(args->trans, dp, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001147 } else {
1148 /*
1149 * Addition succeeded, update Btree hashvals.
1150 */
Dave Chinnerf5ea1102013-04-24 18:58:02 +10001151 xfs_da3_fixhashpath(state, &state->path);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 }
1153
1154 /*
1155 * Kill the state structure, we're done with it and need to
1156 * allow the buffers to come back later.
1157 */
1158 xfs_da_state_free(state);
1159 state = NULL;
1160
1161 /*
1162 * Commit the leaf addition or btree split and start the next
1163 * trans in the chain.
1164 */
Niv Sardi322ff6b2008-08-13 16:05:49 +10001165 error = xfs_trans_roll(&args->trans, dp);
1166 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001167 goto out;
1168
1169 /*
1170 * If there was an out-of-line value, allocate the blocks we
1171 * identified for its storage and copy the value. This is done
1172 * after we create the attribute so that we don't overflow the
1173 * maximum size of a transaction and/or hit a deadlock.
1174 */
1175 if (args->rmtblkno > 0) {
1176 error = xfs_attr_rmtval_set(args);
1177 if (error)
1178 return(error);
1179 }
1180
1181 /*
1182 * If this is an atomic rename operation, we must "flip" the
1183 * incomplete flags on the "new" and "old" attribute/value pairs
1184 * so that one disappears and one appears atomically. Then we
1185 * must remove the "old" attribute/value pair.
1186 */
Barry Naujok6a178102008-05-21 16:42:05 +10001187 if (args->op_flags & XFS_DA_OP_RENAME) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001188 /*
1189 * In a separate transaction, set the incomplete flag on the
1190 * "old" attr and clear the incomplete flag on the "new" attr.
1191 */
Dave Chinner517c2222013-04-24 18:58:55 +10001192 error = xfs_attr3_leaf_flipflags(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001193 if (error)
1194 goto out;
1195
1196 /*
1197 * Dismantle the "old" attribute/value pair by removing
1198 * a "remote" value (if it exists).
1199 */
1200 args->index = args->index2;
1201 args->blkno = args->blkno2;
1202 args->rmtblkno = args->rmtblkno2;
1203 args->rmtblkcnt = args->rmtblkcnt2;
1204 if (args->rmtblkno) {
1205 error = xfs_attr_rmtval_remove(args);
1206 if (error)
1207 return(error);
1208 }
1209
1210 /*
1211 * Re-find the "old" attribute entry after any split ops.
1212 * The INCOMPLETE flag means that we will find the "old"
1213 * attr, not the "new" one.
1214 */
1215 args->flags |= XFS_ATTR_INCOMPLETE;
1216 state = xfs_da_state_alloc();
1217 state->args = args;
1218 state->mp = mp;
1219 state->blocksize = state->mp->m_sb.sb_blocksize;
1220 state->node_ents = state->mp->m_attr_node_ents;
1221 state->inleaf = 0;
Dave Chinnerf5ea1102013-04-24 18:58:02 +10001222 error = xfs_da3_node_lookup_int(state, &retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001223 if (error)
1224 goto out;
1225
1226 /*
1227 * Remove the name and update the hashvals in the tree.
1228 */
1229 blk = &state->path.blk[ state->path.active-1 ];
1230 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
Dave Chinner517c2222013-04-24 18:58:55 +10001231 error = xfs_attr3_leaf_remove(blk->bp, args);
Dave Chinnerf5ea1102013-04-24 18:58:02 +10001232 xfs_da3_fixhashpath(state, &state->path);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001233
1234 /*
1235 * Check to see if the tree needs to be collapsed.
1236 */
1237 if (retval && (state->path.active > 1)) {
Eric Sandeen9d87c312009-01-14 23:22:07 -06001238 xfs_bmap_init(args->flist, args->firstblock);
Dave Chinnerf5ea1102013-04-24 18:58:02 +10001239 error = xfs_da3_join(state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001240 if (!error) {
1241 error = xfs_bmap_finish(&args->trans,
1242 args->flist,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001243 &committed);
1244 }
1245 if (error) {
1246 ASSERT(committed);
1247 args->trans = NULL;
1248 xfs_bmap_cancel(args->flist);
1249 goto out;
1250 }
1251
1252 /*
1253 * bmap_finish() may have committed the last trans
1254 * and started a new one. We need the inode to be
1255 * in all transactions.
1256 */
Christoph Hellwig898621d2010-06-24 11:36:58 +10001257 if (committed)
Christoph Hellwigddc34152011-09-19 15:00:54 +00001258 xfs_trans_ijoin(args->trans, dp, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001259 }
1260
1261 /*
1262 * Commit and start the next trans in the chain.
1263 */
Niv Sardi322ff6b2008-08-13 16:05:49 +10001264 error = xfs_trans_roll(&args->trans, dp);
1265 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001266 goto out;
1267
1268 } else if (args->rmtblkno > 0) {
1269 /*
1270 * Added a "remote" value, just clear the incomplete flag.
1271 */
Dave Chinner517c2222013-04-24 18:58:55 +10001272 error = xfs_attr3_leaf_clearflag(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001273 if (error)
1274 goto out;
1275 }
1276 retval = error = 0;
1277
1278out:
1279 if (state)
1280 xfs_da_state_free(state);
1281 if (error)
1282 return(error);
1283 return(retval);
1284}
1285
1286/*
1287 * Remove a name from a B-tree attribute list.
1288 *
1289 * This will involve walking down the Btree, and may involve joining
1290 * leaf nodes and even joining intermediate nodes up to and including
1291 * the root node (a special case of an intermediate node).
1292 */
1293STATIC int
1294xfs_attr_node_removename(xfs_da_args_t *args)
1295{
1296 xfs_da_state_t *state;
1297 xfs_da_state_blk_t *blk;
1298 xfs_inode_t *dp;
Dave Chinner1d9025e2012-06-22 18:50:14 +10001299 struct xfs_buf *bp;
Nathan Scottd8cc8902005-11-02 10:34:53 +11001300 int retval, error, committed, forkoff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001301
Dave Chinner5a5881c2012-03-22 05:15:13 +00001302 trace_xfs_attr_node_removename(args);
1303
Linus Torvalds1da177e2005-04-16 15:20:36 -07001304 /*
1305 * Tie a string around our finger to remind us where we are.
1306 */
1307 dp = args->dp;
1308 state = xfs_da_state_alloc();
1309 state->args = args;
1310 state->mp = dp->i_mount;
1311 state->blocksize = state->mp->m_sb.sb_blocksize;
1312 state->node_ents = state->mp->m_attr_node_ents;
1313
1314 /*
1315 * Search to see if name exists, and get back a pointer to it.
1316 */
Dave Chinnerf5ea1102013-04-24 18:58:02 +10001317 error = xfs_da3_node_lookup_int(state, &retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001318 if (error || (retval != EEXIST)) {
1319 if (error == 0)
1320 error = retval;
1321 goto out;
1322 }
1323
1324 /*
1325 * If there is an out-of-line value, de-allocate the blocks.
1326 * This is done before we remove the attribute so that we don't
1327 * overflow the maximum size of a transaction and/or hit a deadlock.
1328 */
1329 blk = &state->path.blk[ state->path.active-1 ];
1330 ASSERT(blk->bp != NULL);
1331 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1332 if (args->rmtblkno > 0) {
1333 /*
1334 * Fill in disk block numbers in the state structure
1335 * so that we can get the buffers back after we commit
1336 * several transactions in the following calls.
1337 */
1338 error = xfs_attr_fillstate(state);
1339 if (error)
1340 goto out;
1341
1342 /*
1343 * Mark the attribute as INCOMPLETE, then bunmapi() the
1344 * remote value.
1345 */
Dave Chinner517c2222013-04-24 18:58:55 +10001346 error = xfs_attr3_leaf_setflag(args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 if (error)
1348 goto out;
1349 error = xfs_attr_rmtval_remove(args);
1350 if (error)
1351 goto out;
1352
1353 /*
1354 * Refill the state structure with buffers, the prior calls
1355 * released our buffers.
1356 */
1357 error = xfs_attr_refillstate(state);
1358 if (error)
1359 goto out;
1360 }
1361
1362 /*
1363 * Remove the name and update the hashvals in the tree.
1364 */
1365 blk = &state->path.blk[ state->path.active-1 ];
1366 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
Dave Chinner517c2222013-04-24 18:58:55 +10001367 retval = xfs_attr3_leaf_remove(blk->bp, args);
Dave Chinnerf5ea1102013-04-24 18:58:02 +10001368 xfs_da3_fixhashpath(state, &state->path);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001369
1370 /*
1371 * Check to see if the tree needs to be collapsed.
1372 */
1373 if (retval && (state->path.active > 1)) {
Eric Sandeen9d87c312009-01-14 23:22:07 -06001374 xfs_bmap_init(args->flist, args->firstblock);
Dave Chinnerf5ea1102013-04-24 18:58:02 +10001375 error = xfs_da3_join(state);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001376 if (!error) {
1377 error = xfs_bmap_finish(&args->trans, args->flist,
Eric Sandeenf7c99b62007-02-10 18:37:16 +11001378 &committed);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001379 }
1380 if (error) {
1381 ASSERT(committed);
1382 args->trans = NULL;
1383 xfs_bmap_cancel(args->flist);
1384 goto out;
1385 }
1386
1387 /*
1388 * bmap_finish() may have committed the last trans and started
1389 * a new one. We need the inode to be in all transactions.
1390 */
Christoph Hellwig898621d2010-06-24 11:36:58 +10001391 if (committed)
Christoph Hellwigddc34152011-09-19 15:00:54 +00001392 xfs_trans_ijoin(args->trans, dp, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001393
1394 /*
1395 * Commit the Btree join operation and start a new trans.
1396 */
Niv Sardi322ff6b2008-08-13 16:05:49 +10001397 error = xfs_trans_roll(&args->trans, dp);
1398 if (error)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001399 goto out;
1400 }
1401
1402 /*
1403 * If the result is small enough, push it all into the inode.
1404 */
1405 if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
1406 /*
1407 * Have to get rid of the copy of this dabuf in the state.
1408 */
1409 ASSERT(state->path.active == 1);
1410 ASSERT(state->path.blk[0].bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001411 state->path.blk[0].bp = NULL;
1412
Dave Chinner517c2222013-04-24 18:58:55 +10001413 error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001414 if (error)
1415 goto out;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001416
Nathan Scottd8cc8902005-11-02 10:34:53 +11001417 if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
Eric Sandeen9d87c312009-01-14 23:22:07 -06001418 xfs_bmap_init(args->flist, args->firstblock);
Dave Chinner517c2222013-04-24 18:58:55 +10001419 error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001420 /* bp is gone due to xfs_da_shrink_inode */
1421 if (!error) {
1422 error = xfs_bmap_finish(&args->trans,
1423 args->flist,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001424 &committed);
1425 }
1426 if (error) {
1427 ASSERT(committed);
1428 args->trans = NULL;
1429 xfs_bmap_cancel(args->flist);
1430 goto out;
1431 }
1432
1433 /*
1434 * bmap_finish() may have committed the last trans
1435 * and started a new one. We need the inode to be
1436 * in all transactions.
1437 */
Christoph Hellwig898621d2010-06-24 11:36:58 +10001438 if (committed)
Christoph Hellwigddc34152011-09-19 15:00:54 +00001439 xfs_trans_ijoin(args->trans, dp, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001440 } else
Dave Chinner1d9025e2012-06-22 18:50:14 +10001441 xfs_trans_brelse(args->trans, bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001442 }
1443 error = 0;
1444
1445out:
1446 xfs_da_state_free(state);
1447 return(error);
1448}
1449
1450/*
1451 * Fill in the disk block numbers in the state structure for the buffers
1452 * that are attached to the state structure.
1453 * This is done so that we can quickly reattach ourselves to those buffers
Nathan Scottc41564b2006-03-29 08:55:14 +10001454 * after some set of transaction commits have released these buffers.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001455 */
1456STATIC int
1457xfs_attr_fillstate(xfs_da_state_t *state)
1458{
1459 xfs_da_state_path_t *path;
1460 xfs_da_state_blk_t *blk;
1461 int level;
1462
Dave Chinneree732592012-11-12 22:53:53 +11001463 trace_xfs_attr_fillstate(state->args);
1464
Linus Torvalds1da177e2005-04-16 15:20:36 -07001465 /*
1466 * Roll down the "path" in the state structure, storing the on-disk
1467 * block number for those buffers in the "path".
1468 */
1469 path = &state->path;
1470 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1471 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1472 if (blk->bp) {
Dave Chinner1d9025e2012-06-22 18:50:14 +10001473 blk->disk_blkno = XFS_BUF_ADDR(blk->bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001474 blk->bp = NULL;
1475 } else {
1476 blk->disk_blkno = 0;
1477 }
1478 }
1479
1480 /*
1481 * Roll down the "altpath" in the state structure, storing the on-disk
1482 * block number for those buffers in the "altpath".
1483 */
1484 path = &state->altpath;
1485 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1486 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1487 if (blk->bp) {
Dave Chinner1d9025e2012-06-22 18:50:14 +10001488 blk->disk_blkno = XFS_BUF_ADDR(blk->bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001489 blk->bp = NULL;
1490 } else {
1491 blk->disk_blkno = 0;
1492 }
1493 }
1494
1495 return(0);
1496}
1497
1498/*
1499 * Reattach the buffers to the state structure based on the disk block
1500 * numbers stored in the state structure.
Nathan Scottc41564b2006-03-29 08:55:14 +10001501 * This is done after some set of transaction commits have released those
Linus Torvalds1da177e2005-04-16 15:20:36 -07001502 * buffers from our grip.
1503 */
1504STATIC int
1505xfs_attr_refillstate(xfs_da_state_t *state)
1506{
1507 xfs_da_state_path_t *path;
1508 xfs_da_state_blk_t *blk;
1509 int level, error;
1510
Dave Chinneree732592012-11-12 22:53:53 +11001511 trace_xfs_attr_refillstate(state->args);
1512
Linus Torvalds1da177e2005-04-16 15:20:36 -07001513 /*
1514 * Roll down the "path" in the state structure, storing the on-disk
1515 * block number for those buffers in the "path".
1516 */
1517 path = &state->path;
1518 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1519 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1520 if (blk->disk_blkno) {
Dave Chinnerf5ea1102013-04-24 18:58:02 +10001521 error = xfs_da3_node_read(state->args->trans,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001522 state->args->dp,
1523 blk->blkno, blk->disk_blkno,
Dave Chinnerd9392a42012-11-12 22:54:17 +11001524 &blk->bp, XFS_ATTR_FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001525 if (error)
1526 return(error);
1527 } else {
1528 blk->bp = NULL;
1529 }
1530 }
1531
1532 /*
1533 * Roll down the "altpath" in the state structure, storing the on-disk
1534 * block number for those buffers in the "altpath".
1535 */
1536 path = &state->altpath;
1537 ASSERT((path->active >= 0) && (path->active < XFS_DA_NODE_MAXDEPTH));
1538 for (blk = path->blk, level = 0; level < path->active; blk++, level++) {
1539 if (blk->disk_blkno) {
Dave Chinnerf5ea1102013-04-24 18:58:02 +10001540 error = xfs_da3_node_read(state->args->trans,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001541 state->args->dp,
1542 blk->blkno, blk->disk_blkno,
Dave Chinnerd9392a42012-11-12 22:54:17 +11001543 &blk->bp, XFS_ATTR_FORK);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001544 if (error)
1545 return(error);
1546 } else {
1547 blk->bp = NULL;
1548 }
1549 }
1550
1551 return(0);
1552}
1553
1554/*
1555 * Look up a filename in a node attribute list.
1556 *
1557 * This routine gets called for any attribute fork that has more than one
1558 * block, ie: both true Btree attr lists and for single-leaf-blocks with
1559 * "remote" values taking up more blocks.
1560 */
Christoph Hellwigba0f32d2005-06-21 15:36:52 +10001561STATIC int
Linus Torvalds1da177e2005-04-16 15:20:36 -07001562xfs_attr_node_get(xfs_da_args_t *args)
1563{
1564 xfs_da_state_t *state;
1565 xfs_da_state_blk_t *blk;
1566 int error, retval;
1567 int i;
1568
Dave Chinneree732592012-11-12 22:53:53 +11001569 trace_xfs_attr_node_get(args);
1570
Linus Torvalds1da177e2005-04-16 15:20:36 -07001571 state = xfs_da_state_alloc();
1572 state->args = args;
1573 state->mp = args->dp->i_mount;
1574 state->blocksize = state->mp->m_sb.sb_blocksize;
1575 state->node_ents = state->mp->m_attr_node_ents;
1576
1577 /*
1578 * Search to see if name exists, and get back a pointer to it.
1579 */
Dave Chinnerf5ea1102013-04-24 18:58:02 +10001580 error = xfs_da3_node_lookup_int(state, &retval);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001581 if (error) {
1582 retval = error;
1583 } else if (retval == EEXIST) {
1584 blk = &state->path.blk[ state->path.active-1 ];
1585 ASSERT(blk->bp != NULL);
1586 ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
1587
1588 /*
1589 * Get the value, local or "remote"
1590 */
Dave Chinner517c2222013-04-24 18:58:55 +10001591 retval = xfs_attr3_leaf_getvalue(blk->bp, args);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001592 if (!retval && (args->rmtblkno > 0)
1593 && !(args->flags & ATTR_KERNOVAL)) {
1594 retval = xfs_attr_rmtval_get(args);
1595 }
1596 }
1597
1598 /*
1599 * If not in a transaction, we have to release all the buffers.
1600 */
1601 for (i = 0; i < state->path.active; i++) {
Dave Chinner1d9025e2012-06-22 18:50:14 +10001602 xfs_trans_brelse(args->trans, state->path.blk[i].bp);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001603 state->path.blk[i].bp = NULL;
1604 }
1605
1606 xfs_da_state_free(state);
1607 return(retval);
1608}