size_t nob = io->ci_nob;
struct iov_iter iter;
size_t written = 0;
+ int chunk_size;
+ /* this i_size_read() is potentially racy, but it should be mostly
+ * reliable and this is just a temporary workaround for the compression
+ * preview
+ */
+ loff_t inode_size = i_size_read(inode);
+ bool write_beyond_eof = false;
ENTRY;
file_dentry(file)->d_name.name,
pos, pos + cnt);
+ if (pos >= inode_size)
+ write_beyond_eof = true;
+
+ chunk_size = (1 << (io->ci_compr_chunk_bits + 16));
+
+ /* compressed files require chunk-aligned writes for overwrites
+ * writes at EOF are OK because they do not update existing data
+ * EX-7601
+ */
+ if (io->ci_compressed_io && !write_beyond_eof &&
+ (pos % chunk_size || cnt % chunk_size)) {
+ CERROR("Compression preview requires writes to be chunk size aligned or at EOF, write pos: %llu, bytes: %lu, chunk_size: %d\n",
+ pos, cnt, chunk_size);
+ RETURN(-EINVAL);
+ }
+
/* The maximum Lustre file size is variable, based on the OST maximum
* object size and number of stripes. This needs another check in
* addition to the VFS checks earlier. */
lov_foreach_layout_entry(lov, lle) {
if (lle->lle_lsme->lsme_pattern & LOV_PATTERN_COMPRESS) {
io->ci_compressed_io = true;
+ /* a single IO may hit different components with
+ * different compression chunk sizes; since this is
+ * used for chunk-alignment, we can take the largest
+ * chunk size since chunks are all powers of two and
+ * aligning to the largest size will also align to any
+ * smaller sizes
+ */
+ if (lle->lle_lsme->lsme_compr_chunk_log_bits >
+ io->ci_compr_chunk_bits) {
+ io->ci_compr_chunk_bits =
+ lle->lle_lsme->lsme_compr_chunk_log_bits;
+ }
break;
}
}
CDEBUG(D_INODE,
- DFID "io %p type %d ignore/verify layout %d/%d, compressed %d\n",
+ DFID "io %p type %d ignore/verify layout %d/%d, compressed %x, chunk_size %d\n",
PFID(lu_object_fid(&obj->co_lu)), io, io->ci_type,
io->ci_ignore_layout, io->ci_verify_layout,
- io->ci_compressed_io);
+ io->ci_compressed_io,
+ io->ci_compressed_io ? (1 << (io->ci_compr_chunk_bits + 16)) : 0);
/* IO type CIT_MISC with ci_ignore_layout set are usually invoked from
* the OSC layer. It shouldn't take lov layout conf lock in that case,
}
test_460a() {
- (( MDS1_VERSION >= $(version_code 2.14.0.85) )) ||
- skip "Need MDS version at least 2.14.0.85"
+ (( MDS1_VERSION >= $(version_code 2.14.0.89) )) ||
+ skip "Need MDS version at least 2.14.0.89"
rm -Rf $DIR/$tdir; rm -Rf $TMP/$tdir
run_test 460a "Compress/decompress text test"
test_460b() {
- (( MDS1_VERSION >= $(version_code 2.14.0.85) )) ||
- skip "Need MDS version at least 2.14.0.85"
+ (( MDS1_VERSION >= $(version_code 2.14.0.89) )) ||
+ skip "Need MDS version at least 2.14.0.89"
local stored=$DIR/$tdir/foofile
test_mkdir $DIR/$tdir
}
run_test 460b "Try to compress with wrong algo"
+# This test verifies the write restrictions for the preview version related to
+# EX-7601, this test will be removed once EX-7601 is resolved
+# Restrictions are as follows:
+# Chunk aligned writes are always allowed
+# Non-chunk-aligned writes are only allowed if they are extending the file, ie,
+# if they are not overwriting existing data
+test_460c() {
+ (( MDS1_VERSION >= $(version_code 2.14.0.89) )) ||
+ skip "Need MDS version at least 2.14.0.89"
+
+ local stored=$DIR/$tdir/foofile
+ local tmpfile=$TMP/$tdir/footmp
+ test_mkdir $DIR/$tdir
+ test_mkdir $TMP/$tdir
+
+ stack_trap "rm -Rf $DIR/$tdir; rm -Rf $TMP/$tdir; disable_compression"
+ enable_compression
+
+ $LFS setstripe -E 2M -Z gzip:5 -E 10M -Z none -E -1 -Z lz4:5 \
+ --compress-chunk=64 $stored ||
+ error "set a compress component in $stored failed"
+
+ # Can do non-chunk-aligned IO when extending the file
+ dd if=/dev/zero of=$stored bs=37K count=5 ||
+ error "dd to $stored failed"
+
+ sync; echo 3 > /proc/sys/vm/drop_caches
+
+ # Can overwrite an existing file with chunk aligned IO
+ dd if=/dev/zero of=$stored bs=64K count=5 conv=notrunc ||
+ error "aligned dd to overwrite $stored failed"
+
+ # Test io at 2x chunk size
+ dd if=/dev/zero of=$stored bs=128K count=5 conv=notrunc ||
+ error "aligned dd to overwrite $stored failed"
+
+ # Cannot do non-chunk aligned IO when overwriting
+ dd if=/dev/zero of=$stored bs=37K count=5 conv=notrunc &&
+ error "unsafe dd to $stored succeeded"
+
+ # Cannot do non-chunk aligned IO when overwriting (test larger size)
+ dd if=/dev/zero of=$stored bs=1025K count=5 conv=notrunc &&
+ error "unsafe dd to $stored succeeded"
+
+ # Can do non-chunk aligned IO when extending the file
+ dd if=/dev/zero of=$stored bs=37K count=5 oflag=append conv=notrunc ||
+ error "unaligned dd to extend $stored failed"
+}
+run_test 460c "simple verification of preview write restrictions"
+
test_460d() {
- (( MDS1_VERSION >= $(version_code 2.14.0.85) )) ||
- skip "Need MDS version at least 2.14.0.85"
+ (( MDS1_VERSION >= $(version_code 2.14.0.89) )) ||
+ skip "Need MDS version at least 2.14.0.89"
verify_yaml_available || skip_env "YAML verification not installed"
$LCTL get_param -n sptlrpc.page_pools