Skip to contentSkip to conversation

FIEMAP and disk sync issues

RFC In review Vladimir 'φ-coder/phcoder' Serbinenko 3 participants 6 messages Jan 27, 2012 – Jan 30, 2012 VFS

lore
Share & tools
lore
#0 lore raw

RFC 1/1 FIEMAP and disk sync issues

Hello, all. When someone installs using blocklists (discouraged and unreliable), we use GRUB internal fs reader in order to determine core.img blocklists. With Linux we call fsync and an ioctl on partition in order to flush the cache. I also tried adding "sync" which didn't make any difference. Unfortunately it doesn't seem to be good enough on some filesystems e.g. ext2 (ext3 and ext4 seem to work).
Does anyone know how to ensure flush of a file AND of all filesystem metadata needed to read it?
Alternatively we can ask Linux itself to tell us the blocks the file resides in. There are 2 ioctls for this: FIBMAP and FIEMAP. FIBMAP is unfortunately limited to 32-bit blocks. Most of FS supported by both GRUB and Linux lack FIEMAP. If we exclude the 32-bit fs (which will work fine with FIBMAP as long as it uses the same block size as underlying FS, which seems reasonable but I haven't verified it) (minix1/2/3, reiserfs, hfs, jfs, udf, fat, affs) and read-only filesystems (unsuitable for install) (iso9660, romfs, squash4), the remaining trouble is NTFS and HFS+. So with this approach we'll be unable to install on >2TiB HFS+ or NTFS filesystems. I see following possibilities:
- Someone write fiemap support for HFS+ and NTFS. This would be probably the best approach
- We find a way to flush disk reliably. This would eliminate the necessity of having different branches for Linux and rest.
- Ask Linux devs if they are willing to provide FIBMAP64 since internally 64-bits are used.
Another problem with FIBMAP/FIEMAP is that fuse-mounted BFS lacks them altogether. We will need to find some other way of doing BFS install.
Also some COW filesystems may supply a somewhat valid blocklist with FIBMAP/FIEMAP but which is unusable to GRUB because of COW nature. So we need an FS-whitelist.
Experiment patch attached.
Any thoughts?

Signature · 2 lines
Regards
Vladimir 'φ-coder/phcoder' Serbinenko

=== modified file 'grub-core/fs/affs.c'

fs/affs.c +1 -0
@@ -571,6 +571,7 @@
     .label = grub_affs_label,
 #ifdef GRUB_UTIL
     .reserved_first_sector = 0,
+    .blocklist_install = 1,
 #endif
     .next = 0
   };

=== modified file 'grub-core/fs/bfs.c'

fs/bfs.c +1 -0
@@ -1026,6 +1026,7 @@
 #endif
 #ifdef GRUB_UTIL
   .reserved_first_sector = 1,
+  .blocklist_install = 1,
 #endif
 };
 

=== modified file 'grub-core/fs/btrfs.c'

fs/btrfs.c +1 -0
@@ -1653,6 +1653,7 @@
 #ifdef GRUB_UTIL
   .embed = grub_btrfs_embed,
   .reserved_first_sector = 1,
+  .blocklist_install = 0,
 #endif
 };
 

=== modified file 'grub-core/fs/cpio.c'

fs/cpio.c +1 -0
@@ -714,6 +714,7 @@
   .close = grub_cpio_close,
 #ifdef GRUB_UTIL
   .reserved_first_sector = 0,
+  .blocklist_install = 0,
 #endif
 };
 

=== modified file 'grub-core/fs/ext2.c'

fs/ext2.c +1 -0
@@ -971,6 +971,7 @@
     .mtime = grub_ext2_mtime,
 #ifdef GRUB_UTIL
     .reserved_first_sector = 1,
+    .blocklist_install = 1,
 #endif
     .next = 0
   };

=== modified file 'grub-core/fs/fat.c'

fs/fat.c +1 -0
@@ -1158,6 +1158,7 @@
 #else
     .reserved_first_sector = 1,
 #endif
+    .blocklist_install = 1,
 #endif
     .next = 0
   };

=== modified file 'grub-core/fs/hfs.c'

fs/hfs.c +4 -0
@@ -1356,6 +1356,10 @@
     .label = grub_hfs_label,
     .uuid = grub_hfs_uuid,
     .mtime = grub_hfs_mtime,
