* mode == 0 (which is standard prealloc) and PUNCH is supported
* Rest of mode options are not supported yet.
*/
- if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
+ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
+ FALLOC_FL_ZERO_RANGE))
RETURN(-EOPNOTSUPP);
ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_FALLOCATE, 1);
__u64 size = io->u.ci_setattr.sa_attr.lvb_size;
unsigned int ia_avalid = io->u.ci_setattr.sa_avalid;
enum op_xvalid ia_xvalid = io->u.ci_setattr.sa_xvalid;
- int rc;
+ int rc = 0;
/* silently ignore non-truncate setattr for Data-on-MDT object */
if (cl_io_is_trunc(io)) {
/* truncate cache dirty pages first */
rc = osc_cache_truncate_start(env, cl2osc(obj), size,
&oio->oi_trunc);
- if (rc < 0)
- return rc;
} else if (cl_io_is_fallocate(io) &&
- io->u.ci_setattr.sa_falloc_mode & FALLOC_FL_PUNCH_HOLE) {
+ (io->u.ci_setattr.sa_falloc_mode &
+ (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE))) {
rc = osc_punch_start(env, io, obj);
- if (rc < 0)
- return rc;
}
+ if (rc < 0)
+ return rc;
if (oio->oi_lockless == 0) {
cl_object_attr_lock(obj);
* mode == 0 (which is standard prealloc) and PUNCH is supported
* Rest of mode options are not supported yet.
*/
- if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
+ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
+ FALLOC_FL_ZERO_RANGE))
RETURN(-EOPNOTSUPP);
if (mode & FALLOC_FL_PUNCH_HOLE && !(mode & FALLOC_FL_KEEP_SIZE)) {
* mode == 0 (which is standard prealloc) and PUNCH is supported
* Rest of mode options are not supported yet.
*/
- if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
+ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
+ FALLOC_FL_ZERO_RANGE))
RETURN(-EOPNOTSUPP);
/* PUNCH_HOLE mode should always be accompanied with KEEP_SIZE flag
if (cl_io_is_trunc(io))
result = osc_cache_truncate_start(env, cl2osc(obj), size,
&oio->oi_trunc);
- /* flush local pages prior punching them on server */
+ /* flush local pages prior punching/zero-range them on server */
if (io_is_falloc &&
- io->u.ci_setattr.sa_falloc_mode & FALLOC_FL_PUNCH_HOLE)
+ (io->u.ci_setattr.sa_falloc_mode &
+ (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)))
result = osc_punch_start(env, io, obj);
if (result == 0 && oio->oi_lockless == 0) {
int tl_mode;
bool tl_shared;
bool tl_truncate;
- bool tl_punch;
+ bool tl_fallocate;
};
struct osd_thandle {
* \param pos byte offset of IO start
* \param len number of bytes of IO
* \param lnb array of extents undergoing IO
+ * \param maxlnb max pages could be loaded
* \param rw read or write operation, and other flags
- * \param capa capabilities
*
* \retval pages (zero or more) loaded successfully
* \retval -ENOMEM on memory/page allocation error
ENTRY;
/*
- * mode == 0 (which is standard prealloc) and PUNCH is supported
+ * mode == 0 (which is standard prealloc) and PUNCH/ZERO is supported
* Rest of mode options is not supported yet.
*/
- if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE))
+ if (mode & ~(FALLOC_FL_KEEP_SIZE | FALLOC_FL_PUNCH_HOLE |
+ FALLOC_FL_ZERO_RANGE))
+ RETURN(-EOPNOTSUPP);
+
+ /* TODO: should fix this for DoM/Indirect in another patch */
+ if ((mode & FALLOC_FL_ZERO_RANGE) &&
+ !ldiskfs_test_inode_flag(inode, LDISKFS_INODE_EXTENTS))
RETURN(-EOPNOTSUPP);
/* disable fallocate completely */
RETURN(rc);
}
-static int osd_fallocate_punch(const struct lu_env *env, struct dt_object *dt,
- __u64 start, __u64 end, int mode,
- struct thandle *th)
+static int osd_fallocate_advance(const struct lu_env *env, struct dt_object *dt,
+ __u64 start, __u64 end, int mode,
+ struct thandle *th)
{
struct osd_object *obj = osd_dt_obj(dt);
struct inode *inode = obj->oo_inode;
continue;
LASSERT(al->tl_shared == 0);
found = 1;
- /* do actual punch in osd_trans_stop() */
+ /* do actual punch/zero in osd_trans_stop() */
al->tl_start = start;
al->tl_end = end;
al->tl_mode = mode;
- al->tl_punch = true;
+ al->tl_fallocate = true;
break;
}
ENTRY;
- if (mode & FALLOC_FL_PUNCH_HOLE) {
- /* punch */
- rc = osd_fallocate_punch(env, dt, start, end, mode, th);
+ if (mode & (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_ZERO_RANGE)) {
+ /* punch/zero-range */
+ rc = osd_fallocate_advance(env, dt, start, end, mode, th);
} else {
/* standard preallocate */
rc = osd_fallocate_preallocate(env, dt, start, end, mode, th);
osd_partial_page_flush(d, inode, size);
}
-static int osd_execute_punch(const struct lu_env *env, struct osd_object *obj,
- loff_t start, loff_t end, int mode)
+static int osd_execute_fallocate(const struct lu_env *env,
+ struct osd_object *obj, loff_t start,
+ loff_t end, int mode)
{
struct osd_device *d = osd_obj2dev(obj);
struct inode *inode = obj->oo_inode;
continue;
if (al->tl_truncate)
osd_execute_truncate(al->tl_obj);
- else if (al->tl_punch)
- rc = osd_execute_punch(env, al->tl_obj, al->tl_start,
- al->tl_end, al->tl_mode);
+ else if (al->tl_fallocate)
+ rc = osd_execute_fallocate(env, al->tl_obj,
+ al->tl_start, al->tl_end,
+ al->tl_mode);
}
return rc;
}
run_test 150h "Verify extend fallocate updates the file size"
+test_150ia() {
+ (( $MDS1_VERSION >= $(version_code 2.16.50) )) ||
+ skip "need MDS1 version >= 2.16.50 for falloc zero-range"
+
+ if [[ "$ost1_FSTYPE" = "zfs" || "$mds1_FSTYPE" = "zfs" ]]; then
+ skip "zero-range mode is not implemented on OSD ZFS"
+ fi
+
+ check_set_fallocate_or_skip
+ stack_trap "rm -f $DIR/$tfile; wait_delete_completed"
+
+ echo "Verify fallocate(zero): range within the file"
+ yes 'A' | dd of=$DIR/$tfile bs=$PAGE_SIZE count=8 ||
+ error "dd failed for bs 4096 and count 8"
+
+ # zero range page aligned
+ local offset=$((2 * PAGE_SIZE))
+ local length=$((4 * PAGE_SIZE))
+ out=$(fallocate -z --offset $offset -l $length $DIR/$tfile 2>&1) ||
+ skip_eopnotsupp "$out|falloc(zero): off $offset, len $length"
+
+ # precomputed md5sum
+ local expect="f6b2adb9a352ee2b9d1f54a629e7998c"
+ cksum=($(md5sum $DIR/$tfile))
+ [[ "${cksum[0]}" == "$expect" ]] ||
+ error "unexpected MD5SUM after zero: ${cksum[0]}"
+
+ # zero range partial page
+ local offset=2000
+ local length=1000
+ out=$(fallocate -z --offset $offset -l $length $DIR/$tfile 2>&1) ||
+ skip_eopnotsupp "$out|falloc(zero): off $offset, len $length"
+
+ expect="19912462c2a304a225df656b80844ba5"
+ cksum=($(md5sum $DIR/$tfile))
+ [[ "${cksum[0]}" == "$expect" ]] ||
+ error "unexpected MD5SUM after zero(partial): ${cksum[0]}"
+}
+run_test 150ia "Verify fallocate zero-range ZERO functionality"
+
+test_150ib() {
+ (( $MDS1_VERSION >= $(version_code 2.16.50) )) ||
+ skip "need MDS1 version >= 2.16.50 for falloc zero-range"
+
+ if [[ "$ost1_FSTYPE" = "zfs" || "$mds1_FSTYPE" = "zfs" ]]; then
+ skip "zero-range mode is not implemented on OSD ZFS"
+ fi
+
+ check_set_fallocate_or_skip
+ stack_trap "rm -f $DIR/$tfile; wait_delete_completed"
+
+ local blocks_after_punch=$((4 * PAGE_SIZE / 512))
+ local blocks_after_zero_fill=$((8 * PAGE_SIZE / 512))
+ local blocks_after_extend=$((16 * PAGE_SIZE / 512))
+ local expect_len=$((8 * PAGE_SIZE))
+
+ # file size [0, 32K)
+ echo "Verify fallocate(zero): range within the file"
+ yes 'A' | dd of=$DIR/$tfile bs=$PAGE_SIZE count=8 ||
+ error "dd failed for bs 4096 and count 8"
+
+ # punch across [8K,24K)
+ local offset=$((2 * PAGE_SIZE))
+ local length=$((4 * PAGE_SIZE))
+ out=$(fallocate -p --offset $offset -l $length $DIR/$tfile 2>&1) ||
+ skip_eopnotsupp "$out|falloc(zero): off $offset, len $length"
+
+ # Verify punch worked as expected
+ blocks=$(stat -c '%b' $DIR/$tfile)
+ (( blocks == blocks_after_punch )) ||
+ error "punch failed:$blocks!=$blocks_after_punch"
+
+ # zero prealloc fill the hole just punched
+ out=$(fallocate -z --offset $offset -l $length $DIR/$tfile 2>&1) ||
+ skip_eopnotsupp "$out|falloc(zero): off $offset, len $length"
+
+ # Verify zero prealloc worked.
+ blocks=$(stat -c '%b' $DIR/$tfile)
+ (( blocks == blocks_after_zero_fill )) ||
+ error "zero prealloc failed:$blocks!=$blocks_after_zero_fill"
+
+ # zero prealloc with KEEP_SIZE on
+ offset=$((8 * PAGE_SIZE))
+ length=$((8 * PAGE_SIZE))
+ out=$(fallocate -z -n --offset $offset -l $length $DIR/$tfile 2>&1) ||
+ skip_eopnotsupp "$out|falloc(zero): off $offset, len $length"
+
+ # block allocate, size remains
+ blocks=$(stat -c '%b' $DIR/$tfile)
+ (( blocks == blocks_after_extend )) ||
+ error "extend failed:$blocks!=$blocks_after_extend"
+
+ lsz=$(stat -c '%s' $DIR/$tfile)
+ (( lsz == expect_len)) ||
+ error "zero extend failed(len):$lsz!=$expect_len"
+}
+run_test 150ib "Verify fallocate zero-range PREALLOC functionality"
+
#LU-2902 roc_hit was not able to read all values from lproc
function roc_hit_init() {
local osts=${1:-$(osts_nodes)}