Skip to content

Commit

Permalink
5692 expose the number of hole blocks in a file
Browse files Browse the repository at this point in the history
Reviewed by: Adam Leventhal <[email protected]>
Reviewed by: Matthew Ahrens <[email protected]>
Reviewed by: Boris Protopopov <[email protected]>
Approved by: Richard Lowe <[email protected]>
  • Loading branch information
Max Grossman authored and ahrens committed Apr 5, 2015
1 parent a45f1c3 commit 2bcf024
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 17 deletions.
4 changes: 3 additions & 1 deletion usr/src/lib/libzfs/common/libzfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013 by Delphix. All rights reserved.
* Copyright (c) 2014 by Delphix. All rights reserved.
* Copyright (c) 2012, Joyent, Inc. All rights reserved.
* Copyright (c) 2013 Steven Hartland. All rights reserved.
* Copyright 2013 Nexenta Systems, Inc. All rights reserved.
Expand Down Expand Up @@ -764,6 +764,8 @@ extern boolean_t libzfs_fru_compare(libzfs_handle_t *, const char *,
extern boolean_t libzfs_fru_notself(libzfs_handle_t *, const char *);
extern int zpool_fru_set(zpool_handle_t *, uint64_t, const char *);

extern int zfs_get_hole_count(const char *, uint64_t *, uint64_t *);

#ifdef __cplusplus
}
#endif
Expand Down
49 changes: 48 additions & 1 deletion usr/src/lib/libzfs/common/libzfs_util.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
/*
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, Joyent, Inc. All rights reserved.
* Copyright (c) 2012 by Delphix. All rights reserved.
* Copyright (c) 2014 by Delphix. All rights reserved.
*/

/*
Expand All @@ -39,6 +39,7 @@
#include <unistd.h>
#include <ctype.h>
#include <math.h>
#include <sys/filio.h>
#include <sys/mnttab.h>
#include <sys/mntent.h>
#include <sys/types.h>
Expand Down Expand Up @@ -1499,3 +1500,49 @@ zprop_iter(zprop_func func, void *cb, boolean_t show_all, boolean_t ordered,
{
return (zprop_iter_common(func, cb, show_all, ordered, type));
}

/*
* zfs_get_hole_count retrieves the number of holes (blocks which are
* zero-filled) in the specified file using the _FIO_COUNT_FILLED ioctl. It
* also optionally fetches the block size when bs is non-NULL. With hole count
* and block size the full space consumed by the holes of a file can be
* calculated.
*
* On success, zero is returned, the count argument is set to the
* number of holes, and the bs argument is set to the block size (if it is
* not NULL). On error, a non-zero errno is returned and the values in count
* and bs are undefined.
*/
int
zfs_get_hole_count(const char *path, uint64_t *count, uint64_t *bs) {
int fd, err;
struct stat64 ss;
uint64_t fill;

fd = open(path, O_RDONLY | O_LARGEFILE);
if (fd == -1)
return (errno);

if (ioctl(fd, _FIO_COUNT_FILLED, &fill) == -1) {
err = errno;
(void) close(fd);
return (err);
}

if (fstat64(fd, &ss) == -1) {
err = errno;
(void) close(fd);
return (err);
}

*count = (ss.st_size + ss.st_blksize - 1) / ss.st_blksize - fill;
VERIFY3S(*count, >=, 0);
if (bs != NULL) {
*bs = ss.st_blksize;
}

if (close(fd) == -1) {
return (errno);
}
return (0);
}
1 change: 1 addition & 0 deletions usr/src/lib/libzfs/common/mapfile-vers
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ SYMBOL_VERSION SUNWprivate_1.1 {
zfs_expand_proplist;
zfs_get_handle;
zfs_get_holds;
zfs_get_hole_count;
zfs_get_name;
zfs_get_pool_handle;
zfs_get_user_props;
Expand Down
51 changes: 38 additions & 13 deletions usr/src/uts/common/fs/zfs/dmu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1811,25 +1811,20 @@ int
dmu_offset_next(objset_t *os, uint64_t object, boolean_t hole, uint64_t *off)
{
dnode_t *dn;
int i, err;
int err;

err = dnode_hold(os, object, FTAG, &dn);
if (err)
return (err);
/*
* Sync any current changes before
* we go trundling through the block pointers.
*/
for (i = 0; i < TXG_SIZE; i++) {
if (list_link_active(&dn->dn_dirty_link[i]))
break;
err = dmu_object_wait_synced(os, object);
if (err) {
return (err);
}
if (i != TXG_SIZE) {
dnode_rele(dn, FTAG);
txg_wait_synced(dmu_objset_pool(os), 0);
err = dnode_hold(os, object, FTAG, &dn);
if (err)
return (err);

err = dnode_hold(os, object, FTAG, &dn);
if (err) {
return (err);
}

err = dnode_next_offset(dn, (hole ? DNODE_FIND_HOLE : 0), off, 1, 1, 0);
Expand All @@ -1838,6 +1833,36 @@ dmu_offset_next(objset_t *os, uint64_t object, boolean_t hole, uint64_t *off)
return (err);
}

/*
* Given the ZFS object, if it contains any dirty nodes
* this function flushes all dirty blocks to disk. This
* ensures the DMU object info is updated. A more efficient
* future version might just find the TXG with the maximum
* ID and wait for that to be synced.
*/
int
dmu_object_wait_synced(objset_t *os, uint64_t object) {
dnode_t *dn;
int error, i;

error = dnode_hold(os, object, FTAG, &dn);
if (error) {
return (error);
}

for (i = 0; i < TXG_SIZE; i++) {
if (list_link_active(&dn->dn_dirty_link[i])) {
break;
}
}
dnode_rele(dn, FTAG);
if (i != TXG_SIZE) {
txg_wait_synced(dmu_objset_pool(os), 0);
}

return (0);
}

void
dmu_object_info_from_dnode(dnode_t *dn, dmu_object_info_t *doi)
{
Expand Down
9 changes: 9 additions & 0 deletions usr/src/uts/common/fs/zfs/sys/dmu.h
Original file line number Diff line number Diff line change
Expand Up @@ -903,6 +903,15 @@ int dmu_sync(struct zio *zio, uint64_t txg, dmu_sync_cb_t *done, zgd_t *zgd);
int dmu_offset_next(objset_t *os, uint64_t object, boolean_t hole,
uint64_t *off);

/*
* Check if a DMU object has any dirty blocks. If so, sync out
* all pending transaction groups. Otherwise, this function
* does not alter DMU state. This could be improved to only sync
* out the necessary transaction groups for this particular
* object.
*/
int dmu_object_wait_synced(objset_t *os, uint64_t object);

/*
* Initial setup and final teardown.
*/
Expand Down
47 changes: 47 additions & 0 deletions usr/src/uts/common/fs/zfs/zfs_vnops.c
Original file line number Diff line number Diff line change
Expand Up @@ -298,24 +298,31 @@ zfs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred,
int *rvalp, caller_context_t *ct)
{
offset_t off;
offset_t ndata;
dmu_object_info_t doi;
int error;
zfsvfs_t *zfsvfs;
znode_t *zp;

switch (com) {
case _FIOFFS:
{
return (zfs_sync(vp->v_vfsp, 0, cred));

/*
* The following two ioctls are used by bfu. Faking out,
* necessary to avoid bfu errors.
*/
}
case _FIOGDIO:
case _FIOSDIO:
{
return (0);
}

case _FIO_SEEK_DATA:
case _FIO_SEEK_HOLE:
{
if (ddi_copyin((void *)data, &off, sizeof (off), flag))
return (SET_ERROR(EFAULT));

Expand All @@ -333,6 +340,46 @@ zfs_ioctl(vnode_t *vp, int com, intptr_t data, int flag, cred_t *cred,
return (SET_ERROR(EFAULT));
return (0);
}
case _FIO_COUNT_FILLED:
{
/*
* _FIO_COUNT_FILLED adds a new ioctl command which
* exposes the number of filled blocks in a
* ZFS object.
*/
zp = VTOZ(vp);
zfsvfs = zp->z_zfsvfs;
ZFS_ENTER(zfsvfs);
ZFS_VERIFY_ZP(zp);

/*
* Wait for all dirty blocks for this object
* to get synced out to disk, and the DMU info
* updated.
*/
error = dmu_object_wait_synced(zfsvfs->z_os, zp->z_id);
if (error) {
ZFS_EXIT(zfsvfs);
return (error);
}

/*
* Retrieve fill count from DMU object.
*/
error = dmu_object_info(zfsvfs->z_os, zp->z_id, &doi);
if (error) {
ZFS_EXIT(zfsvfs);
return (error);
}

ndata = doi.doi_fill_count;

ZFS_EXIT(zfsvfs);
if (ddi_copyout(&ndata, (void *)data, sizeof (ndata), flag))
return (SET_ERROR(EFAULT));
return (0);
}
}
return (SET_ERROR(ENOTTY));
}

Expand Down
11 changes: 9 additions & 2 deletions usr/src/uts/common/sys/filio.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,13 @@
* contributors.
*/

/*
* Copyright (c) 2013 by Delphix. All rights reserved.
*/

#ifndef _SYS_FILIO_H
#define _SYS_FILIO_H

#pragma ident "%Z%%M% %I% %E% SMI"

/*
* General file ioctl definitions.
*/
Expand Down Expand Up @@ -137,6 +139,11 @@ extern "C" {
*/
#define _FIO_COMPRESSED _IO('f', 99) /* mark file as compressed */

/*
* Expose fill information through ioctl
*/
#define _FIO_COUNT_FILLED _IO('f', 100) /* count holes in a file */

#ifdef __cplusplus
}
#endif
Expand Down

0 comments on commit 2bcf024

Please sign in to comment.