# This file is used by configure to get version information
#
PKG_MAJOR=2
-PKG_MINOR=0
-PKG_REVISION=6
+PKG_MINOR=1
+PKG_REVISION=0
PKG_BUILD=0
{ "unit", FLDT_UINT32D, OI(OFF(unit)), C1, 0, TYP_NONE },
{ "width", FLDT_UINT32D, OI(OFF(width)), C1, 0, TYP_NONE },
{ "dirblklog", FLDT_UINT8D, OI(OFF(dirblklog)), C1, 0, TYP_NONE },
+ { "logsunit", FLDT_UINT32D, OI(OFF(logsunit)), C1, 0, TYP_NONE },
{ NULL }
};
XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
&uu,
- XLOG_FMT)) {
+ XFS_SB_VERSION_HASLOGV2(&mp->m_sb) ? 2 : 1,
+ mp->m_sb.sb_logsunit, XLOG_FMT)) {
dbprintf("error clearing log\n");
return 0;
}
-[cvs]
+xfsprogs-2.1.0 (14 Jun 2002)
+ - support for xfs version 2 log format.
- Fix for xfs_repair mangling i8count for dir2_sf directories
- Minor mkfs.xfs man page update for blocksize limits on Linux
extern void libxfs_device_close (dev_t);
/* check or write log footer: specify device, log size in blocks & uuid */
-extern int libxfs_log_clear (dev_t, xfs_daddr_t, uint, uuid_t *, int);
+extern int libxfs_log_clear (dev_t, xfs_daddr_t, uint, uuid_t *,
+ int, int, int);
/*
* Define a user-level mount structure with all we need
__uint64_t m_maxicount; /* maximum inode count */
int m_dalign; /* stripe unit */
int m_swidth; /* stripe width */
+ int m_lstripemask; /* log stripe mask */
int m_sinoalign; /* stripe unit inode alignmnt */
int m_dir_magicpct; /* 37% of the dir blocksize */
__uint8_t m_dirversion; /* 1 or 2 */
__s32 l_pad[4]; /* reserve area */
} xfs_flock64_t;
+/*
+ * Output for XFS_IOC_FSGEOMETRY_V1
+ */
+typedef struct xfs_fsop_geom_v1 {
+ __u32 blocksize; /* filesystem (data) block size */
+ __u32 rtextsize; /* realtime extent size */
+ __u32 agblocks; /* fsblocks in an AG */
+ __u32 agcount; /* number of allocation groups */
+ __u32 logblocks; /* fsblocks in the log */
+ __u32 sectsize; /* (data) sector size, bytes */
+ __u32 inodesize; /* inode size in bytes */
+ __u32 imaxpct; /* max allowed inode space(%) */
+ __u64 datablocks; /* fsblocks in data subvolume */
+ __u64 rtblocks; /* fsblocks in realtime subvol */
+ __u64 rtextents; /* rt extents in realtime subvol*/
+ __u64 logstart; /* starting fsblock of the log */
+ unsigned char uuid[16]; /* unique id of the filesystem */
+ __u32 sunit; /* stripe unit, fsblocks */
+ __u32 swidth; /* stripe width, fsblocks */
+ __s32 version; /* structure version */
+ __u32 flags; /* superblock version flags */
+ __u32 logsectsize; /* log sector size, bytes */
+ __u32 rtsectsize; /* realtime sector size, bytes */
+ __u32 dirblocksize; /* directory block size, bytes */
+} xfs_fsop_geom_v1_t;
+
/*
* Output for XFS_IOC_FSGEOMETRY
*/
__u32 logsectsize; /* log sector size, bytes */
__u32 rtsectsize; /* realtime sector size, bytes */
__u32 dirblocksize; /* directory block size, bytes */
+ __u32 logsunit; /* log stripe unit, bytes */
} xfs_fsop_geom_t;
/* Output for XFS_FS_COUNTS */
#define XFS_FSOP_GEOM_FLAGS_SHARED 0x20 /* read-only shared */
#define XFS_FSOP_GEOM_FLAGS_EXTFLG 0x40 /* special extent flag */
#define XFS_FSOP_GEOM_FLAGS_DIRV2 0x80 /* directory version 2 */
+#define XFS_FSOP_GEOM_FLAGS_LOGV2 0x100 /* log format version 2 */
/*
/*
* ioctl commands that replace IRIX syssgi()'s
*/
-#define XFS_IOC_FSGEOMETRY _IOR ('X', 100, struct xfs_fsop_geom)
+#define XFS_IOC_FSGEOMETRY_V1 _IOR ('X', 100, struct xfs_fsop_geom_v1)
#define XFS_IOC_FSBULKSTAT _IOWR('X', 101, struct xfs_fsop_bulkreq)
#define XFS_IOC_FSBULKSTAT_SINGLE _IOWR('X', 102, struct xfs_fsop_bulkreq)
#define XFS_IOC_FSINUMBERS _IOWR('X', 103, struct xfs_fsop_bulkreq)
#define XFS_IOC_FSSETDM_BY_HANDLE _IOW ('X', 121, struct xfs_fsop_setdm_handlereq)
#define XFS_IOC_ATTRLIST_BY_HANDLE _IOW ('X', 122, struct xfs_fsop_attrlist_handlereq)
#define XFS_IOC_ATTRMULTI_BY_HANDLE _IOW ('X', 123, struct xfs_fsop_attrmulti_handlereq)
+#define XFS_IOC_FSGEOMETRY _IOR ('X', 124, struct xfs_fsop_geom)
/* XFS_IOC_GETFSUUID ---------- deprecated 140 */
#define XLOG_MAX_ICLOGS 8
#define XLOG_CALLBACK_SIZE 10
#define XLOG_HEADER_MAGIC_NUM 0xFEEDbabe /* Illegal cycle number */
+#define XLOG_VERSION_1 1
+#define XLOG_VERSION_2 2 /* Large IClogs, Log sunit */
+#define XLOG_VERSION_OKBITS (XLOG_VERSION_1 | XLOG_VERSION_2)
#define XLOG_RECORD_BSIZE (16*1024) /* eventually 32k */
-#define XLOG_MAX_RECORD_BSIZE (32*1024)
+#define XLOG_BIG_RECORD_BSIZE (32*1024) /* 32k buffers */
+#define XLOG_MAX_RECORD_BSIZE (256*1024)
+#define XLOG_HEADER_CYCLE_SIZE (32*1024) /* cycle data in header */
#define XLOG_RECORD_BSHIFT 14 /* 16384 == 1 << 14 */
-#define XLOG_MAX_RECORD_BSHIFT 15 /* 32k == 1 << 15 */
+#define XLOG_BIG_RECORD_BSHIFT 15 /* 32k == 1 << 15 */
+#define XLOG_MAX_RECORD_BSHIFT 18 /* 256k == 1 << 18 */
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XLOG_BTOLRBB)
int xlog_btolrbb(int b);
#define XLOG_BTOLRBB(b) xlog_btolrbb(b)
#define XLOG_HEADER_SIZE 512
+#define XLOG_TOTAL_REC_SHIFT(log) \
+ BTOBB(XLOG_MAX_ICLOGS << (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb) ? \
+ XLOG_MAX_RECORD_BSHIFT : XLOG_BIG_RECORD_BSHIFT))
+
/*
* set lsns
*/
#define GET_CLIENT_ID(i,arch) \
((i) >> 24)
#endif
-
+
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XLOG_GRANT_SUB_SPACE)
void xlog_grant_sub_space(struct log *log, int bytes, int type);
#define XLOG_GRANT_SUB_SPACE(log,bytes,type) \
typedef struct xlog_op_header {
xlog_tid_t oh_tid; /* transaction id of operation : 4 b */
- int oh_len; /* bytes in data region : 2 b */
+ int oh_len; /* bytes in data region : 4 b */
__uint8_t oh_clientid; /* who sent me this : 1 b */
__uint8_t oh_flags; /* : 1 b */
ushort oh_res2; /* 32 bit align : 2 b */
uint h_chksum; /* may not be used; non-zero if used : 4 */
int h_prev_block; /* block number to previous LR : 4 */
int h_num_logops; /* number of log operations in this LR : 4 */
- uint h_cycle_data[XLOG_MAX_RECORD_BSIZE / BBSIZE];
+ uint h_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE];
/* new fields */
int h_fmt; /* format of log record : 4 */
uuid_t h_fs_uuid; /* uuid of FS : 16 */
+ int h_size; /* iclog size : 4 */
} xlog_rec_header_t;
+typedef struct xlog_rec_ext_header {
+ uint xh_cycle; /* write cycle of log : 4 */
+ uint xh_cycle_data[XLOG_HEADER_CYCLE_SIZE / BBSIZE]; /* : 256 */
+} xlog_rec_ext_header_t;
#ifdef __KERNEL__
/*
* - A log record header is 512 bytes. There is plenty of room to grow the
* - ic_state is the state of the iclog.
*/
typedef struct xlog_iclog_fields {
- struct tq_struct ic_write_sched;
sv_t ic_forcesema;
struct xlog_in_core *ic_next;
struct xlog_in_core *ic_prev;
int ic_roundoff;
int ic_bwritecnt;
ushort_t ic_state;
+ char *ic_datap; /* pointer to iclog data */
+ struct tq_struct ic_write_sched;
} xlog_iclog_fields_t;
typedef struct xlog_in_core2 {
union {
xlog_rec_header_t hic_header;
+ xlog_rec_ext_header_t hic_xheader;
char hic_sector[XLOG_HEADER_SIZE];
} ic_h;
- __uint8_t hic_data[1];
} xlog_in_core_2_t;
typedef struct xlog_in_core {
#define ic_roundoff hic_fields.ic_roundoff
#define ic_bwritecnt hic_fields.ic_bwritecnt
#define ic_state hic_fields.ic_state
+#define ic_datap hic_fields.ic_datap
#define ic_header hic_data->ic_h.hic_header
-#define ic_data hic_data->hic_data
/*
* The reservation head lsn is not made up of a cycle number and block number.
uint l_flags;
uint l_quotaoffs_flag;/* XFS_DQ_*, if QUOTAOFFs found */
struct xfs_buf_cancel **l_buf_cancel_table;
+ int l_iclog_hsize; /* size of iclog header */
+ int l_iclog_heads; /* number of iclog header sectors */
} xlog_t;
#endif
int m_dalign; /* stripe unit */
int m_swidth; /* stripe width */
+ int m_lstripemask; /* log stripe mask */
int m_sinoalign; /* stripe unit inode alignmnt */
int m_attr_magicpct;/* 37% of the blocksize */
int m_dir_magicpct; /* 37% of the dir blocksize */
#define XFS_SB_VERSION_ALIGNBIT 0x0080
#define XFS_SB_VERSION_DALIGNBIT 0x0100
#define XFS_SB_VERSION_SHAREDBIT 0x0200
+#define XFS_SB_VERSION_LOGV2BIT 0x0400
#define XFS_SB_VERSION_EXTFLGBIT 0x1000
#define XFS_SB_VERSION_DIRV2BIT 0x2000
#define XFS_SB_VERSION_OKSASHFBITS \
XFS_SB_VERSION_QUOTABIT | \
XFS_SB_VERSION_ALIGNBIT | \
XFS_SB_VERSION_DALIGNBIT | \
- XFS_SB_VERSION_SHAREDBIT)
+ XFS_SB_VERSION_SHAREDBIT | \
+ XFS_SB_VERSION_LOGV2BIT)
#define XFS_SB_VERSION_OKSASHBITS \
(XFS_SB_VERSION_NUMBITS | \
XFS_SB_VERSION_REALFBITS | \
(XFS_SB_VERSION_NUMBITS | \
XFS_SB_VERSION_OKREALFBITS | \
XFS_SB_VERSION_OKSASHFBITS)
-#define XFS_SB_VERSION_MKFS(ia,dia,extflag,dirv2) \
- (((ia) || (dia) || (extflag) || (dirv2)) ? \
+#define XFS_SB_VERSION_MKFS(ia,dia,extflag,dirv2,na) \
+ (((ia) || (dia) || (extflag) || (dirv2) || (na)) ? \
(XFS_SB_VERSION_4 | \
((ia) ? XFS_SB_VERSION_ALIGNBIT : 0) | \
((dia) ? XFS_SB_VERSION_DALIGNBIT : 0) | \
((extflag) ? XFS_SB_VERSION_EXTFLGBIT : 0) | \
- ((dirv2) ? XFS_SB_VERSION_DIRV2BIT : 0)) : \
+ ((dirv2) ? XFS_SB_VERSION_DIRV2BIT : 0) | \
+ ((na) ? XFS_SB_VERSION_LOGV2BIT : 0)) : \
XFS_SB_VERSION_1)
typedef struct xfs_sb
__uint32_t sb_unit; /* stripe or raid unit */
__uint32_t sb_width; /* stripe or raid width */
__uint8_t sb_dirblklog; /* log2 of dir block size (fsbs) */
- __uint8_t sb_dummy[7]; /* padding */
+ __uint8_t sb_dummy[3]; /* padding */
+ __uint32_t sb_logsunit; /* stripe unit size for the log */
} xfs_sb_t;
/*
XFS_SBS_IFREE, XFS_SBS_FDBLOCKS, XFS_SBS_FREXTENTS, XFS_SBS_UQUOTINO,
XFS_SBS_GQUOTINO, XFS_SBS_QFLAGS, XFS_SBS_FLAGS, XFS_SBS_SHARED_VN,
XFS_SBS_INOALIGNMT, XFS_SBS_UNIT, XFS_SBS_WIDTH, XFS_SBS_DIRBLKLOG,
- XFS_SBS_DUMMY,
+ XFS_SBS_DUMMY, XFS_SBS_LOGSUNIT,
XFS_SBS_FIELDCOUNT
} xfs_sb_field_t;
((sbp)->sb_versionnum & XFS_SB_VERSION_DIRV2BIT))
#endif
+#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASLOGV2)
+int xfs_sb_version_haslogv2(xfs_sb_t *sbp);
+#define XFS_SB_VERSION_HASLOGV2(sbp) xfs_sb_version_haslogv2(sbp)
+#else
+#define XFS_SB_VERSION_HASLOGV2(sbp) \
+ ((XFS_SB_VERSION_NUM(sbp) == XFS_SB_VERSION_4) && \
+ ((sbp)->sb_versionnum & XFS_SB_VERSION_LOGV2BIT))
+#endif
+
#if XFS_WANT_FUNCS || (XFS_WANT_SPACE && XFSSO_XFS_SB_VERSION_HASEXTFLGBIT)
int xfs_sb_version_hasextflgbit(xfs_sb_t *sbp);
#define XFS_SB_VERSION_HASEXTFLGBIT(sbp) xfs_sb_version_hasextflgbit(sbp)
xfs_daddr_t start,
uint length,
uuid_t *fs_uuid,
+ int version,
+ int sunit,
int fmt)
{
xfs_buf_t *buf;
xlog_rec_header_t *head;
xlog_op_header_t *op;
+ int i, len;
/* the data section must be 32 bit size aligned */
struct {
__uint16_t magic;
libxfs_device_zero(device, start, length);
/* then write a log record header */
- buf = libxfs_getbuf(device, start, 1);
+ if ((version == 2) && sunit)
+ len = BTOBB(sunit);
+ else
+ len = 1;
+ buf = libxfs_getbuf(device, start, len);
if (!buf)
return -1;
- memset(XFS_BUF_PTR(buf), 0, BBSIZE);
+ memset(XFS_BUF_PTR(buf), 0, BBSIZE * len);
head = (xlog_rec_header_t *)XFS_BUF_PTR(buf);
/* note that oh_tid actually contains the cycle number
INT_SET(head->h_magicno, ARCH_CONVERT, XLOG_HEADER_MAGIC_NUM);
INT_SET(head->h_cycle, ARCH_CONVERT, 1);
- INT_SET(head->h_version, ARCH_CONVERT, 1);
- INT_SET(head->h_len, ARCH_CONVERT, 20);
+ INT_SET(head->h_version, ARCH_CONVERT, version);
+ if (len != 1)
+ INT_SET(head->h_len, ARCH_CONVERT, sunit - BBSIZE);
+ else
+ INT_SET(head->h_len, ARCH_CONVERT, 20);
INT_SET(head->h_chksum, ARCH_CONVERT, 0);
INT_SET(head->h_prev_block, ARCH_CONVERT, -1);
INT_SET(head->h_num_logops, ARCH_CONVERT, 1);
INT_SET(head->h_cycle_data[0], ARCH_CONVERT, 0xb0c0d0d0);
INT_SET(head->h_fmt, ARCH_CONVERT, fmt);
+ INT_SET(head->h_size, ARCH_CONVERT, XLOG_HEADER_CYCLE_SIZE);
ASSIGN_ANY_LSN(head->h_lsn, 1, 0, ARCH_CONVERT);
ASSIGN_ANY_LSN(head->h_tail_lsn, 1, 0, ARCH_CONVERT);
memcpy(head->h_fs_uuid, fs_uuid, sizeof(uuid_t));
+
+ if (len > 1) {
+ xfs_caddr_t dp;
+ uint cycle_lsn;
+
+ cycle_lsn = CYCLE_LSN_NOCONV(head->h_lsn, ARCH_CONVERT);
+ dp = XFS_BUF_PTR(buf) + BBSIZE;
+ for (i = 1; i < len; i++) {
+ *(uint *)dp = cycle_lsn;
+ dp += BBSIZE;
+ }
+ }
if (libxfs_writebuf(buf, 0))
return -1;
mp->m_blockwsize = sbp->sb_blocksize >> XFS_WORDLOG;
mp->m_blockwmask = mp->m_blockwsize - 1;
+
+ if (XFS_SB_VERSION_HASLOGV2(sbp)) {
+ if (sbp->sb_logsunit <= 1) {
+ mp->m_lstripemask = 1;
+ } else {
+ mp->m_lstripemask =
+ 1 << xfs_highbit32(sbp->sb_logsunit >> BBSHIFT);
+ }
+ }
+
/*
* Setup for attributes, in case they get created.
* This value is for inodes getting attributes for the first time,
{ offsetof(xfs_sb_t, sb_width), 0 },
{ offsetof(xfs_sb_t, sb_dirblklog), 0 },
{ offsetof(xfs_sb_t, sb_dummy), 1 },
+ { offsetof(xfs_sb_t, sb_logsunit), 0 },
{ sizeof(xfs_sb_t), 0 }
};
int error = 0;
int smallmem = 0;
int num_blks = *last_blk - start_blk;
+ int xhdrs;
ASSERT(start_blk != 0 || *last_blk != start_blk);
* reset last_blk. Only when last_blk points in the middle of a log
* record do we update last_blk.
*/
+ if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
+ int h_size = INT_GET(head->h_size, ARCH_CONVERT);
+ xhdrs = h_size / XLOG_HEADER_CYCLE_SIZE;
+ if (h_size % XLOG_HEADER_CYCLE_SIZE)
+ xhdrs++;
+ } else {
+ xhdrs = 1;
+ }
+
if (*last_blk - i + extra_bblks
- != BTOBB(INT_GET(head->h_len, ARCH_CONVERT))+1)
+ != BTOBB(INT_GET(head->h_len, ARCH_CONVERT))+xhdrs)
*last_blk = i;
out:
* in the in-core log. The following number can be made tighter if
* we actually look at the block size of the filesystem.
*/
- num_scan_bblks = BTOBB(XLOG_MAX_ICLOGS<<XLOG_MAX_RECORD_BSHIFT);
+ num_scan_bblks = XLOG_TOTAL_REC_SHIFT(log);
if (head_blk >= num_scan_bblks) {
/*
* We are guaranteed that the entire check can be performed
xfs_daddr_t umount_data_blk;
xfs_daddr_t after_umount_blk;
xfs_lsn_t tail_lsn;
+ int hblks;
found = error = 0;
* unmount record if there is one, so we pass the lsn of the
* unmount record rather than the block after it.
*/
- after_umount_blk = (i + 2) % log->l_logBBsize;
+ if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
+ int h_size = INT_GET(rhead->h_size, ARCH_CONVERT);
+ int h_version = INT_GET(rhead->h_version, ARCH_CONVERT);
+ if ((h_version && XLOG_VERSION_2) &&
+ (h_size > XLOG_HEADER_CYCLE_SIZE)) {
+ hblks = h_size / XLOG_HEADER_CYCLE_SIZE;
+ if (h_size % XLOG_HEADER_CYCLE_SIZE)
+ hblks++;
+ } else {
+ hblks = 1;
+ }
+ } else {
+ hblks = 1;
+ }
+ after_umount_blk = (i + hblks +
+ (int)BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT))) % log->l_logBBsize;
tail_lsn = log->l_tail_lsn;
if (*head_blk == after_umount_blk && INT_GET(rhead->h_num_logops, ARCH_CONVERT) == 1) {
- umount_data_blk = (i + 1) % log->l_logBBsize;
+ umount_data_blk = (i + hblks) % log->l_logBBsize;
if ((error = xlog_bread(log, umount_data_blk, 1, bp))) {
goto bread_err;
}
return error;
} /* xlog_find_tail */
-
/*
* Is the log zeroed at all?
*
* we scan over the defined maximum blocks. At this point, the maximum
* is not chosen to mean anything special. XXXmiken
*/
- num_scan_bblks = BTOBB(XLOG_MAX_ICLOGS<<XLOG_MAX_RECORD_BSHIFT);
+ num_scan_bblks = XLOG_TOTAL_REC_SHIFT(log);
ASSERT(num_scan_bblks <= INT_MAX);
if (last_blk < num_scan_bblks)
xfs_caddr_t dp,
xlog_t *log)
{
- int i;
+ int i, j, k;
+ union ich {
+ xlog_rec_header_t hic_header;
+ xlog_rec_ext_header_t hic_xheader;
+ char hic_sector[XLOG_HEADER_SIZE];
+ } *xhdr;
+
#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
uint *up = (uint *)dp;
uint chksum = 0;
#endif
- for (i=0; i<BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); i++) {
- /* these are both on-disk, so don't endian flip twice */
+ for (i=0; i < BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)) &&
+ i < (XLOG_HEADER_CYCLE_SIZE / BBSIZE); i++) {
*(uint *)dp = *(uint *)&rhead->h_cycle_data[i];
dp += BBSIZE;
}
+
+ if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
+ xhdr = (union ich*)rhead;
+ for ( ; i < BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); i++) {
+ j = i / (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
+ k = i % (XLOG_HEADER_CYCLE_SIZE / BBSIZE);
+ *(uint *)dp = xhdr[j].hic_xheader.xh_cycle_data[k];
+ dp += BBSIZE;
+ }
+ }
+
#if defined(DEBUG) && defined(XFS_LOUD_RECOVERY)
/* divide length by 4 to get # words */
for (i=0; i < INT_GET(rhead->h_len, ARCH_CONVERT) >> 2; i++) {
INT_GET(rhead->h_chksum, ARCH_CONVERT), chksum);
cmn_err(CE_DEBUG,
"XFS: Disregard message if filesystem was created with non-DEBUG kernel");
+ if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
+ cmn_err(CE_DEBUG,
+ "XFS: LogR this is a LogV2 filesystem\n");
+ }
log->l_flags |= XLOG_CHKSUM_MISMATCH;
}
}
#endif /* DEBUG && XFS_LOUD_RECOVERY */
} /* xlog_unpack_data */
-
STATIC xlog_recover_t *
xlog_recover_find_tid(xlog_recover_t *q,
xlog_tid_t tid)
if (xlog_header_check_recover(log->l_mp, rhead))
return (XFS_ERROR(EIO));
- while (dp < lp) {
+ while ((dp < lp) && num_logops) {
ASSERT(dp + sizeof(xlog_op_header_t) <= lp);
ohead = (xlog_op_header_t *)dp;
dp += sizeof(xlog_op_header_t);
xfs_daddr_t blk_no;
xfs_caddr_t bufaddr;
xfs_buf_t *hbp, *dbp;
- int error;
+ int error, h_size;
int bblks, split_bblks;
+ int hblks, split_hblks, wrapped_hblks;
xlog_recover_t *rhash[XLOG_RHASH_SIZE];
error = 0;
- hbp = xlog_get_bp(1,log->l_mp);
+
+
+ /*
+ * Read the header of the tail block and get the iclog buffer size from
+ * h_size. Use this to tell how many sectors make up the log header.
+ */
+ if (XFS_SB_VERSION_HASLOGV2(&log->l_mp->m_sb)) {
+ /*
+ * When using variable length iclogs, read first sector of iclog
+ * header and extract the header size from it. Get a new hbp that
+ * is the correct size.
+ */
+ hbp = xlog_get_bp(1, log->l_mp);
+ if (!hbp)
+ return ENOMEM;
+ if ((error = xlog_bread(log, tail_blk, 1, hbp)))
+ goto bread_err1;
+ rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp);
+ ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) ==
+ XLOG_HEADER_MAGIC_NUM);
+ if ((INT_GET(rhead->h_version, ARCH_CONVERT) & (~XLOG_VERSION_OKBITS)) != 0) {
+ xlog_warn("XFS: xlog_do_recovery_pass: unrecognised log version number.");
+ error = XFS_ERROR(EIO);
+ goto bread_err1;
+ }
+ h_size = INT_GET(rhead->h_size, ARCH_CONVERT);
+
+ if ((INT_GET(rhead->h_version, ARCH_CONVERT) & XLOG_VERSION_2) &&
+ (h_size > XLOG_HEADER_CYCLE_SIZE)) {
+ hblks = h_size / XLOG_HEADER_CYCLE_SIZE;
+ if (h_size % XLOG_HEADER_CYCLE_SIZE)
+ hblks++;
+ xlog_put_bp(hbp);
+ hbp = xlog_get_bp(hblks, log->l_mp);
+ } else {
+ hblks=1;
+ }
+ } else {
+ hblks=1;
+ hbp = xlog_get_bp(1, log->l_mp);
+ h_size = XLOG_BIG_RECORD_BSIZE;
+ }
+
if (!hbp)
return ENOMEM;
- dbp = xlog_get_bp(BTOBB(XLOG_MAX_RECORD_BSIZE),log->l_mp);
+ dbp = xlog_get_bp(BTOBB(h_size),log->l_mp);
if (!dbp) {
xlog_put_bp(hbp);
return ENOMEM;
}
+
bzero(rhash, sizeof(rhash));
if (tail_blk <= head_blk) {
for (blk_no = tail_blk; blk_no < head_blk; ) {
- if ((error = xlog_bread(log, blk_no, 1, hbp)))
- goto bread_err;
+ if ((error = xlog_bread(log, blk_no, hblks, hbp)))
+ goto bread_err2;
rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp);
ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM);
ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX));
+ if ((INT_GET(rhead->h_version, ARCH_CONVERT) & (~XLOG_VERSION_OKBITS)) != 0) {
+ xlog_warn("XFS: xlog_do_recovery_pass: unrecognised log version number.");
+ error = XFS_ERROR(EIO);
+ goto bread_err2;
+ }
bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT)); /* blocks in data section */
if (bblks > 0) {
- if ((error = xlog_bread(log, blk_no+1, bblks, dbp)))
- goto bread_err;
+ if ((error = xlog_bread(log, blk_no+hblks, bblks, dbp)))
+ goto bread_err2;
xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log);
if ((error = xlog_recover_process_data(log, rhash,
rhead, XFS_BUF_PTR(dbp),
pass)))
- goto bread_err;
+ goto bread_err2;
}
- blk_no += (bblks+1);
+ blk_no += (bblks+hblks);
}
} else {
/*
*/
blk_no = tail_blk;
while (blk_no < log->l_logBBsize) {
-
- /* Read header of one block */
- if ((error = xlog_bread(log, blk_no, 1, hbp)))
- goto bread_err;
+ /*
+ * Check for header wrapping around physical end-of-log
+ */
+ wrapped_hblks = 0;
+ if (blk_no+hblks <= log->l_logBBsize) {
+ /* Read header in one read */
+ if ((error = xlog_bread(log, blk_no, hblks, hbp)))
+ goto bread_err2;
+ } else {
+ /* This log record is split across physical end of log */
+ split_hblks = 0;
+ if (blk_no != log->l_logBBsize) {
+ /* some data is before physical end of log */
+ ASSERT(blk_no <= INT_MAX);
+ split_hblks = log->l_logBBsize - (int)blk_no;
+ ASSERT(split_hblks > 0);
+ if ((error = xlog_bread(log, blk_no, split_hblks, hbp)))
+ goto bread_err2;
+ }
+ bufaddr = XFS_BUF_PTR(hbp);
+ XFS_BUF_SET_PTR(hbp, bufaddr + BBTOB(split_hblks),
+ BBTOB(hblks - split_hblks));
+ wrapped_hblks = hblks - split_hblks;
+ if ((error = xlog_bread(log, 0, wrapped_hblks, hbp)))
+ goto bread_err2;
+ XFS_BUF_SET_PTR(hbp, bufaddr, hblks);
+ }
rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp);
ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM);
ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX));
/* LR body must have data or it wouldn't have been written */
ASSERT(bblks > 0);
- blk_no++; /* successfully read header */
- ASSERT(blk_no <= log->l_logBBsize);
+ blk_no += hblks; /* successfully read header */
if ((INT_GET(rhead->h_magicno, ARCH_CONVERT) != XLOG_HEADER_MAGIC_NUM) ||
(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) > INT_MAX)) ||
- (bblks <= 0) ||
- (blk_no > log->l_logBBsize)) {
+ (bblks <= 0)) {
error = EFSCORRUPTED;
- goto bread_err;
+ goto bread_err2;
}
/* Read in data for log record */
if (blk_no+bblks <= log->l_logBBsize) {
if ((error = xlog_bread(log, blk_no, bblks, dbp)))
- goto bread_err;
+ goto bread_err2;
} else {
/* This log record is split across physical end of log */
split_bblks = 0;
split_bblks = log->l_logBBsize - (int)blk_no;
ASSERT(split_bblks > 0);
if ((error = xlog_bread(log, blk_no, split_bblks, dbp)))
- goto bread_err;
+ goto bread_err2;
}
bufaddr = XFS_BUF_PTR(dbp);
XFS_BUF_SET_PTR(dbp, bufaddr + BBTOB(split_bblks),
BBTOB(bblks - split_bblks));
- if ((error = xlog_bread(log, 0, bblks - split_bblks, dbp)))
- goto bread_err;
- XFS_BUF_SET_PTR(dbp, bufaddr, XLOG_MAX_RECORD_BSIZE);
+ if ((error = xlog_bread(log, wrapped_hblks,
+ bblks - split_bblks, dbp)))
+ goto bread_err2;
+ XFS_BUF_SET_PTR(dbp, bufaddr, XLOG_BIG_RECORD_BSIZE);
}
xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log);
if ((error = xlog_recover_process_data(log, rhash,
rhead, XFS_BUF_PTR(dbp),
pass)))
- goto bread_err;
+ goto bread_err2;
blk_no += bblks;
}
/* read first part of physical log */
while (blk_no < head_blk) {
- if ((error = xlog_bread(log, blk_no, 1, hbp)))
- goto bread_err;
+ if ((error = xlog_bread(log, blk_no, hblks, hbp)))
+ goto bread_err2;
rhead = (xlog_rec_header_t *)XFS_BUF_PTR(hbp);
ASSERT(INT_GET(rhead->h_magicno, ARCH_CONVERT) == XLOG_HEADER_MAGIC_NUM);
ASSERT(BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT) <= INT_MAX));
bblks = (int) BTOBB(INT_GET(rhead->h_len, ARCH_CONVERT));
ASSERT(bblks > 0);
- if ((error = xlog_bread(log, blk_no+1, bblks, dbp)))
- goto bread_err;
+ if ((error = xlog_bread(log, blk_no+hblks, bblks, dbp)))
+ goto bread_err2;
xlog_unpack_data(rhead, XFS_BUF_PTR(dbp), log);
if ((error = xlog_recover_process_data(log, rhash,
rhead, XFS_BUF_PTR(dbp),
pass)))
- goto bread_err;
- blk_no += (bblks+1);
+ goto bread_err2;
+ blk_no += (bblks+hblks);
}
}
-bread_err:
+bread_err2:
xlog_put_bp(dbp);
+bread_err1:
xlog_put_bp(hbp);
return error;
These options specify the location, size, and other parameters of the
log section of the filesystem.
The valid suboptions are:
-.BI internal[= value ]
-and
-\f3size=\f1\f2value\f1.
+.BI internal[= value ],
+\f3size=\f1\f2value\f1,
+\f3version=\f1\f2[1|2]\f1 and
+\f3sunit=\f1\f2value\f1.
.IP
The
.B internal
The overriding minimum value for size is 512 blocks.
With some combinations of filesystem block size, inode size,
and directory block size, the minimum log size is larger than 512 blocks.
+.IP
+Using the
+.B version
+option to set a version 2 log enables the
+.B sunit
+option, and allows the logbsize to be increased beyond 32K.
+The
+.B sunit
+option specifies the alignment to be used for log writes,
+it can be in bytes or filesystem blocks.
+Log writes will be aligned on this boundary,
+and rounded up to this boundary.
+This gives major improvements in performance on some configurations
+such as software raid5 when the sunit is specified as the filesystem
+block size.
.TP
.B \-n
Naming options.
"internal",
#define L_SIZE 2
"size",
-#define L_DEV 3
+#define L_VERSION 3
+ "version",
+#define L_LSUNIT 4
+ "sunit",
+#define L_DEV 5
"logdev",
#ifdef MKFS_SIMULATION
-#define L_FILE 4
+#define L_FILE 6
"file",
-#define L_NAME 5
+#define L_NAME 7
"name",
#endif
NULL
return 0;
}
+xfs_dfsbno_t
+fixup_log_stripe(
+ xfs_mount_t *mp,
+ int lsflag,
+ xfs_dfsbno_t logstart,
+ __uint64_t agsize,
+ int sunit,
+ xfs_drfsbno_t *logblocks,
+ int blocklog)
+{
+ __uint64_t tmp_logblocks;
+
+ sunit = XFS_B_TO_FSB(mp, sunit);
+ logstart = ((logstart + (sunit - 1))/sunit) * sunit;
+ /*
+ * Make sure that the log size is a multiple of the
+ * stripe unit
+ */
+ if ((*logblocks % sunit) != 0) {
+ if (!lsflag) {
+ tmp_logblocks = ((*logblocks + (sunit - 1))
+ / sunit) * sunit;
+ /*
+ * If the log is too large, round down
+ * instead of round up
+ */
+ if ((tmp_logblocks > XFS_MAX_LOG_BLOCKS) ||
+ ((tmp_logblocks << blocklog) > XFS_MAX_LOG_BYTES)) {
+ tmp_logblocks = (*logblocks / sunit) * sunit;
+ }
+ *logblocks = tmp_logblocks;
+ } else {
+ fprintf(stderr,
+ "internal log size %lld is not a multiple of the log stripe unit %d\n",
+ (long long)*logblocks, sunit);
+ usage();
+ }
+ }
+
+ if (*logblocks > agsize-XFS_FSB_TO_AGBNO(mp,logstart)) {
+ fprintf(stderr,
+ "Due to stripe alignment, the internal log size %lld is too large.\n"
+ "Must fit in allocation group\n",
+ (long long)*logblocks);
+ usage();
+ }
+ return logstart;
+}
int
main(int argc, char **argv)
int loginternal;
char *logsize;
xfs_dfsbno_t logstart;
+ int logversion;
+ int lvflag;
int lsflag;
+ int lsunit;
+ char *logstripe;
int min_logblocks;
mnt_check_state_t *mnt_check_state;
int mnt_partition_count;
xfs_sb_t *sbp;
int sectlog;
__uint64_t tmp_agsize;
- __uint64_t tmp_logblocks;
uuid_t uuid;
int worst_freelist;
libxfs_init_t xi;
blocklog = libxfs_highbit32(blocksize);
agsize = daflag = dblocks = 0;
ilflag = imflag = ipflag = isflag = 0;
- liflag = laflag = lsflag = ldflag = 0;
+ liflag = laflag = lsflag = ldflag = lvflag = 0;
loginternal = 1;
+ logversion = 1;
logagno = logblocks = rtblocks = 0;
nlflag = nsflag = nvflag = 0;
dirblocklog = dirblocksize = dirversion = 0;
xi.notvolok = 1;
xi.setblksize = 1;
dfile = logfile = rtfile = NULL;
- dsize = logsize = rtsize = rtextsize = protofile = NULL;
+ dsize = logsize = logstripe = rtsize = rtextsize = protofile = NULL;
opterr = 0;
- dsu = dsw = dsunit = dswidth = nodsflag = lalign = 0;
+ dsu = dsw = dsunit = dswidth = nodsflag = lalign = lsunit = 0;
do_overlap_checks = 1;
extent_flagging = 0;
force_overwrite = 0;
illegal(value, "l internal");
liflag = 1;
break;
+ case L_LSUNIT:
+ if (!value)
+ reqval('l', lopts, L_LSUNIT);
+ if (logstripe)
+ respec('l', lopts, L_LSUNIT);
+ logstripe = value;
+ break;
#ifdef HAVE_VOLUME_MANAGER
case L_NAME:
if (!value)
xi.logname = value;
break;
#endif
+ case L_VERSION:
+ if (!value)
+ reqval('n', nopts, L_VERSION);
+ if (lvflag)
+ respec('n', nopts, L_VERSION);
+ logversion = atoi(value);
+ if (logversion < 1 || logversion > 2)
+ illegal(value, "l version");
+ lvflag = 1;
+ break;
case L_SIZE:
if (!value)
reqval('l', lopts, L_SIZE);
(long long)logbytes, blocksize,
(long long)(logblocks << blocklog));
}
+ if (logstripe) {
+ lsunit = cvtnum(blocksize, logstripe);
+ }
#ifdef HAVE_VOLUME_MANAGER
if (xi.risfile && (!rtsize || !xi.rtname)) {
fprintf(stderr,
}
}
+ /*
+ * check that log sunit is modulo fsblksize or default it to dsunit.
+ */
+
+ if (lsunit) {
+ if (lsunit % blocksize != 0) {
+ fprintf(stderr,
+"log stripe unit (%d) is not a multiple of the block size (%d)\n",
+ lsunit, blocksize);
+ exit(1);
+ }
+ } else {
+ if (dsunit)
+ lsunit = dsunit;
+ }
+
+ if (lsunit > 256 * 1024) {
+ fprintf(stderr,
+"log stripe unit (%d) is too large for kernel to handle\n", lsunit);
+ exit(1);
+ }
+
protostring = setup_proto(protofile);
bsize = 1 << (blocklog - BBSHIFT);
mp = &mbuf;
/*
* Align the logstart at stripe unit boundary.
*/
- if (dsunit && ((logstart % dsunit) != 0)) {
- logstart = ((logstart + (dsunit - 1))/dsunit) * dsunit;
- /*
- * Make sure that the log size is a multiple of the
- * stripe unit
- */
- if ((logblocks % dsunit) != 0) {
- if (!lsflag) {
- tmp_logblocks = ((logblocks + (dsunit - 1))
- / dsunit) * dsunit;
- /*
- * If the log is too large, round down
- * instead of round up
- */
- if ((tmp_logblocks > XFS_MAX_LOG_BLOCKS) ||
- ((tmp_logblocks << blocklog) > XFS_MAX_LOG_BYTES)) {
- tmp_logblocks = (logblocks / dsunit) * dsunit;
- }
- logblocks = tmp_logblocks;
- } else {
- fprintf(stderr,
- "internal log size %lld is not a multiple of the stripe unit %d\n",
- (long long)logblocks, dsunit);
- usage();
- }
- }
- if (logblocks > agsize-XFS_FSB_TO_AGBNO(mp,logstart)) {
- fprintf(stderr,
- "Due to stripe alignment, the internal log size %lld is too large.\n"
- "Must fit in allocation group\n",
- (long long)logblocks);
- usage();
- }
+ if (lsunit && ((logstart % lsunit) != 0)) {
+ logstart = fixup_log_stripe(mp, lsflag, logstart,
+ agsize, lsunit, &logblocks,
+ blocklog);
+ lalign = 1;
+ } else if (dsunit && ((logstart % dsunit) != 0)) {
+ logstart = fixup_log_stripe(mp, lsflag, logstart,
+ agsize, dsunit, &logblocks,
+ blocklog);
lalign = 1;
}
} else
sbp->sb_width = dswidth;
if (dirversion == 2)
sbp->sb_dirblklog = dirblocklog - blocklog;
+ if (logversion == 2)
+ sbp->sb_logsunit = (lsunit == 0) ? 1 : lsunit;
+ else
+ sbp->sb_logsunit = 0;
if (iaflag) {
sbp->sb_inoalignmt = XFS_INODE_BIG_CLUSTER_SIZE >> blocklog;
iaflag = sbp->sb_inoalignmt != 0;
sbp->sb_inoalignmt = 0;
sbp->sb_versionnum =
XFS_SB_VERSION_MKFS(iaflag, dsunit != 0, extent_flagging,
- dirversion == 2);
+ dirversion == 2, logversion == 2);
/*
* Zero out the first 68k in on the device, to obliterate any old
"data =%-22s bsize=%-6d blocks=%lld, imaxpct=%d\n"
" =%-22s sunit=%-6d swidth=%d blks, unwritten=%d\n"
"naming =version %-14d bsize=%-6d\n"
- "log =%-22s bsize=%-6d blocks=%lld\n"
+ "log =%-22s bsize=%-6d blocks=%lld, version=%d\n"
+ " =%-22s sunit=%d\n"
"realtime =%-22s extsz=%-6d blocks=%lld, rtextents=%lld\n",
dfile, isize, (long long)agcount, (long long)agsize,
"", blocksize, (long long)dblocks, sbp->sb_imax_pct,
"", dsunit, dswidth, extent_flagging,
dirversion, dirversion == 1 ? blocksize : dirblocksize,
logfile, 1 << blocklog, (long long)logblocks,
+ logversion, "", lsunit,
rtfile, rtextblocks << blocklog,
(long long)rtblocks, (long long)rtextents);
/*
XFS_FSB_TO_DADDR(mp, logstart),
(xfs_extlen_t)XFS_FSB_TO_BB(mp, logblocks),
&sbp->sb_uuid,
- XLOG_FMT);
+ logversion, lsunit, XLOG_FMT);
mp = libxfs_mount(mp, sbp, xi.ddev, xi.logdev, xi.rtdev, 1);
if (mp == NULL) {
su=value,sw=value]\n\
/* inode size */ [-i log=n|perblock=n|size=num,maxpct=n]\n\
/* log subvol */ [-l agnum=n,internal,size=num,logdev=xxx]\n\
+ version=n,sunit=value]\n\
/* naming */ [-n log=n|size=num|version=n]\n\
/* label */ [-L label (maximum 12 characters)]\n\
/* prototype file */ [-p fname]\n\
* work against older filesystems when the superblock
* gets rev'ed again with new fields appended.
*/
- if (XFS_SB_VERSION_HASDIRV2(sb))
+ if (XFS_SB_VERSION_HASLOGV2(sb))
+ size = (__psint_t)&sb->sb_logsunit
+ + sizeof(sb->sb_logsunit) - (__psint_t)sb;
+ else if (XFS_SB_VERSION_HASDIRV2(sb))
size = (__psint_t)&sb->sb_dirblklog
+ sizeof(sb->sb_dirblklog) - (__psint_t)sb;
else
XFS_FSB_TO_DADDR(mp, mp->m_sb.sb_logstart),
(xfs_extlen_t)XFS_FSB_TO_BB(mp, mp->m_sb.sb_logblocks),
&mp->m_sb.sb_uuid,
- XLOG_FMT);
+ XFS_SB_VERSION_HASLOGV2(&mp->m_sb) ? 2 : 1,
+ mp->m_sb.sb_logsunit, XLOG_FMT);
}
/*