+#ifdef GRUB_UTIL
+    .reserved_first_sector = 1,
+    .blocklist_install = 1,
+#endif
     .next = 0
   };
 

=== modified file 'grub-core/fs/hfsplus.c'

fs/hfsplus.c +1 -0
@@ -1084,6 +1084,7 @@
     .uuid = grub_hfsplus_uuid,
 #ifdef GRUB_UTIL
     .reserved_first_sector = 1,
+    .blocklist_install = 1,
 #endif
     .next = 0
   };

=== modified file 'grub-core/fs/iso9660.c'

fs/iso9660.c +4 -0
@@ -1092,6 +1092,10 @@
     .label = grub_iso9660_label,
     .uuid = grub_iso9660_uuid,
     .mtime = grub_iso9660_mtime,
+#ifdef GRUB_UTIL
+    .reserved_first_sector = 1,
+    .blocklist_install = 1,
+#endif
     .next = 0
   };
 

=== modified file 'grub-core/fs/jfs.c'

fs/jfs.c +4 -0
@@ -906,6 +906,10 @@
     .close = grub_jfs_close,
     .label = grub_jfs_label,
     .uuid = grub_jfs_uuid,
+#ifdef GRUB_UTIL
+    .reserved_first_sector = 1,
+    .blocklist_install = 1,
+#endif
     .next = 0
   };
 

=== modified file 'grub-core/fs/minix.c'

fs/minix.c +4 -0
@@ -653,6 +653,10 @@
     .open = grub_minix_open,
     .read = grub_minix_read,
     .close = grub_minix_close,
+#ifdef GRUB_UTIL
+    .reserved_first_sector = 1,
+    .blocklist_install = 1,
+#endif
     .next = 0
   };
 

=== modified file 'grub-core/fs/nilfs2.c'

fs/nilfs2.c +1 -0
@@ -1178,6 +1178,7 @@
   .mtime = grub_nilfs2_mtime,
 #ifdef GRUB_UTIL
   .reserved_first_sector = 1,
+  .blocklist_install = 0,
 #endif
   .next = 0
 };

=== modified file 'grub-core/fs/ntfs.c'

fs/ntfs.c +1 -0
@@ -1248,6 +1248,7 @@
     .uuid = grub_ntfs_uuid,
 #ifdef GRUB_UTIL
     .reserved_first_sector = 1,
+    .blocklist_install = 1,
 #endif
     .next = 0
 };

=== modified file 'grub-core/fs/reiserfs.c'

fs/reiserfs.c +4 -0
@@ -1387,6 +1387,10 @@
     .close = grub_reiserfs_close,
     .label = grub_reiserfs_label,
     .uuid = grub_reiserfs_uuid,
+#ifdef GRUB_UTIL
+    .reserved_first_sector = 1,
+    .blocklist_install = 1,
+#endif
     .next = 0
   };
 

=== modified file 'grub-core/fs/romfs.c'

fs/romfs.c +1 -0
@@ -452,6 +452,7 @@
     .label = grub_romfs_label,
 #ifdef GRUB_UTIL
     .reserved_first_sector = 0,
+    .blocklist_install = 0,
 #endif
     .next = 0
   };

=== modified file 'grub-core/fs/sfs.c'

fs/sfs.c +1 -0
@@ -616,6 +616,7 @@
     .label = grub_sfs_label,
 #ifdef GRUB_UTIL
     .reserved_first_sector = 0,
+    .blocklist_install = 1,
 #endif
     .next = 0
   };

=== modified file 'grub-core/fs/squash4.c'

fs/squash4.c +1 -0
@@ -935,6 +935,7 @@
     .mtime = grub_squash_mtime,
 #ifdef GRUB_UTIL
     .reserved_first_sector = 0,
+    .blocklist_install = 0,
 #endif
     .next = 0
   };

=== modified file 'grub-core/fs/udf.c'

fs/udf.c +4 -0
@@ -1097,6 +1097,10 @@
   .read = grub_udf_read,
   .close = grub_udf_close,
   .label = grub_udf_label,
+#ifdef GRUB_UTIL
+  .reserved_first_sector = 1,
+  .blocklist_install = 1,
+#endif
   .next = 0
 };
 

=== modified file 'grub-core/fs/ufs.c'

