]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/commitdiff
logprint: handle split EFI entry
authorMark Tinguely <tinguely@sgi.com>
Mon, 14 Apr 2014 06:15:05 +0000 (16:15 +1000)
committerDave Chinner <david@fromorbit.com>
Mon, 14 Apr 2014 06:15:05 +0000 (16:15 +1000)
xfs_logprint does not correctly handle EFI entries that
are split across two log buffers. xfs_efi_copy_format()
falsely interrupts the truncated size of the split entry
as being a corrupt entry.

If the first log entry has enough information, namely the
number of extents in the entry and the identifier, then
display this information and a warning that this entry is
truncated. Otherwise, if there is not enough information in
the first log buffer, then print a message that the EFI decode
was not possible. These messages are similar to split inode
entries.

Example of a continued entry:
Oper (336): tid: f214bdb  len: 44  clientid: TRANS  flags: CONTINUE
EFI:  #regs: 1    num_extents: 2  id: 0xffff880804f63900
EFI free extent data skipped (CONTINUE set, no space)

Reported-by: Michael L. Semon <mlsemon35@gmail.com>
Signed-off-by: Mark Tinguely <tinguely@sgi.com>
Reviewed-by: Dave Chinner <dchinner@redhat.com>
Signed-off-by: Dave Chinner <david@fromorbit.com>
logprint/log_misc.c
logprint/log_print_all.c
logprint/logprint.h

index 45a2ed59b45e5a521f61b121ef1baa01f4d16dba..928f60a52533ad501f5d458f520ebadd63101db5 100644 (file)
@@ -477,13 +477,17 @@ xlog_print_trans_efd(xfs_caddr_t *ptr, uint len)
 
 
 int
-xlog_print_trans_efi(xfs_caddr_t *ptr, uint src_len)
+xlog_print_trans_efi(
+       xfs_caddr_t *ptr,
+       uint src_len,
+       int continued)
 {
     xfs_efi_log_format_t *src_f, *f;
     uint                dst_len;
     xfs_extent_t        *ex;
     int                         i;
     int                         error = 0;
+    int                         core_size = offsetof(xfs_efi_log_format_t, efi_extents);
 
     /*
      * memmove to ensure 8-byte alignment for the long longs in
@@ -498,17 +502,29 @@ xlog_print_trans_efi(xfs_caddr_t *ptr, uint src_len)
 
     /* convert to native format */
     dst_len = sizeof(xfs_efi_log_format_t) + (src_f->efi_nextents - 1) * sizeof(xfs_extent_t);
+
+    if (continued && src_len < core_size) {
+       printf(_("EFI: Not enough data to decode further\n"));
+       return 1;
+    }
+
     if ((f = (xfs_efi_log_format_t *)malloc(dst_len)) == NULL) {
        fprintf(stderr, _("%s: xlog_print_trans_efi: malloc failed\n"), progname);
        exit(1);
     }
-    if (xfs_efi_copy_format((char*)src_f, src_len, f)) {
+    if (xfs_efi_copy_format((char*)src_f, src_len, f, continued)) {
        error = 1;
        goto error;
     }
 
     printf(_("EFI:  #regs: %d    num_extents: %d  id: 0x%llx\n"),
           f->efi_size, f->efi_nextents, (unsigned long long)f->efi_id);
+
+    if (continued) {
+       printf(_("EFI free extent data skipped (CONTINUE set, no space)\n"));
+       goto error;
+    }
+
     ex = f->efi_extents;
     for (i=0; i < f->efi_nextents; i++) {
            printf("(s: 0x%llx, l: %d) ",
@@ -1033,7 +1049,8 @@ xlog_print_record(
                    }
                    case XFS_LI_EFI: {
                        skip = xlog_print_trans_efi(&ptr,
-                                       be32_to_cpu(op_head->oh_len));
+                                       be32_to_cpu(op_head->oh_len),
+                                       continued);
                        break;
                    }
                    case XFS_LI_EFD: {
@@ -1571,7 +1588,11 @@ xfs_inode_item_format_convert(char *src_buf, uint len, xfs_inode_log_format_t *i
 }
 
 int
-xfs_efi_copy_format(char *buf, uint len, xfs_efi_log_format_t *dst_efi_fmt)
+xfs_efi_copy_format(
+       char                      *buf,
+       uint                      len,
+       struct xfs_efi_log_format *dst_efi_fmt,
+       int                       continued)
 {
         uint i;
        uint nextents = ((xfs_efi_log_format_t *)buf)->efi_nextents;
@@ -1579,7 +1600,7 @@ xfs_efi_copy_format(char *buf, uint len, xfs_efi_log_format_t *dst_efi_fmt)
         uint len32 = sizeof(xfs_efi_log_format_32_t) + (nextents - 1) * sizeof(xfs_extent_32_t);
         uint len64 = sizeof(xfs_efi_log_format_64_t) + (nextents - 1) * sizeof(xfs_extent_64_t);
 
-        if (len == dst_len) {
+        if (len == dst_len || continued) {
                 memcpy((char *)dst_efi_fmt, buf, len);
                 return 0;
         } else if (len == len32) {
index 60da2722d1fce4ada32a4cd8deb0e3fac0c69bd9..2b5c4beb9f3ab26b0a72095f4f0e6d28aa75d260 100644 (file)
@@ -410,7 +410,7 @@ xlog_recover_print_efi(
            fprintf(stderr, _("%s: xlog_recover_print_efi: malloc failed\n"), progname);
            exit(1);
        }
-       if (xfs_efi_copy_format((char*)src_f, src_len, f)) {
+       if (xfs_efi_copy_format((char*)src_f, src_len, f, 0)) {
            free(f);
            return;
        }
index 933c9e6d2ce22550618f554caf38204c69cc7171..228b04280587842aac0437ed2ae8ffcf87ee3955 100644 (file)
@@ -47,6 +47,6 @@ extern void print_stars(void);
 
 extern xfs_inode_log_format_t *
        xfs_inode_item_format_convert(char *, uint, xfs_inode_log_format_t *);
-extern int xfs_efi_copy_format(char *, uint, xfs_efi_log_format_t *);
+extern int xfs_efi_copy_format(char *, uint, xfs_efi_log_format_t *, int);
 
 #endif /* LOGPRINT_H */