Skip to content

Commit df1dc6e

Browse files
committed
Implement FileCompressionInformation for ZFS dataset compression
file_compression_information() now returns proper FILE_COMPRESSION_INFORMATION for files on compressed datasets. It uses os_compress (the dataset-level setting) rather than doi_compress (which is 0 for most files even when compression is active via inheritance), and reports physical block usage from doi_physical_blocks_512 as the CompressedFileSize. GetCompressedFileSize() correctly returns the physical compressed size via this handler. Explorer "Size on disk" continues to show the cluster-rounded logical size (computed from allocation unit size, not from FileCompressionInformation or AllocationSize). allocationsize() is moved out of the inline in zfs_windows.h into zfs_vnops_windows_lib.c so it can use zfs_blksz() with its fallback logic, fixing the case where z_blksz is 0 at open time. Signed-off-by: Jorgen Lundman <lundman@lundman.net>
1 parent eef5a99 commit df1dc6e

2 files changed

Lines changed: 64 additions & 35 deletions

File tree

include/os/windows/zfs/sys/zfs_windows.h

Lines changed: 1 addition & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -140,23 +140,7 @@ extern NTSTATUS zfsdev_release(dev_t dev, PIRP Irp);
140140
extern int zfs_vnop_recycle(znode_t *zp, int force);
141141
extern uint64_t zfs_blksz(znode_t *zp);
142142

143-
inline static uint64_t
144-
allocationsize(struct znode *zp)
145-
{
146-
if (S_ISDIR(zp->z_mode))
147-
return (0ULL);
148-
149-
if (zp->z_size == 0) {
150-
// Did they prealloc?
151-
struct vnode *vp = ZTOV(zp);
152-
if ((vp != NULL) &&
153-
(vp->FileHeader.AllocationSize.QuadPart > 0ULL))
154-
return (vp->FileHeader.AllocationSize.QuadPart);
155-
return (0ULL);
156-
}
157-
158-
return (P2ROUNDUP(zp->z_size, zfs_blksz(zp)));
159-
}
143+
extern uint64_t allocationsize(struct znode *zp);
160144

161145
extern int zfs_vnop_mount(PDEVICE_OBJECT DiskDevice, PIRP Irp,
162146
PIO_STACK_LOCATION IrpSp);

module/os/windows/zfs/zfs_vnops_windows_lib.c

Lines changed: 63 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4853,35 +4853,63 @@ NTSTATUS
48534853
file_compression_information(PDEVICE_OBJECT DeviceObject, PIRP Irp,
48544854
PIO_STACK_LOCATION IrpSp, FILE_COMPRESSION_INFORMATION *fci)
48554855
{
4856-
dprintf(" %s\n", __func__);
4857-
48584856
if (IrpSp->Parameters.QueryFile.Length <
48594857
sizeof (FILE_COMPRESSION_INFORMATION)) {
48604858
Irp->IoStatus.Information =
48614859
sizeof (FILE_COMPRESSION_INFORMATION);
48624860
return (STATUS_BUFFER_TOO_SMALL);
48634861
}
48644862

4865-
if (IrpSp->FileObject && IrpSp->FileObject->FsContext) {
4866-
struct vnode *vp = IrpSp->FileObject->FsContext;
4867-
if (VN_HOLD(vp) == 0) {
4868-
znode_t *zp = VTOZ(vp);
4869-
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
4870-
4871-
memset(fci, 0, sizeof (FILE_COMPRESSION_INFORMATION));
4863+
if (IrpSp->FileObject == NULL ||
4864+
IrpSp->FileObject->FsContext == NULL)
4865+
return (STATUS_INVALID_PARAMETER);
48724866

4873-
// Deal with ads here, and send adsdata.length
4874-
if (vnode_isdir(vp))
4875-
fci->CompressedFileSize.QuadPart = zp->z_size;
4867+
struct vnode *vp = IrpSp->FileObject->FsContext;
4868+
if (VN_HOLD(vp) != 0)
4869+
return (STATUS_INVALID_PARAMETER);
48764870

4877-
VN_RELE(vp);
4878-
}
4879-
Irp->IoStatus.Information =
4880-
sizeof (FILE_COMPRESSION_INFORMATION);
4881-
return (STATUS_SUCCESS);
4871+
znode_t *zp = VTOZ(vp);
4872+
memset(fci, 0, sizeof (FILE_COMPRESSION_INFORMATION));
4873+
4874+
dmu_object_info_t doi;
4875+
boolean_t compressed = B_FALSE;
4876+
uint64_t phys_bytes = 0;
4877+
4878+
objset_t *os = zp->z_zfsvfs->z_os;
4879+
boolean_t ds_compressed = (os != NULL &&
4880+
os->os_compress != ZIO_COMPRESS_OFF &&
4881+
os->os_compress != ZIO_COMPRESS_EMPTY);
4882+
4883+
if (zp->z_sa_hdl != NULL) {
4884+
4885+
dmu_object_info_from_db(sa_get_db(zp->z_sa_hdl), &doi);
4886+
compressed = ds_compressed;
4887+
phys_bytes = doi.doi_physical_blocks_512 * 512ULL;
4888+
fci->CompressedFileSize.QuadPart =
4889+
(int64_t)(compressed ? phys_bytes : zp->z_size);
4890+
fci->CompressionFormat = compressed ?
4891+
COMPRESSION_FORMAT_DEFAULT : COMPRESSION_FORMAT_NONE;
4892+
/*
4893+
* CompressionUnitShift: log2 of the compression unit size.
4894+
* highbit64 returns 1-based position of highest set bit, so
4895+
* subtract 1 to get log2.
4896+
*/
4897+
fci->CompressionUnitShift =
4898+
(UCHAR)(highbit64(doi.doi_data_block_size) - 1);
4899+
fci->ChunkShift = fci->CompressionUnitShift;
4900+
fci->ClusterShift = fci->CompressionUnitShift;
4901+
} else {
4902+
/* Fallback: no object info, report uncompressed */
4903+
fci->CompressedFileSize.QuadPart = (int64_t)zp->z_size;
48824904
}
48834905

4884-
return (STATUS_INVALID_PARAMETER);
4906+
dprintf("%s: phys=%llu logical=%llu fmt=%u\n", __func__,
4907+
(unsigned long long)phys_bytes,
4908+
(unsigned long long)zp->z_size, fci->CompressionFormat);
4909+
4910+
VN_RELE(vp);
4911+
Irp->IoStatus.Information = sizeof (FILE_COMPRESSION_INFORMATION);
4912+
return (STATUS_SUCCESS);
48854913
}
48864914

48874915
uint64_t
@@ -4902,6 +4930,23 @@ zfs_blksz(znode_t *zp)
49024930
return (512ULL);
49034931
}
49044932

4933+
uint64_t
4934+
allocationsize(znode_t *zp)
4935+
{
4936+
if (S_ISDIR(zp->z_mode))
4937+
return (0ULL);
4938+
4939+
if (zp->z_size == 0) {
4940+
struct vnode *vp = ZTOV(zp);
4941+
if (vp != NULL &&
4942+
vp->FileHeader.AllocationSize.QuadPart > 0ULL)
4943+
return (vp->FileHeader.AllocationSize.QuadPart);
4944+
return (0ULL);
4945+
}
4946+
4947+
return (P2ROUNDUP(zp->z_size, zfs_blksz(zp)));
4948+
}
4949+
49054950
void
49064951
file_standard_information_impl(PDEVICE_OBJECT DeviceObject,
49074952
PFILE_OBJECT FileObject, FILE_STANDARD_INFORMATION *fsi,

0 commit comments

Comments
 (0)