xfs_attr_list.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606
  1. /*
  2. * Copyright (c) 2000-2005 Silicon Graphics, Inc.
  3. * Copyright (c) 2013 Red Hat, Inc.
  4. * All Rights Reserved.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License as
  8. * published by the Free Software Foundation.
  9. *
  10. * This program is distributed in the hope that it would be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write the Free Software Foundation,
  17. * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  18. */
  19. #include "xfs.h"
  20. #include "xfs_fs.h"
  21. #include "xfs_format.h"
  22. #include "xfs_log_format.h"
  23. #include "xfs_trans_resv.h"
  24. #include "xfs_bit.h"
  25. #include "xfs_mount.h"
  26. #include "xfs_da_format.h"
  27. #include "xfs_da_btree.h"
  28. #include "xfs_inode.h"
  29. #include "xfs_trans.h"
  30. #include "xfs_inode_item.h"
  31. #include "xfs_bmap.h"
  32. #include "xfs_attr.h"
  33. #include "xfs_attr_sf.h"
  34. #include "xfs_attr_remote.h"
  35. #include "xfs_attr_leaf.h"
  36. #include "xfs_error.h"
  37. #include "xfs_trace.h"
  38. #include "xfs_buf_item.h"
  39. #include "xfs_cksum.h"
  40. #include "xfs_dir2.h"
  41. STATIC int
  42. xfs_attr_shortform_compare(const void *a, const void *b)
  43. {
  44. xfs_attr_sf_sort_t *sa, *sb;
  45. sa = (xfs_attr_sf_sort_t *)a;
  46. sb = (xfs_attr_sf_sort_t *)b;
  47. if (sa->hash < sb->hash) {
  48. return -1;
  49. } else if (sa->hash > sb->hash) {
  50. return 1;
  51. } else {
  52. return sa->entno - sb->entno;
  53. }
  54. }
  55. #define XFS_ISRESET_CURSOR(cursor) \
  56. (!((cursor)->initted) && !((cursor)->hashval) && \
  57. !((cursor)->blkno) && !((cursor)->offset))
  58. /*
  59. * Copy out entries of shortform attribute lists for attr_list().
  60. * Shortform attribute lists are not stored in hashval sorted order.
  61. * If the output buffer is not large enough to hold them all, then we
  62. * we have to calculate each entries' hashvalue and sort them before
  63. * we can begin returning them to the user.
  64. */
  65. static int
  66. xfs_attr_shortform_list(xfs_attr_list_context_t *context)
  67. {
  68. attrlist_cursor_kern_t *cursor;
  69. xfs_attr_sf_sort_t *sbuf, *sbp;
  70. xfs_attr_shortform_t *sf;
  71. xfs_attr_sf_entry_t *sfe;
  72. xfs_inode_t *dp;
  73. int sbsize, nsbuf, count, i;
  74. ASSERT(context != NULL);
  75. dp = context->dp;
  76. ASSERT(dp != NULL);
  77. ASSERT(dp->i_afp != NULL);
  78. sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
  79. ASSERT(sf != NULL);
  80. if (!sf->hdr.count)
  81. return 0;
  82. cursor = context->cursor;
  83. ASSERT(cursor != NULL);
  84. trace_xfs_attr_list_sf(context);
  85. /*
  86. * If the buffer is large enough and the cursor is at the start,
  87. * do not bother with sorting since we will return everything in
  88. * one buffer and another call using the cursor won't need to be
  89. * made.
  90. * Note the generous fudge factor of 16 overhead bytes per entry.
  91. * If bufsize is zero then put_listent must be a search function
  92. * and can just scan through what we have.
  93. */
  94. if (context->bufsize == 0 ||
  95. (XFS_ISRESET_CURSOR(cursor) &&
  96. (dp->i_afp->if_bytes + sf->hdr.count * 16) < context->bufsize)) {
  97. for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
  98. context->put_listent(context,
  99. sfe->flags,
  100. sfe->nameval,
  101. (int)sfe->namelen,
  102. (int)sfe->valuelen);
  103. /*
  104. * Either search callback finished early or
  105. * didn't fit it all in the buffer after all.
  106. */
  107. if (context->seen_enough)
  108. break;
  109. sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
  110. }
  111. trace_xfs_attr_list_sf_all(context);
  112. return 0;
  113. }
  114. /* do no more for a search callback */
  115. if (context->bufsize == 0)
  116. return 0;
  117. /*
  118. * It didn't all fit, so we have to sort everything on hashval.
  119. */
  120. sbsize = sf->hdr.count * sizeof(*sbuf);
  121. sbp = sbuf = kmem_alloc(sbsize, KM_SLEEP | KM_NOFS);
  122. /*
  123. * Scan the attribute list for the rest of the entries, storing
  124. * the relevant info from only those that match into a buffer.
  125. */
  126. nsbuf = 0;
  127. for (i = 0, sfe = &sf->list[0]; i < sf->hdr.count; i++) {
  128. if (unlikely(
  129. ((char *)sfe < (char *)sf) ||
  130. ((char *)sfe >= ((char *)sf + dp->i_afp->if_bytes)))) {
  131. XFS_CORRUPTION_ERROR("xfs_attr_shortform_list",
  132. XFS_ERRLEVEL_LOW,
  133. context->dp->i_mount, sfe);
  134. kmem_free(sbuf);
  135. return -EFSCORRUPTED;
  136. }
  137. sbp->entno = i;
  138. sbp->hash = xfs_da_hashname(sfe->nameval, sfe->namelen);
  139. sbp->name = sfe->nameval;
  140. sbp->namelen = sfe->namelen;
  141. /* These are bytes, and both on-disk, don't endian-flip */
  142. sbp->valuelen = sfe->valuelen;
  143. sbp->flags = sfe->flags;
  144. sfe = XFS_ATTR_SF_NEXTENTRY(sfe);
  145. sbp++;
  146. nsbuf++;
  147. }
  148. /*
  149. * Sort the entries on hash then entno.
  150. */
  151. xfs_sort(sbuf, nsbuf, sizeof(*sbuf), xfs_attr_shortform_compare);
  152. /*
  153. * Re-find our place IN THE SORTED LIST.
  154. */
  155. count = 0;
  156. cursor->initted = 1;
  157. cursor->blkno = 0;
  158. for (sbp = sbuf, i = 0; i < nsbuf; i++, sbp++) {
  159. if (sbp->hash == cursor->hashval) {
  160. if (cursor->offset == count) {
  161. break;
  162. }
  163. count++;
  164. } else if (sbp->hash > cursor->hashval) {
  165. break;
  166. }
  167. }
  168. if (i == nsbuf) {
  169. kmem_free(sbuf);
  170. return 0;
  171. }
  172. /*
  173. * Loop putting entries into the user buffer.
  174. */
  175. for ( ; i < nsbuf; i++, sbp++) {
  176. if (cursor->hashval != sbp->hash) {
  177. cursor->hashval = sbp->hash;
  178. cursor->offset = 0;
  179. }
  180. context->put_listent(context,
  181. sbp->flags,
  182. sbp->name,
  183. sbp->namelen,
  184. sbp->valuelen);
  185. if (context->seen_enough)
  186. break;
  187. cursor->offset++;
  188. }
  189. kmem_free(sbuf);
  190. return 0;
  191. }
  192. STATIC int
  193. xfs_attr_node_list(xfs_attr_list_context_t *context)
  194. {
  195. attrlist_cursor_kern_t *cursor;
  196. xfs_attr_leafblock_t *leaf;
  197. xfs_da_intnode_t *node;
  198. struct xfs_attr3_icleaf_hdr leafhdr;
  199. struct xfs_da3_icnode_hdr nodehdr;
  200. struct xfs_da_node_entry *btree;
  201. int error, i;
  202. struct xfs_buf *bp;
  203. struct xfs_inode *dp = context->dp;
  204. struct xfs_mount *mp = dp->i_mount;
  205. trace_xfs_attr_node_list(context);
  206. cursor = context->cursor;
  207. cursor->initted = 1;
  208. /*
  209. * Do all sorts of validation on the passed-in cursor structure.
  210. * If anything is amiss, ignore the cursor and look up the hashval
  211. * starting from the btree root.
  212. */
  213. bp = NULL;
  214. if (cursor->blkno > 0) {
  215. error = xfs_da3_node_read(NULL, dp, cursor->blkno, -1,
  216. &bp, XFS_ATTR_FORK);
  217. if ((error != 0) && (error != -EFSCORRUPTED))
  218. return error;
  219. if (bp) {
  220. struct xfs_attr_leaf_entry *entries;
  221. node = bp->b_addr;
  222. switch (be16_to_cpu(node->hdr.info.magic)) {
  223. case XFS_DA_NODE_MAGIC:
  224. case XFS_DA3_NODE_MAGIC:
  225. trace_xfs_attr_list_wrong_blk(context);
  226. xfs_trans_brelse(NULL, bp);
  227. bp = NULL;
  228. break;
  229. case XFS_ATTR_LEAF_MAGIC:
  230. case XFS_ATTR3_LEAF_MAGIC:
  231. leaf = bp->b_addr;
  232. xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo,
  233. &leafhdr, leaf);
  234. entries = xfs_attr3_leaf_entryp(leaf);
  235. if (cursor->hashval > be32_to_cpu(
  236. entries[leafhdr.count - 1].hashval)) {
  237. trace_xfs_attr_list_wrong_blk(context);
  238. xfs_trans_brelse(NULL, bp);
  239. bp = NULL;
  240. } else if (cursor->hashval <= be32_to_cpu(
  241. entries[0].hashval)) {
  242. trace_xfs_attr_list_wrong_blk(context);
  243. xfs_trans_brelse(NULL, bp);
  244. bp = NULL;
  245. }
  246. break;
  247. default:
  248. trace_xfs_attr_list_wrong_blk(context);
  249. xfs_trans_brelse(NULL, bp);
  250. bp = NULL;
  251. }
  252. }
  253. }
  254. /*
  255. * We did not find what we expected given the cursor's contents,
  256. * so we start from the top and work down based on the hash value.
  257. * Note that start of node block is same as start of leaf block.
  258. */
  259. if (bp == NULL) {
  260. cursor->blkno = 0;
  261. for (;;) {
  262. __uint16_t magic;
  263. error = xfs_da3_node_read(NULL, dp,
  264. cursor->blkno, -1, &bp,
  265. XFS_ATTR_FORK);
  266. if (error)
  267. return error;
  268. node = bp->b_addr;
  269. magic = be16_to_cpu(node->hdr.info.magic);
  270. if (magic == XFS_ATTR_LEAF_MAGIC ||
  271. magic == XFS_ATTR3_LEAF_MAGIC)
  272. break;
  273. if (magic != XFS_DA_NODE_MAGIC &&
  274. magic != XFS_DA3_NODE_MAGIC) {
  275. XFS_CORRUPTION_ERROR("xfs_attr_node_list(3)",
  276. XFS_ERRLEVEL_LOW,
  277. context->dp->i_mount,
  278. node);
  279. xfs_trans_brelse(NULL, bp);
  280. return -EFSCORRUPTED;
  281. }
  282. dp->d_ops->node_hdr_from_disk(&nodehdr, node);
  283. btree = dp->d_ops->node_tree_p(node);
  284. for (i = 0; i < nodehdr.count; btree++, i++) {
  285. if (cursor->hashval
  286. <= be32_to_cpu(btree->hashval)) {
  287. cursor->blkno = be32_to_cpu(btree->before);
  288. trace_xfs_attr_list_node_descend(context,
  289. btree);
  290. break;
  291. }
  292. }
  293. if (i == nodehdr.count) {
  294. xfs_trans_brelse(NULL, bp);
  295. return 0;
  296. }
  297. xfs_trans_brelse(NULL, bp);
  298. }
  299. }
  300. ASSERT(bp != NULL);
  301. /*
  302. * Roll upward through the blocks, processing each leaf block in
  303. * order. As long as there is space in the result buffer, keep
  304. * adding the information.
  305. */
  306. for (;;) {
  307. leaf = bp->b_addr;
  308. xfs_attr3_leaf_list_int(bp, context);
  309. xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &leafhdr, leaf);
  310. if (context->seen_enough || leafhdr.forw == 0)
  311. break;
  312. cursor->blkno = leafhdr.forw;
  313. xfs_trans_brelse(NULL, bp);
  314. error = xfs_attr3_leaf_read(NULL, dp, cursor->blkno, -1, &bp);
  315. if (error)
  316. return error;
  317. }
  318. xfs_trans_brelse(NULL, bp);
  319. return 0;
  320. }
  321. /*
  322. * Copy out attribute list entries for attr_list(), for leaf attribute lists.
  323. */
  324. void
  325. xfs_attr3_leaf_list_int(
  326. struct xfs_buf *bp,
  327. struct xfs_attr_list_context *context)
  328. {
  329. struct attrlist_cursor_kern *cursor;
  330. struct xfs_attr_leafblock *leaf;
  331. struct xfs_attr3_icleaf_hdr ichdr;
  332. struct xfs_attr_leaf_entry *entries;
  333. struct xfs_attr_leaf_entry *entry;
  334. int i;
  335. struct xfs_mount *mp = context->dp->i_mount;
  336. trace_xfs_attr_list_leaf(context);
  337. leaf = bp->b_addr;
  338. xfs_attr3_leaf_hdr_from_disk(mp->m_attr_geo, &ichdr, leaf);
  339. entries = xfs_attr3_leaf_entryp(leaf);
  340. cursor = context->cursor;
  341. cursor->initted = 1;
  342. /*
  343. * Re-find our place in the leaf block if this is a new syscall.
  344. */
  345. if (context->resynch) {
  346. entry = &entries[0];
  347. for (i = 0; i < ichdr.count; entry++, i++) {
  348. if (be32_to_cpu(entry->hashval) == cursor->hashval) {
  349. if (cursor->offset == context->dupcnt) {
  350. context->dupcnt = 0;
  351. break;
  352. }
  353. context->dupcnt++;
  354. } else if (be32_to_cpu(entry->hashval) >
  355. cursor->hashval) {
  356. context->dupcnt = 0;
  357. break;
  358. }
  359. }
  360. if (i == ichdr.count) {
  361. trace_xfs_attr_list_notfound(context);
  362. return;
  363. }
  364. } else {
  365. entry = &entries[0];
  366. i = 0;
  367. }
  368. context->resynch = 0;
  369. /*
  370. * We have found our place, start copying out the new attributes.
  371. */
  372. for (; i < ichdr.count; entry++, i++) {
  373. char *name;
  374. int namelen, valuelen;
  375. if (be32_to_cpu(entry->hashval) != cursor->hashval) {
  376. cursor->hashval = be32_to_cpu(entry->hashval);
  377. cursor->offset = 0;
  378. }
  379. if (entry->flags & XFS_ATTR_INCOMPLETE)
  380. continue; /* skip incomplete entries */
  381. if (entry->flags & XFS_ATTR_LOCAL) {
  382. xfs_attr_leaf_name_local_t *name_loc;
  383. name_loc = xfs_attr3_leaf_name_local(leaf, i);
  384. name = name_loc->nameval;
  385. namelen = name_loc->namelen;
  386. valuelen = be16_to_cpu(name_loc->valuelen);
  387. } else {
  388. xfs_attr_leaf_name_remote_t *name_rmt;
  389. name_rmt = xfs_attr3_leaf_name_remote(leaf, i);
  390. name = name_rmt->name;
  391. namelen = name_rmt->namelen;
  392. valuelen = be32_to_cpu(name_rmt->valuelen);
  393. }
  394. context->put_listent(context, entry->flags,
  395. name, namelen, valuelen);
  396. if (context->seen_enough)
  397. break;
  398. cursor->offset++;
  399. }
  400. trace_xfs_attr_list_leaf_end(context);
  401. return;
  402. }
  403. /*
  404. * Copy out attribute entries for attr_list(), for leaf attribute lists.
  405. */
  406. STATIC int
  407. xfs_attr_leaf_list(xfs_attr_list_context_t *context)
  408. {
  409. int error;
  410. struct xfs_buf *bp;
  411. trace_xfs_attr_leaf_list(context);
  412. context->cursor->blkno = 0;
  413. error = xfs_attr3_leaf_read(NULL, context->dp, 0, -1, &bp);
  414. if (error)
  415. return error;
  416. xfs_attr3_leaf_list_int(bp, context);
  417. xfs_trans_brelse(NULL, bp);
  418. return 0;
  419. }
  420. int
  421. xfs_attr_list_int(
  422. xfs_attr_list_context_t *context)
  423. {
  424. int error;
  425. xfs_inode_t *dp = context->dp;
  426. uint lock_mode;
  427. XFS_STATS_INC(dp->i_mount, xs_attr_list);
  428. if (XFS_FORCED_SHUTDOWN(dp->i_mount))
  429. return -EIO;
  430. /*
  431. * Decide on what work routines to call based on the inode size.
  432. */
  433. lock_mode = xfs_ilock_attr_map_shared(dp);
  434. if (!xfs_inode_hasattr(dp)) {
  435. error = 0;
  436. } else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
  437. error = xfs_attr_shortform_list(context);
  438. } else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
  439. error = xfs_attr_leaf_list(context);
  440. } else {
  441. error = xfs_attr_node_list(context);
  442. }
  443. xfs_iunlock(dp, lock_mode);
  444. return error;
  445. }
  446. #define ATTR_ENTBASESIZE /* minimum bytes used by an attr */ \
  447. (((struct attrlist_ent *) 0)->a_name - (char *) 0)
  448. #define ATTR_ENTSIZE(namelen) /* actual bytes used by an attr */ \
  449. ((ATTR_ENTBASESIZE + (namelen) + 1 + sizeof(u_int32_t)-1) \
  450. & ~(sizeof(u_int32_t)-1))
  451. /*
  452. * Format an attribute and copy it out to the user's buffer.
  453. * Take care to check values and protect against them changing later,
  454. * we may be reading them directly out of a user buffer.
  455. */
  456. STATIC void
  457. xfs_attr_put_listent(
  458. xfs_attr_list_context_t *context,
  459. int flags,
  460. unsigned char *name,
  461. int namelen,
  462. int valuelen)
  463. {
  464. struct attrlist *alist = (struct attrlist *)context->alist;
  465. attrlist_ent_t *aep;
  466. int arraytop;
  467. ASSERT(!(context->flags & ATTR_KERNOVAL));
  468. ASSERT(context->count >= 0);
  469. ASSERT(context->count < (ATTR_MAX_VALUELEN/8));
  470. ASSERT(context->firstu >= sizeof(*alist));
  471. ASSERT(context->firstu <= context->bufsize);
  472. /*
  473. * Only list entries in the right namespace.
  474. */
  475. if (((context->flags & ATTR_SECURE) == 0) !=
  476. ((flags & XFS_ATTR_SECURE) == 0))
  477. return;
  478. if (((context->flags & ATTR_ROOT) == 0) !=
  479. ((flags & XFS_ATTR_ROOT) == 0))
  480. return;
  481. arraytop = sizeof(*alist) +
  482. context->count * sizeof(alist->al_offset[0]);
  483. context->firstu -= ATTR_ENTSIZE(namelen);
  484. if (context->firstu < arraytop) {
  485. trace_xfs_attr_list_full(context);
  486. alist->al_more = 1;
  487. context->seen_enough = 1;
  488. return;
  489. }
  490. aep = (attrlist_ent_t *)&context->alist[context->firstu];
  491. aep->a_valuelen = valuelen;
  492. memcpy(aep->a_name, name, namelen);
  493. aep->a_name[namelen] = 0;
  494. alist->al_offset[context->count++] = context->firstu;
  495. alist->al_count = context->count;
  496. trace_xfs_attr_list_add(context);
  497. return;
  498. }
  499. /*
  500. * Generate a list of extended attribute names and optionally
  501. * also value lengths. Positive return value follows the XFS
  502. * convention of being an error, zero or negative return code
  503. * is the length of the buffer returned (negated), indicating
  504. * success.
  505. */
  506. int
  507. xfs_attr_list(
  508. xfs_inode_t *dp,
  509. char *buffer,
  510. int bufsize,
  511. int flags,
  512. attrlist_cursor_kern_t *cursor)
  513. {
  514. xfs_attr_list_context_t context;
  515. struct attrlist *alist;
  516. int error;
  517. /*
  518. * Validate the cursor.
  519. */
  520. if (cursor->pad1 || cursor->pad2)
  521. return -EINVAL;
  522. if ((cursor->initted == 0) &&
  523. (cursor->hashval || cursor->blkno || cursor->offset))
  524. return -EINVAL;
  525. /*
  526. * Check for a properly aligned buffer.
  527. */
  528. if (((long)buffer) & (sizeof(int)-1))
  529. return -EFAULT;
  530. if (flags & ATTR_KERNOVAL)
  531. bufsize = 0;
  532. /*
  533. * Initialize the output buffer.
  534. */
  535. memset(&context, 0, sizeof(context));
  536. context.dp = dp;
  537. context.cursor = cursor;
  538. context.resynch = 1;
  539. context.flags = flags;
  540. context.alist = buffer;
  541. context.bufsize = (bufsize & ~(sizeof(int)-1)); /* align */
  542. context.firstu = context.bufsize;
  543. context.put_listent = xfs_attr_put_listent;
  544. alist = (struct attrlist *)context.alist;
  545. alist->al_count = 0;
  546. alist->al_more = 0;
  547. alist->al_offset[0] = context.bufsize;
  548. error = xfs_attr_list_int(&context);
  549. ASSERT(error <= 0);
  550. return error;
  551. }