diff --git a/c_defs_linux.go b/c_defs_linux.go index 0540772..561616c 100644 --- a/c_defs_linux.go +++ b/c_defs_linux.go @@ -72,6 +72,7 @@ package scoutfs // typedef struct scoutfs_ioctl_xattr_index_entry scoutfs_ioctl_xattr_index_entry_t; // typedef struct scoutfs_ioctl_read_xattr_index scoutfs_ioctl_read_xattr_index_t; // typedef struct scoutfs_ioctl_inode_attr_x scoutfs_ioctl_inode_attr_x_t; +// typedef struct scoutfs_ioctl_punch_offline scoutfs_ioctl_punch_offline_t; import "C" const IOCQUERYINODES = C.SCOUTFS_IOC_WALK_INODES @@ -122,6 +123,7 @@ const IOCIAXPROJECTID = C.SCOUTFS_IOC_IAX_PROJECT_ID const IOCIAXBITS = C.SCOUTFS_IOC_IAX__BITS const IOCGETATTRX = C.SCOUTFS_IOC_GET_ATTR_X const IOCSETATTRX = C.SCOUTFS_IOC_SET_ATTR_X +const IOCPUNCHOFFLINE = C.SCOUTFS_IOC_PUNCH_OFFLINE type InodesEntry C.scoutfs_ioctl_walk_inodes_entry_t type queryInodes C.scoutfs_ioctl_walk_inodes_t @@ -148,6 +150,7 @@ type getQuotaRules C.scoutfs_ioctl_get_quota_rules_t type indexEntry C.scoutfs_ioctl_xattr_index_entry_t type readXattrIndex C.scoutfs_ioctl_read_xattr_index_t type inodeAttrX C.scoutfs_ioctl_inode_attr_x_t +type punchOffline C.scoutfs_ioctl_punch_offline_t const sizeofstatfsMore = C.sizeof_scoutfs_ioctl_statfs_more_t const sizeofxattrTotal = C.sizeof_scoutfs_ioctl_xattr_total_t diff --git a/scoutfs.go b/scoutfs.go index 131e5ab..74ba189 100644 --- a/scoutfs.go +++ b/scoutfs.go @@ -905,11 +905,7 @@ func StageMoveAt(from, to *os.File, len, fromOffset, toOffset, version uint64) e } _, err := scoutfsctl(to, IOCMOVEBLOCKS, unsafe.Pointer(&mb)) - if err != nil { - return err - } - - return nil + return err } // XattrTotal has the total values matching id triple @@ -1807,3 +1803,30 @@ func (i indexEntry) increment() indexEntry { } return i } + +// PunchHole is a limited and specific version of hole punching. It's an +// archive layer operation that only converts unmapped offline extents +// into sparse extents. It is intended to be used when restoring sparse +// files after the initial creation set the entire file size offline. +// +// The offset and len fields are in units of bytes and must be aligned +// to the small (4KiB) block size. All regions of offline extents +// covered by the region will be converted into sparse online extents, +// including regions that straddle the boundaries of the region. Any +// existing sparse extents in the region are ignored. +// +// The data_version must match the inode or EINVAL is returned. The +// data_version is not modified by this operation. +// +// EINVAL is returned if any mapped extents are found in the region. If +// an error is returned then partial progress may have been made. +func PunchHole(f *os.File, length, offset, version uint64) error { + po := punchOffline{ + Offset: offset, + Len: length, + Version: version, + } + + _, err := scoutfsctl(f, IOCPUNCHOFFLINE, unsafe.Pointer(&po)) + return err +} diff --git a/scoutfsdefs.go b/scoutfsdefs.go index b280246..552edb7 100644 --- a/scoutfsdefs.go +++ b/scoutfsdefs.go @@ -51,6 +51,7 @@ const IOCIAXPROJECTID = 0x200 const IOCIAXBITS = 0x100 const IOCGETATTRX = 0x4068e812 const IOCSETATTRX = 0x4068e813 +const IOCPUNCHOFFLINE = 0x4020e818 type InodesEntry struct { Major uint64 @@ -241,6 +242,12 @@ type inodeAttrX struct { Bits uint64 Project_id uint64 } +type punchOffline struct { + Offset uint64 + Len uint64 + Version uint64 + Flags uint64 +} const sizeofstatfsMore = 0x30 const sizeofxattrTotal = 0x28