xfs_trans_item.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553
  1. /*
  2. * Copyright (c) 2000-2002 Silicon Graphics, Inc. All Rights Reserved.
  3. *
  4. * This program is free software; you can redistribute it and/or modify it
  5. * under the terms of version 2 of the GNU General Public License as
  6. * published by the Free Software Foundation.
  7. *
  8. * This program is distributed in the hope that it would be useful, but
  9. * WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. *
  12. * Further, this software is distributed without any warranty that it is
  13. * free of the rightful claim of any third person regarding infringement
  14. * or the like. Any license provided herein, whether implied or
  15. * otherwise, applies only to this software file. Patent licenses, if
  16. * any, provided herein do not apply to combinations of this program with
  17. * other software, or any other product whatsoever.
  18. *
  19. * You should have received a copy of the GNU General Public License along
  20. * with this program; if not, write the Free Software Foundation, Inc., 59
  21. * Temple Place - Suite 330, Boston MA 02111-1307, USA.
  22. *
  23. * Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
  24. * Mountain View, CA 94043, or:
  25. *
  26. * http://www.sgi.com
  27. *
  28. * For further information regarding this notice, see:
  29. *
  30. * http://oss.sgi.com/projects/GenInfo/SGIGPLNoticeExplan/
  31. */
  32. #include "xfs.h"
  33. #include "xfs_macros.h"
  34. #include "xfs_types.h"
  35. #include "xfs_inum.h"
  36. #include "xfs_log.h"
  37. #include "xfs_trans.h"
  38. STATIC int xfs_trans_unlock_chunk(xfs_log_item_chunk_t *,
  39. int, int, xfs_lsn_t);
  40. /*
  41. * This is called to add the given log item to the transaction's
  42. * list of log items. It must find a free log item descriptor
  43. * or allocate a new one and add the item to that descriptor.
  44. * The function returns a pointer to item descriptor used to point
  45. * to the new item. The log item will now point to its new descriptor
  46. * with its li_desc field.
  47. */
  48. xfs_log_item_desc_t *
  49. xfs_trans_add_item(xfs_trans_t *tp, xfs_log_item_t *lip)
  50. {
  51. xfs_log_item_desc_t *lidp;
  52. xfs_log_item_chunk_t *licp;
  53. int i=0;
  54. /*
  55. * If there are no free descriptors, allocate a new chunk
  56. * of them and put it at the front of the chunk list.
  57. */
  58. if (tp->t_items_free == 0) {
  59. licp = (xfs_log_item_chunk_t*)
  60. kmem_alloc(sizeof(xfs_log_item_chunk_t), KM_SLEEP);
  61. ASSERT(licp != NULL);
  62. /*
  63. * Initialize the chunk, and then
  64. * claim the first slot in the newly allocated chunk.
  65. */
  66. XFS_LIC_INIT(licp);
  67. XFS_LIC_CLAIM(licp, 0);
  68. licp->lic_unused = 1;
  69. XFS_LIC_INIT_SLOT(licp, 0);
  70. lidp = XFS_LIC_SLOT(licp, 0);
  71. /*
  72. * Link in the new chunk and update the free count.
  73. */
  74. licp->lic_next = tp->t_items.lic_next;
  75. tp->t_items.lic_next = licp;
  76. tp->t_items_free = XFS_LIC_NUM_SLOTS - 1;
  77. /*
  78. * Initialize the descriptor and the generic portion
  79. * of the log item.
  80. *
  81. * Point the new slot at this item and return it.
  82. * Also point the log item at its currently active
  83. * descriptor and set the item's mount pointer.
  84. */
  85. lidp->lid_item = lip;
  86. lidp->lid_flags = 0;
  87. lidp->lid_size = 0;
  88. lip->li_desc = lidp;
  89. lip->li_mountp = tp->t_mountp;
  90. return (lidp);
  91. }
  92. /*
  93. * Find the free descriptor. It is somewhere in the chunklist
  94. * of descriptors.
  95. */
  96. licp = &tp->t_items;
  97. while (licp != NULL) {
  98. if (XFS_LIC_VACANCY(licp)) {
  99. if (licp->lic_unused <= XFS_LIC_MAX_SLOT) {
  100. i = licp->lic_unused;
  101. ASSERT(XFS_LIC_ISFREE(licp, i));
  102. break;
  103. }
  104. for (i = 0; i <= XFS_LIC_MAX_SLOT; i++) {
  105. if (XFS_LIC_ISFREE(licp, i))
  106. break;
  107. }
  108. ASSERT(i <= XFS_LIC_MAX_SLOT);
  109. break;
  110. }
  111. licp = licp->lic_next;
  112. }
  113. ASSERT(licp != NULL);
  114. /*
  115. * If we find a free descriptor, claim it,
  116. * initialize it, and return it.
  117. */
  118. XFS_LIC_CLAIM(licp, i);
  119. if (licp->lic_unused <= i) {
  120. licp->lic_unused = i + 1;
  121. XFS_LIC_INIT_SLOT(licp, i);
  122. }
  123. lidp = XFS_LIC_SLOT(licp, i);
  124. tp->t_items_free--;
  125. lidp->lid_item = lip;
  126. lidp->lid_flags = 0;
  127. lidp->lid_size = 0;
  128. lip->li_desc = lidp;
  129. lip->li_mountp = tp->t_mountp;
  130. return (lidp);
  131. }
  132. /*
  133. * Free the given descriptor.
  134. *
  135. * This requires setting the bit in the chunk's free mask corresponding
  136. * to the given slot.
  137. */
  138. void
  139. xfs_trans_free_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp)
  140. {
  141. uint slot;
  142. xfs_log_item_chunk_t *licp;
  143. xfs_log_item_chunk_t **licpp;
  144. slot = XFS_LIC_DESC_TO_SLOT(lidp);
  145. licp = XFS_LIC_DESC_TO_CHUNK(lidp);
  146. XFS_LIC_RELSE(licp, slot);
  147. lidp->lid_item->li_desc = NULL;
  148. tp->t_items_free++;
  149. /*
  150. * If there are no more used items in the chunk and this is not
  151. * the chunk embedded in the transaction structure, then free
  152. * the chunk. First pull it from the chunk list and then
  153. * free it back to the heap. We didn't bother with a doubly
  154. * linked list here because the lists should be very short
  155. * and this is not a performance path. It's better to save
  156. * the memory of the extra pointer.
  157. *
  158. * Also decrement the transaction structure's count of free items
  159. * by the number in a chunk since we are freeing an empty chunk.
  160. */
  161. if (XFS_LIC_ARE_ALL_FREE(licp) && (licp != &(tp->t_items))) {
  162. licpp = &(tp->t_items.lic_next);
  163. while (*licpp != licp) {
  164. ASSERT(*licpp != NULL);
  165. licpp = &((*licpp)->lic_next);
  166. }
  167. *licpp = licp->lic_next;
  168. kmem_free(licp, sizeof(xfs_log_item_chunk_t));
  169. tp->t_items_free -= XFS_LIC_NUM_SLOTS;
  170. }
  171. }
  172. /*
  173. * This is called to find the descriptor corresponding to the given
  174. * log item. It returns a pointer to the descriptor.
  175. * The log item MUST have a corresponding descriptor in the given
  176. * transaction. This routine does not return NULL, it panics.
  177. *
  178. * The descriptor pointer is kept in the log item's li_desc field.
  179. * Just return it.
  180. */
  181. /*ARGSUSED*/
  182. xfs_log_item_desc_t *
  183. xfs_trans_find_item(xfs_trans_t *tp, xfs_log_item_t *lip)
  184. {
  185. ASSERT(lip->li_desc != NULL);
  186. return (lip->li_desc);
  187. }
  188. /*
  189. * Return a pointer to the first descriptor in the chunk list.
  190. * This does not return NULL if there are none, it panics.
  191. *
  192. * The first descriptor must be in either the first or second chunk.
  193. * This is because the only chunk allowed to be empty is the first.
  194. * All others are freed when they become empty.
  195. *
  196. * At some point this and xfs_trans_next_item() should be optimized
  197. * to quickly look at the mask to determine if there is anything to
  198. * look at.
  199. */
  200. xfs_log_item_desc_t *
  201. xfs_trans_first_item(xfs_trans_t *tp)
  202. {
  203. xfs_log_item_chunk_t *licp;
  204. int i;
  205. licp = &tp->t_items;
  206. /*
  207. * If it's not in the first chunk, skip to the second.
  208. */
  209. if (XFS_LIC_ARE_ALL_FREE(licp)) {
  210. licp = licp->lic_next;
  211. }
  212. /*
  213. * Return the first non-free descriptor in the chunk.
  214. */
  215. ASSERT(!XFS_LIC_ARE_ALL_FREE(licp));
  216. for (i = 0; i < licp->lic_unused; i++) {
  217. if (XFS_LIC_ISFREE(licp, i)) {
  218. continue;
  219. }
  220. return (XFS_LIC_SLOT(licp, i));
  221. }
  222. cmn_err(CE_WARN, "xfs_trans_first_item() -- no first item");
  223. return(NULL);
  224. }
  225. /*
  226. * Given a descriptor, return the next descriptor in the chunk list.
  227. * This returns NULL if there are no more used descriptors in the list.
  228. *
  229. * We do this by first locating the chunk in which the descriptor resides,
  230. * and then scanning forward in the chunk and the list for the next
  231. * used descriptor.
  232. */
  233. /*ARGSUSED*/
  234. xfs_log_item_desc_t *
  235. xfs_trans_next_item(xfs_trans_t *tp, xfs_log_item_desc_t *lidp)
  236. {
  237. xfs_log_item_chunk_t *licp;
  238. int i;
  239. licp = XFS_LIC_DESC_TO_CHUNK(lidp);
  240. /*
  241. * First search the rest of the chunk. The for loop keeps us
  242. * from referencing things beyond the end of the chunk.
  243. */
  244. for (i = (int)XFS_LIC_DESC_TO_SLOT(lidp) + 1; i < licp->lic_unused; i++) {
  245. if (XFS_LIC_ISFREE(licp, i)) {
  246. continue;
  247. }
  248. return (XFS_LIC_SLOT(licp, i));
  249. }
  250. /*
  251. * Now search the next chunk. It must be there, because the
  252. * next chunk would have been freed if it were empty.
  253. * If there is no next chunk, return NULL.
  254. */
  255. if (licp->lic_next == NULL) {
  256. return (NULL);
  257. }
  258. licp = licp->lic_next;
  259. ASSERT(!XFS_LIC_ARE_ALL_FREE(licp));
  260. for (i = 0; i < licp->lic_unused; i++) {
  261. if (XFS_LIC_ISFREE(licp, i)) {
  262. continue;
  263. }
  264. return (XFS_LIC_SLOT(licp, i));
  265. }
  266. ASSERT(0);
  267. /* NOTREACHED */
  268. return NULL; /* keep gcc quite */
  269. }
  270. /*
  271. * This is called to unlock all of the items of a transaction and to free
  272. * all the descriptors of that transaction.
  273. *
  274. * It walks the list of descriptors and unlocks each item. It frees
  275. * each chunk except that embedded in the transaction as it goes along.
  276. */
  277. void
  278. xfs_trans_free_items(
  279. xfs_trans_t *tp,
  280. int flags)
  281. {
  282. xfs_log_item_chunk_t *licp;
  283. xfs_log_item_chunk_t *next_licp;
  284. int abort;
  285. abort = flags & XFS_TRANS_ABORT;
  286. licp = &tp->t_items;
  287. /*
  288. * Special case the embedded chunk so we don't free it below.
  289. */
  290. if (!XFS_LIC_ARE_ALL_FREE(licp)) {
  291. (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN);
  292. XFS_LIC_ALL_FREE(licp);
  293. licp->lic_unused = 0;
  294. }
  295. licp = licp->lic_next;
  296. /*
  297. * Unlock each item in each chunk and free the chunks.
  298. */
  299. while (licp != NULL) {
  300. ASSERT(!XFS_LIC_ARE_ALL_FREE(licp));
  301. (void) xfs_trans_unlock_chunk(licp, 1, abort, NULLCOMMITLSN);
  302. next_licp = licp->lic_next;
  303. kmem_free(licp, sizeof(xfs_log_item_chunk_t));
  304. licp = next_licp;
  305. }
  306. /*
  307. * Reset the transaction structure's free item count.
  308. */
  309. tp->t_items_free = XFS_LIC_NUM_SLOTS;
  310. tp->t_items.lic_next = NULL;
  311. }
  312. /*
  313. * This is called to unlock the items associated with a transaction.
  314. * Items which were not logged should be freed.
  315. * Those which were logged must still be tracked so they can be unpinned
  316. * when the transaction commits.
  317. */
  318. void
  319. xfs_trans_unlock_items(xfs_trans_t *tp, xfs_lsn_t commit_lsn)
  320. {
  321. xfs_log_item_chunk_t *licp;
  322. xfs_log_item_chunk_t *next_licp;
  323. xfs_log_item_chunk_t **licpp;
  324. int freed;
  325. freed = 0;
  326. licp = &tp->t_items;
  327. /*
  328. * Special case the embedded chunk so we don't free.
  329. */
  330. if (!XFS_LIC_ARE_ALL_FREE(licp)) {
  331. freed = xfs_trans_unlock_chunk(licp, 0, 0, commit_lsn);
  332. }
  333. licpp = &(tp->t_items.lic_next);
  334. licp = licp->lic_next;
  335. /*
  336. * Unlock each item in each chunk, free non-dirty descriptors,
  337. * and free empty chunks.
  338. */
  339. while (licp != NULL) {
  340. ASSERT(!XFS_LIC_ARE_ALL_FREE(licp));
  341. freed += xfs_trans_unlock_chunk(licp, 0, 0, commit_lsn);
  342. next_licp = licp->lic_next;
  343. if (XFS_LIC_ARE_ALL_FREE(licp)) {
  344. *licpp = next_licp;
  345. kmem_free(licp, sizeof(xfs_log_item_chunk_t));
  346. freed -= XFS_LIC_NUM_SLOTS;
  347. } else {
  348. licpp = &(licp->lic_next);
  349. }
  350. ASSERT(*licpp == next_licp);
  351. licp = next_licp;
  352. }
  353. /*
  354. * Fix the free descriptor count in the transaction.
  355. */
  356. tp->t_items_free += freed;
  357. }
  358. /*
  359. * Unlock each item pointed to by a descriptor in the given chunk.
  360. * Stamp the commit lsn into each item if necessary.
  361. * Free descriptors pointing to items which are not dirty if freeing_chunk
  362. * is zero. If freeing_chunk is non-zero, then we need to unlock all
  363. * items in the chunk.
  364. *
  365. * Return the number of descriptors freed.
  366. */
  367. STATIC int
  368. xfs_trans_unlock_chunk(
  369. xfs_log_item_chunk_t *licp,
  370. int freeing_chunk,
  371. int abort,
  372. xfs_lsn_t commit_lsn)
  373. {
  374. xfs_log_item_desc_t *lidp;
  375. xfs_log_item_t *lip;
  376. int i;
  377. int freed;
  378. freed = 0;
  379. lidp = licp->lic_descs;
  380. for (i = 0; i < licp->lic_unused; i++, lidp++) {
  381. if (XFS_LIC_ISFREE(licp, i)) {
  382. continue;
  383. }
  384. lip = lidp->lid_item;
  385. lip->li_desc = NULL;
  386. if (commit_lsn != NULLCOMMITLSN)
  387. IOP_COMMITTING(lip, commit_lsn);
  388. if (abort)
  389. lip->li_flags |= XFS_LI_ABORTED;
  390. IOP_UNLOCK(lip);
  391. /*
  392. * Free the descriptor if the item is not dirty
  393. * within this transaction and the caller is not
  394. * going to just free the entire thing regardless.
  395. */
  396. if (!(freeing_chunk) &&
  397. (!(lidp->lid_flags & XFS_LID_DIRTY) || abort)) {
  398. XFS_LIC_RELSE(licp, i);
  399. freed++;
  400. }
  401. }
  402. return (freed);
  403. }
  404. /*
  405. * This is called to add the given busy item to the transaction's
  406. * list of busy items. It must find a free busy item descriptor
  407. * or allocate a new one and add the item to that descriptor.
  408. * The function returns a pointer to busy descriptor used to point
  409. * to the new busy entry. The log busy entry will now point to its new
  410. * descriptor with its ???? field.
  411. */
  412. xfs_log_busy_slot_t *
  413. xfs_trans_add_busy(xfs_trans_t *tp, xfs_agnumber_t ag, xfs_extlen_t idx)
  414. {
  415. xfs_log_busy_chunk_t *lbcp;
  416. xfs_log_busy_slot_t *lbsp;
  417. int i=0;
  418. /*
  419. * If there are no free descriptors, allocate a new chunk
  420. * of them and put it at the front of the chunk list.
  421. */
  422. if (tp->t_busy_free == 0) {
  423. lbcp = (xfs_log_busy_chunk_t*)
  424. kmem_alloc(sizeof(xfs_log_busy_chunk_t), KM_SLEEP);
  425. ASSERT(lbcp != NULL);
  426. /*
  427. * Initialize the chunk, and then
  428. * claim the first slot in the newly allocated chunk.
  429. */
  430. XFS_LBC_INIT(lbcp);
  431. XFS_LBC_CLAIM(lbcp, 0);
  432. lbcp->lbc_unused = 1;
  433. lbsp = XFS_LBC_SLOT(lbcp, 0);
  434. /*
  435. * Link in the new chunk and update the free count.
  436. */
  437. lbcp->lbc_next = tp->t_busy.lbc_next;
  438. tp->t_busy.lbc_next = lbcp;
  439. tp->t_busy_free = XFS_LIC_NUM_SLOTS - 1;
  440. /*
  441. * Initialize the descriptor and the generic portion
  442. * of the log item.
  443. *
  444. * Point the new slot at this item and return it.
  445. * Also point the log item at its currently active
  446. * descriptor and set the item's mount pointer.
  447. */
  448. lbsp->lbc_ag = ag;
  449. lbsp->lbc_idx = idx;
  450. return (lbsp);
  451. }
  452. /*
  453. * Find the free descriptor. It is somewhere in the chunklist
  454. * of descriptors.
  455. */
  456. lbcp = &tp->t_busy;
  457. while (lbcp != NULL) {
  458. if (XFS_LBC_VACANCY(lbcp)) {
  459. if (lbcp->lbc_unused <= XFS_LBC_MAX_SLOT) {
  460. i = lbcp->lbc_unused;
  461. break;
  462. } else {
  463. /* out-of-order vacancy */
  464. printk("OOO vacancy lbcp 0x%p\n", lbcp);
  465. ASSERT(0);
  466. }
  467. }
  468. lbcp = lbcp->lbc_next;
  469. }
  470. ASSERT(lbcp != NULL);
  471. /*
  472. * If we find a free descriptor, claim it,
  473. * initialize it, and return it.
  474. */
  475. XFS_LBC_CLAIM(lbcp, i);
  476. if (lbcp->lbc_unused <= i) {
  477. lbcp->lbc_unused = i + 1;
  478. }
  479. lbsp = XFS_LBC_SLOT(lbcp, i);
  480. tp->t_busy_free--;
  481. lbsp->lbc_ag = ag;
  482. lbsp->lbc_idx = idx;
  483. return (lbsp);
  484. }
  485. /*
  486. * xfs_trans_free_busy
  487. * Free all of the busy lists from a transaction
  488. */
  489. void
  490. xfs_trans_free_busy(xfs_trans_t *tp)
  491. {
  492. xfs_log_busy_chunk_t *lbcp;
  493. xfs_log_busy_chunk_t *lbcq;
  494. lbcp = tp->t_busy.lbc_next;
  495. while (lbcp != NULL) {
  496. lbcq = lbcp->lbc_next;
  497. kmem_free(lbcp, sizeof(xfs_log_busy_chunk_t));
  498. lbcp = lbcq;
  499. }
  500. XFS_LBC_INIT(&tp->t_busy);
  501. tp->t_busy.lbc_unused = 0;
  502. }