fs/ufs.c +4 -0
@@ -792,6 +792,10 @@
     .label = grub_ufs_label,
     .uuid = grub_ufs_uuid,
     .mtime = grub_ufs_mtime,
+    /* FIXME: set reserved_first_sector.  */
+#ifdef GRUB_UTIL
+    .blocklist_install = 1,
+#endif
     .next = 0
   };
 

=== modified file 'grub-core/fs/xfs.c'

fs/xfs.c +1 -0
@@ -884,6 +884,7 @@
     .uuid = grub_xfs_uuid,
 #ifdef GRUB_UTIL
     .reserved_first_sector = 0,
+    .blocklist_install = 1,
 #endif
     .next = 0
   };

=== modified file 'grub-core/fs/zfs/zfs.c'

fs/zfs/zfs.c +1 -0
@@ -3931,6 +3931,7 @@
 #ifdef GRUB_UTIL
   .embed = grub_zfs_embed,
   .reserved_first_sector = 1,
+  .blocklist_install = 0,
 #endif
   .next = 0
 };

=== modified file 'include/grub/fs.h'

grub/fs.h +3 -0
@@ -86,6 +86,9 @@
 
   /* Whether this filesystem reserves first sector for DOS-style boot.  */
   int reserved_first_sector;
+
+  /* Whether blocklist installs have a chance to work.  */
+  int blocklist_install;
 #endif
 };
 typedef struct grub_fs *grub_fs_t;

=== modified file 'util/grub-setup.c'

grub-setup.c +224 -23

321 lines not on this page · raw message

#1 lore raw

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 6 lines · Vladimir 'φ-coder/phcoder' Serbinenko

Hello, all. When someone installs using blocklists (discouraged and unreliable), we use GRUB internal fs reader in order to determine core.img blocklists. With Linux we call fsync and an ioctl on partition in order to flush the cache. I also tried adding "sync" which didn't make any difference. Unfortunately it doesn't seem to be good enough on

By "sync" you mean running the sync command? If so, that absolutely, positively should flush everything to disk. If it isn't then there's a major kernel bug. An fsync() on the core.img file ( not the partition device ) also should flush everything needed to find that file, without flushing everything else that isn't.

Doing an fsync() on the partition device will flush buffers from a process directly opening the block dev and performing IO there, not the buffers for files within the filesystem on that block device. IIRC, ext2 uses the block buffers for directory access so that partition fsync will flush directories, but ext3 and ext4 do not.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJPIvUhAAoJEJrBOlT6nu75ZSwH/2vgqHY3L+9xPGAsMDMzelAq ae6P0aKgqEsZPEiTDx6+sBNE9uvJO6va5mKv9eyvDhpmKeq64mLa3EDJBKUmnSL+ E/b/cAAYPV7RaJ7Rc3tUNa96PRC8rOPyOcGeOVQxqjFS5rmZOa4p+wrO3YitqIGR IUD7HSN8wt4PtmeS8thRXQPhcSICQwPy8rg4QVq2mFHxFws/WALAr7p5uVu/SH2Q E8lXARKdvqd6HPjxlo7A/WeDEVvRd25eb84vX33wAhaauAI9VFD2+eCWR5ayyVUe aymZ+DNyXpenEGK5JDdW38ovmAwIsWI+LbWVCh/gInEfHJkDVqN9XogtmCc9S68= =3Yxi
-----END PGP SIGNATURE-----

#2 lore raw

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

It looks like BLKFLSBUF also should do the trick. That appears to both tell the fs ( if one is mounted ) to sync, and flush the dirty block buffers like fsync() on the blockdev does.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJPIxxOAAoJEJrBOlT6nu75yMkIAKCDIhGFevEuEDsOxoIXWH88 /i9Txf5fpDiwDRp+ryU194pCfHoZXxZ1/7gkqTVhj9TEVpqGtXlYL6JdwSHbUWeJ +RCzrxEoVHLlAKxoTFrjZQorM+fKe0rleibAa9vGu98XzBvXCGiD8B1n/Mv2f6LT HbRsYs1IFEeF/YfH3d+nbjInQZQgTvGu5lnltBFsHr/V892q7Wqs5WuT/oqRMfvw L2g90Ft9YmfgwItbmAmhfPtFayus4TrOhXHSCCj4JsDEjeZpdNSnEJs/QrlqcYHU xRjKz9DG//1RncTpXun9C8ikpez66RT1voOL0v8xR5f8QPaJ68w1+1lTA+Hxtj0= =n8zF
-----END PGP SIGNATURE-----

