Commit 52d8ea4f authored by Darrick J. Wong's avatar Darrick J. Wong

xfs: create shadow transaction reservations for computing minimum log size

Every time someone changes the transaction reservation sizes, they
introduce potential compatibility problems if the changes affect the
minimum log size that we validate at mount time.  If the minimum log
size gets larger (which should be avoided because doing so presents a
serious risk of log livelock), filesystems created with old mkfs will
not mount on a newer kernel; if the minimum size shrinks, filesystems
created with newer mkfs will not mount on older kernels.

Therefore, enable the creation of a shadow log reservation structure
where we can "undo" the effects of tweaks when computing minimum log
sizes.  These shadow reservations should never be used in practice, but
they insulate us from perturbations in minimum log size.
Signed-off-by: default avatarDarrick J. Wong <djwong@kernel.org>
Reviewed-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
parent f1e6a8d7
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "xfs_trans_space.h" #include "xfs_trans_space.h"
#include "xfs_da_btree.h" #include "xfs_da_btree.h"
#include "xfs_bmap_btree.h" #include "xfs_bmap_btree.h"
#include "xfs_trace.h"
/* /*
* Calculate the maximum length in bytes that would be required for a local * Calculate the maximum length in bytes that would be required for a local
...@@ -46,19 +47,25 @@ xfs_log_get_max_trans_res( ...@@ -46,19 +47,25 @@ xfs_log_get_max_trans_res(
struct xfs_mount *mp, struct xfs_mount *mp,
struct xfs_trans_res *max_resp) struct xfs_trans_res *max_resp)
{ {
struct xfs_trans_resv resv;
struct xfs_trans_res *resp; struct xfs_trans_res *resp;
struct xfs_trans_res *end_resp; struct xfs_trans_res *end_resp;
unsigned int i;
int log_space = 0; int log_space = 0;
int attr_space; int attr_space;
attr_space = xfs_log_calc_max_attrsetm_res(mp); attr_space = xfs_log_calc_max_attrsetm_res(mp);
resp = (struct xfs_trans_res *)M_RES(mp); memcpy(&resv, M_RES(mp), sizeof(struct xfs_trans_resv));
end_resp = (struct xfs_trans_res *)(M_RES(mp) + 1);
for (; resp < end_resp; resp++) { resp = (struct xfs_trans_res *)&resv;
end_resp = (struct xfs_trans_res *)(&resv + 1);
for (i = 0; resp < end_resp; i++, resp++) {
int tmp = resp->tr_logcount > 1 ? int tmp = resp->tr_logcount > 1 ?
resp->tr_logres * resp->tr_logcount : resp->tr_logres * resp->tr_logcount :
resp->tr_logres; resp->tr_logres;
trace_xfs_trans_resv_calc_minlogsize(mp, i, resp);
if (log_space < tmp) { if (log_space < tmp) {
log_space = tmp; log_space = tmp;
*max_resp = *resp; /* struct copy */ *max_resp = *resp; /* struct copy */
...@@ -66,7 +73,7 @@ xfs_log_get_max_trans_res( ...@@ -66,7 +73,7 @@ xfs_log_get_max_trans_res(
} }
if (attr_space > log_space) { if (attr_space > log_space) {
*max_resp = M_RES(mp)->tr_attrsetm; /* struct copy */ *max_resp = resv.tr_attrsetm; /* struct copy */
max_resp->tr_logres = attr_space; max_resp->tr_logres = attr_space;
} }
} }
......
...@@ -3500,7 +3500,7 @@ DEFINE_GETFSMAP_EVENT(xfs_getfsmap_low_key); ...@@ -3500,7 +3500,7 @@ DEFINE_GETFSMAP_EVENT(xfs_getfsmap_low_key);
DEFINE_GETFSMAP_EVENT(xfs_getfsmap_high_key); DEFINE_GETFSMAP_EVENT(xfs_getfsmap_high_key);
DEFINE_GETFSMAP_EVENT(xfs_getfsmap_mapping); DEFINE_GETFSMAP_EVENT(xfs_getfsmap_mapping);
TRACE_EVENT(xfs_trans_resv_calc, DECLARE_EVENT_CLASS(xfs_trans_resv_class,
TP_PROTO(struct xfs_mount *mp, unsigned int type, TP_PROTO(struct xfs_mount *mp, unsigned int type,
struct xfs_trans_res *res), struct xfs_trans_res *res),
TP_ARGS(mp, type, res), TP_ARGS(mp, type, res),
...@@ -3524,7 +3524,15 @@ TRACE_EVENT(xfs_trans_resv_calc, ...@@ -3524,7 +3524,15 @@ TRACE_EVENT(xfs_trans_resv_calc,
__entry->logres, __entry->logres,
__entry->logcount, __entry->logcount,
__entry->logflags) __entry->logflags)
); )
#define DEFINE_TRANS_RESV_EVENT(name) \
DEFINE_EVENT(xfs_trans_resv_class, name, \
TP_PROTO(struct xfs_mount *mp, unsigned int type, \
struct xfs_trans_res *res), \
TP_ARGS(mp, type, res))
DEFINE_TRANS_RESV_EVENT(xfs_trans_resv_calc);
DEFINE_TRANS_RESV_EVENT(xfs_trans_resv_calc_minlogsize);
DECLARE_EVENT_CLASS(xfs_trans_class, DECLARE_EVENT_CLASS(xfs_trans_class,
TP_PROTO(struct xfs_trans *tp, unsigned long caller_ip), TP_PROTO(struct xfs_trans *tp, unsigned long caller_ip),
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment