btrfs: props: add per-inode compression level support
Setting a per-file compression level is an often requested feature, and
the btrfs.compression property has silently accepted level suffixes
("zstd:9") since compression types were added to it: the property
validator only matches the algorithm name prefix, the verbatim string is
stored in the xattr and returned by getxattr, and everything after the
algorithm name is ignored when the value is parsed into the in-memory
compression type.
All of the pieces needed to honor the level already exist: the level is
a per-call argument down the whole compression path, per-inode levels
are already implemented for the defrag ioctl (defrag_compress_level),
and btrfs_compress_str2level() already parses and clamps ":level"
suffixes for the mount options. Wire the property path up to them:
* Cache the parsed level in a new btrfs_inode::prop_compress_level,
with 0 meaning no level was specified, in which case the level from
the mount options is used as before. The field is signed to allow
negative (realtime) zstd levels.
* Parse an optional ":level" suffix in prop_compression_apply().
Values stored by old kernels were never validated, so an unparseable
suffix falls back to the default level rather than making the inode's
properties fail to load. Levels for lzo parse and clamp to nothing,
matching commit
6db1df415d73 ("btrfs: accept and ignore compression
level for lzo").
* Use the level in compress_file_range() when compression is selected
by the property. The defrag ioctl retains precedence.
* Regenerate the canonical "type:level" string with a new helper,
btrfs_prop_compression_extract(), so that directory inheritance
propagates the level to new inodes, and so that FS_IOC_SETFLAGS,
which rewrites the property when setting FS_COMPR_FL, preserves the
level instead of truncating the value to the bare algorithm name.
The prop_handler extract hook itself is unchanged: it still returns
a static string, and the inheritance loop regenerates the leveled
value only for the compression property.
There is no disk format change: the level lives in the already-existing
xattr value string. Note that levels stored by old kernels (which were
accepted but ignored) become effective after this change.
Signed-off-by: Zygo Blaxell <ce3g8jdj@umail.furryterror.org>
Assisted-by: Claude:claude-fable-5