#3 lore raw
In reply to Phillip Susi
Quoted 11 lines · Phillip Susi

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Quoted 6 lines · Vladimir 'φ-coder/phcoder' Serbinenko

Hello, all. When someone installs using blocklists (discouraged and unreliable), we use GRUB internal fs reader in order to determine core.img blocklists. With Linux we call fsync and an ioctl on partition in order to flush the cache. I also tried adding "sync" which didn't make any difference. Unfortunately it doesn't seem to be good enough on

By "sync" you mean running the sync command?

Actually the sync () call

Quoted 5 lines

If so, that absolutely,
positively should flush everything to disk. If it isn't then there's a major kernel bug. An fsync() on the core.img file ( not the partition device ) also should flush everything needed to find that file, without flushing everything else that isn't.

I'll recheck. But considering that I ran into some data loss it's possible that I have some kind of hardware or software failure (most likely because of new kernel and xen tests). Busy now doing the backups in case it gets worse

Quoted 19 lines

Doing an fsync() on the partition device will flush buffers from a process directly opening the block dev and performing IO there, not the buffers for files within the filesystem on that block device. IIRC, ext2 uses the block buffers for directory access so that partition fsync will flush directories, but ext3 and ext4 do not.

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.17 (MingW32)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJPIvUhAAoJEJrBOlT6nu75ZSwH/2vgqHY3L+9xPGAsMDMzelAq ae6P0aKgqEsZPEiTDx6+sBNE9uvJO6va5mKv9eyvDhpmKeq64mLa3EDJBKUmnSL+ E/b/cAAYPV7RaJ7Rc3tUNa96PRC8rOPyOcGeOVQxqjFS5rmZOa4p+wrO3YitqIGR IUD7HSN8wt4PtmeS8thRXQPhcSICQwPy8rg4QVq2mFHxFws/WALAr7p5uVu/SH2Q E8lXARKdvqd6HPjxlo7A/WeDEVvRd25eb84vX33wAhaauAI9VFD2+eCWR5ayyVUe aymZ+DNyXpenEGK5JDdW38ovmAwIsWI+LbWVCh/gInEfHJkDVqN9XogtmCc9S68= =3Yxi
-----END PGP SIGNATURE-----

Signature · 2 lines
Regards
Vladimir 'φ-coder/phcoder' Serbinenko
#4 lore raw
In reply to Vladimir 'φ-coder/phcoder' Serbinenko
Quoted 7 lines · Vladimir 'φ-coder/phcoder' Serbinenko

Another problem with FIBMAP/FIEMAP is that fuse-mounted BFS lacks them altogether. We will need to find some other way of doing BFS install. Also some COW filesystems may supply a somewhat valid blocklist with FIBMAP/FIEMAP but which is unusable to GRUB because of COW nature. So we need an FS-whitelist.
Experiment patch attached.
Any thoughts?

The fuse/lowlevel.h has:

/**
* Map block index within file to block index within device *
* Note: This makes sense only for block device backed filesystems
* mounted with the 'blkdev' option
*
* Introduced in version 2.6
*
* Valid replies:
* fuse_reply_bmap
* fuse_reply_err
*
* @param req request handle
* @param ino the inode number
* @param blocksize unit of block index
* @param idx block index within file
*/
void (*bmap) (fuse_req_t req, fuse_ino_t ino, size_t blocksize,
uint64_t idx);

/**
* Reply with block index
*
* Possible requests:
* bmap
*
* @param req request handle
* @param idx block index within device
* @return zero for success, -errno for failure to send reply */
int fuse_reply_bmap(fuse_req_t req, uint64_t idx);

So it is a matter of implementing the right callback in BFS to support FIBMAP/FIEMAP. Same for ntfs3g.

MfG
Goswin

#5 lore raw
Quoted 4 lines

So it is a matter of implementing the right callback in BFS to support FIBMAP/FIEMAP. Same for ntfs3g.

ntfs3g does implement bmap. Problem is that the only way to access this from userspace is FIBMAP which cuts to 32-bits. FIEMAP is implemented as a different ioctl rather than piggybacking on bmap.

Signature · 2 lines
Regards
Vladimir 'φ-coder/phcoder' Serbinenko