1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright (c) 2013 Jie Liu. 4 * All Rights Reserved. 5 */ 6 #include "xfs.h" 7 #include "xfs_fs.h" 8 #include "xfs_shared.h" 9 #include "xfs_format.h" 10 #include "xfs_log_format.h" 11 #include "xfs_trans_resv.h" 12 #include "xfs_mount.h" 13 #include "xfs_da_format.h" 14 #include "xfs_trans_space.h" 15 #include "xfs_da_btree.h" 16 #include "xfs_bmap_btree.h" 17 18 /* 19 * Calculate the maximum length in bytes that would be required for a local 20 * attribute value as large attributes out of line are not logged. 21 */ 22 STATIC int 23 xfs_log_calc_max_attrsetm_res( 24 struct xfs_mount *mp) 25 { 26 int size; 27 int nblks; 28 29 size = xfs_attr_leaf_entsize_local_max(mp->m_attr_geo->blksize) - 30 MAXNAMELEN - 1; 31 nblks = XFS_DAENTER_SPACE_RES(mp, XFS_ATTR_FORK); 32 nblks += XFS_B_TO_FSB(mp, size); 33 nblks += XFS_NEXTENTADD_SPACE_RES(mp, size, XFS_ATTR_FORK); 34 35 return M_RES(mp)->tr_attrsetm.tr_logres + 36 M_RES(mp)->tr_attrsetrt.tr_logres * nblks; 37 } 38 39 /* 40 * Iterate over the log space reservation table to figure out and return 41 * the maximum one in terms of the pre-calculated values which were done 42 * at mount time. 43 */ 44 void 45 xfs_log_get_max_trans_res( 46 struct xfs_mount *mp, 47 struct xfs_trans_res *max_resp) 48 { 49 struct xfs_trans_res *resp; 50 struct xfs_trans_res *end_resp; 51 int log_space = 0; 52 int attr_space; 53 54 attr_space = xfs_log_calc_max_attrsetm_res(mp); 55 56 resp = (struct xfs_trans_res *)M_RES(mp); 57 end_resp = (struct xfs_trans_res *)(M_RES(mp) + 1); 58 for (; resp < end_resp; resp++) { 59 int tmp = resp->tr_logcount > 1 ? 60 resp->tr_logres * resp->tr_logcount : 61 resp->tr_logres; 62 if (log_space < tmp) { 63 log_space = tmp; 64 *max_resp = *resp; /* struct copy */ 65 } 66 } 67 68 if (attr_space > log_space) { 69 *max_resp = M_RES(mp)->tr_attrsetm; /* struct copy */ 70 max_resp->tr_logres = attr_space; 71 } 72 } 73 74 /* 75 * Calculate the minimum valid log size for the given superblock configuration. 76 * Used to calculate the minimum log size at mkfs time, and to determine if 77 * the log is large enough or not at mount time. Returns the minimum size in 78 * filesystem block size units. 79 */ 80 int 81 xfs_log_calc_minimum_size( 82 struct xfs_mount *mp) 83 { 84 struct xfs_trans_res tres = {0}; 85 int max_logres; 86 int min_logblks = 0; 87 int lsunit = 0; 88 89 xfs_log_get_max_trans_res(mp, &tres); 90 91 max_logres = xfs_log_calc_unit_res(mp, tres.tr_logres); 92 if (tres.tr_logcount > 1) 93 max_logres *= tres.tr_logcount; 94 95 if (xfs_sb_version_haslogv2(&mp->m_sb) && mp->m_sb.sb_logsunit > 1) 96 lsunit = BTOBB(mp->m_sb.sb_logsunit); 97 98 /* 99 * Two factors should be taken into account for calculating the minimum 100 * log space. 101 * 1) The fundamental limitation is that no single transaction can be 102 * larger than half size of the log. 103 * 104 * From mkfs.xfs, this is considered by the XFS_MIN_LOG_FACTOR 105 * define, which is set to 3. That means we can definitely fit 106 * maximally sized 2 transactions in the log. We'll use this same 107 * value here. 108 * 109 * 2) If the lsunit option is specified, a transaction requires 2 LSU 110 * for the reservation because there are two log writes that can 111 * require padding - the transaction data and the commit record which 112 * are written separately and both can require padding to the LSU. 113 * Consider that we can have an active CIL reservation holding 2*LSU, 114 * but the CIL is not over a push threshold, in this case, if we 115 * don't have enough log space for at one new transaction, which 116 * includes another 2*LSU in the reservation, we will run into dead 117 * loop situation in log space grant procedure. i.e. 118 * xlog_grant_head_wait(). 119 * 120 * Hence the log size needs to be able to contain two maximally sized 121 * and padded transactions, which is (2 * (2 * LSU + maxlres)). 122 * 123 * Also, the log size should be a multiple of the log stripe unit, round 124 * it up to lsunit boundary if lsunit is specified. 125 */ 126 if (lsunit) { 127 min_logblks = roundup_64(BTOBB(max_logres), lsunit) + 128 2 * lsunit; 129 } else 130 min_logblks = BTOBB(max_logres) + 2 * BBSIZE; 131 min_logblks *= XFS_MIN_LOG_FACTOR; 132 133 return XFS_BB_TO_FSB(mp, min_logblks); 134 } 135