summaryrefslogtreecommitdiff
path: root/fs/xfs/scrub
diff options
context:
space:
mode:
authorDarrick J. Wong <djwong@kernel.org>2021-09-29 15:17:02 -0700
committerDarrick J. Wong <djwong@kernel.org>2021-12-15 17:29:29 -0800
commitac629a3a8dd1518e48f647372b1b7377248b1c24 (patch)
tree33cb8b10f334d8a9ab03e013c42f06ff9d9293c9 /fs/xfs/scrub
parentbb3fa72be19cdab77e76e3ead6fe171b279e968e (diff)
xfs: dump xfiles for debugging purposes
Add a debug function to dump an xfile's contents for debug purposes. Signed-off-by: Darrick J. Wong <djwong@kernel.org>
Diffstat (limited to 'fs/xfs/scrub')
-rw-r--r--fs/xfs/scrub/xfile.c100
-rw-r--r--fs/xfs/scrub/xfile.h2
2 files changed, 102 insertions, 0 deletions
diff --git a/fs/xfs/scrub/xfile.c b/fs/xfs/scrub/xfile.c
index 47bc47acf61d..027fce9cb9c4 100644
--- a/fs/xfs/scrub/xfile.c
+++ b/fs/xfs/scrub/xfile.c
@@ -343,3 +343,103 @@ xfile_stat(
statbuf->bytes = ks.blocks << SECTOR_SHIFT;
return 0;
}
+
+/* Dump an xfile to dmesg. */
+int
+xfile_dump(
+ struct xfile *xf)
+{
+ struct xfile_stat sb;
+ struct inode *inode = file_inode(xf->file);
+ struct address_space *mapping = inode->i_mapping;
+ loff_t holepos = 0;
+ loff_t datapos;
+ loff_t ret;
+ unsigned int pflags;
+ bool all_zeroes = true;
+ int error = 0;
+
+ error = xfile_stat(xf, &sb);
+ if (error)
+ return error;
+
+ printk(KERN_ALERT "xfile ino 0x%lx isize 0x%llx dump:", inode->i_ino,
+ sb.size);
+ pflags = memalloc_nofs_save();
+
+ while ((ret = vfs_llseek(xf->file, holepos, SEEK_DATA)) >= 0) {
+ datapos = rounddown_64(ret, PAGE_SIZE);
+ ret = vfs_llseek(xf->file, datapos, SEEK_HOLE);
+ if (ret < 0)
+ break;
+ holepos = min_t(loff_t, sb.size, roundup_64(ret, PAGE_SIZE));
+
+ while (datapos < holepos) {
+ struct page *page = NULL;
+ void *p, *kaddr;
+ u64 datalen = holepos - datapos;
+ unsigned int pagepos;
+ unsigned int pagelen;
+
+ cond_resched();
+
+ if (fatal_signal_pending(current)) {
+ error = -EINTR;
+ goto out_pflags;
+ }
+
+ pagelen = min_t(u64, datalen, PAGE_SIZE);
+
+ page = shmem_read_mapping_page_gfp(mapping,
+ datapos >> PAGE_SHIFT, __GFP_NOWARN);
+ if (IS_ERR(page)) {
+ error = PTR_ERR(page);
+ if (error != -ENOMEM)
+ goto out_pflags;
+
+ goto next_pgoff;
+ }
+
+ if (!PageUptodate(page))
+ goto next_page;
+ if (PageHWPoison(page)) {
+ printk(KERN_ALERT "%.8llx: poisoned",
+ datapos);
+ goto next_page;
+ }
+
+ kaddr = kmap_local_page(page);
+ p = kaddr;
+
+ for (pagepos = 0; pagepos < pagelen; pagepos += 16) {
+ char prefix[16];
+ unsigned int linelen;
+
+ linelen = min_t(unsigned int, pagelen, 16);
+
+ if (!memchr_inv(p + pagepos, 0, linelen))
+ continue;
+
+ snprintf(prefix, 16, "%.8llx: ",
+ datapos + pagepos);
+
+ all_zeroes = false;
+ print_hex_dump(KERN_ALERT, prefix,
+ DUMP_PREFIX_NONE, 16, 1,
+ p + pagepos, linelen, true);
+ }
+ kunmap_local(kaddr);
+next_page:
+ put_page(page);
+next_pgoff:
+ datapos += PAGE_SIZE;
+ }
+ }
+ if (all_zeroes)
+ printk(KERN_ALERT "<all zeroes>");
+ if (ret != -ENXIO)
+ error = ret;
+out_pflags:
+ memalloc_nofs_restore(pflags);
+ return error;
+}
diff --git a/fs/xfs/scrub/xfile.h b/fs/xfs/scrub/xfile.h
index 7bf5ab8f8502..93d277bb19a5 100644
--- a/fs/xfs/scrub/xfile.h
+++ b/fs/xfs/scrub/xfile.h
@@ -55,4 +55,6 @@ struct xfile_stat {
int xfile_stat(struct xfile *xf, struct xfile_stat *statbuf);
+int xfile_dump(struct xfile *xf);
+
#endif /* __XFS_SCRUB_XFILE_H__ */