ntfs: persist nodump in the $LINUXFLAGS EA

Store nodump in bit 2 of LINUXFLAGS and allow it through fileattr_set.
Report the cached persistent bit through fileattr_get and
STATX_ATTR_NODUMP, including the statx supported-attribute mask. Reuse
the existing EA update and inode-load paths; nodump needs no additional
inode flag enforcement.

Document the complete immutable, append-only and nodump bitmask.

Signed-off-by: Baolin Liu <liubaolin@kylinos.cn>
Reviewed-by: Hyunchul Lee <hyc.lee@gmail.com>
Signed-off-by: Namjae Jeon <linkinjeon@kernel.org>
This commit is contained in:
Baolin Liu 2026-09-23 14:02:46 +08:00 committed by Namjae Jeon
parent a8be55640e
commit eb75ab5474
3 changed files with 28 additions and 16 deletions

View File

@ -38,21 +38,25 @@ The project is available at:
Linux file attributes
=====================
The driver supports lsattr(1) and setting immutable and append-only with chattr(1).
Immutable is stored in bit 0 and append-only in bit 1 of a private ``$LINUXFLAGS`` extended attribute
within the standard NTFS ``$EA``/``$EA_INFORMATION`` attributes. Its value
is a 32-bit little-endian bitmask. Unknown bits are preserved; the entry
is removed when the entire value becomes zero. These settings survive
inode eviction, unmount and reboot. Direct writes or removal through
xattr interfaces are rejected; use chattr(1) instead.
The driver supports lsattr(1) and chattr(1). Immutable, append-only and
nodump are stored in a private ``$LINUXFLAGS`` extended attribute within the
standard NTFS ``$EA``/``$EA_INFORMATION`` attributes. Its value is a
32-bit little-endian bitmask: bit 0 is immutable, bit 1 is append-only,
and bit 2 is nodump. Unknown bits are preserved when updating the flags;
the entry is removed when the entire value becomes zero. These settings
survive inode eviction, unmount and reboot. Direct writes to this EA
through setxattr(2) or removexattr(2) are rejected; use chattr(1) instead.
System metadata files and files protected by ``sys_immutable`` cannot
have their immutable protection cleared. Protection derived solely from
that policy is not stored in the EA. Compression, encryption
and mount-wide case folding are reported but cannot be changed through
chattr(1).
System metadata files and files protected by the ``sys_immutable`` mount
option cannot have their immutable protection cleared with chattr(1).
Protection derived solely from the mount option is not stored in the EA.
Case folding is reported according to the mount options and cannot be
configured per file. Compression and encryption are reported but cannot
be changed through chattr(1).
These Linux flags are enforced by Linux. Storing them in an NTFS EA does
not make Windows enforce immutable, append-only or nodump semantics.
Windows does not enforce the Linux immutable and append-only flags stored in this EA.
Supported mount options
=======================

View File

@ -10,8 +10,9 @@
/* $LINUXFLAGS stores these bits in a single little-endian 32-bit value. */
#define NTFS_LINUXFLAGS_IMMUTABLE BIT(0)
#define NTFS_LINUXFLAGS_APPEND BIT(1)
#define NTFS_LINUXFLAGS_NODUMP BIT(2)
#define NTFS_LINUXFLAGS_MASK (NTFS_LINUXFLAGS_IMMUTABLE | \
NTFS_LINUXFLAGS_APPEND)
NTFS_LINUXFLAGS_APPEND | NTFS_LINUXFLAGS_NODUMP)
extern const struct xattr_handler *const ntfs_xattr_handlers[];

View File

@ -167,6 +167,8 @@ int ntfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
flags |= FS_IMMUTABLE_FL;
if (vi->i_flags & S_APPEND)
flags |= FS_APPEND_FL;
if (ni->linuxflags & NTFS_LINUXFLAGS_NODUMP)
flags |= FS_NODUMP_FL;
if (!NVolCaseSensitive(ni->vol))
flags |= FS_CASEFOLD_FL;
@ -198,7 +200,7 @@ int ntfs_fileattr_set(const struct mnt_idmap *idmap, struct dentry *dentry,
{
struct inode *vi = d_inode(dentry);
struct ntfs_inode *ni = NTFS_I(vi);
u32 allowed = FS_IMMUTABLE_FL | FS_APPEND_FL;
u32 allowed = FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL;
u32 readonly = 0;
u32 linuxflags = ni->linuxflags & ~NTFS_LINUXFLAGS_MASK;
unsigned int new_fl = 0;
@ -241,6 +243,8 @@ int ntfs_fileattr_set(const struct mnt_idmap *idmap, struct dentry *dentry,
new_fl |= S_APPEND;
linuxflags |= NTFS_LINUXFLAGS_APPEND;
}
if (fa->flags & FS_NODUMP_FL)
linuxflags |= NTFS_LINUXFLAGS_NODUMP;
mutex_lock(&ni->mrec_lock);
err = ntfs_ea_set_linuxflags(vi, linuxflags);
@ -619,9 +623,12 @@ int ntfs_getattr(const struct mnt_idmap *idmap, const struct path *path,
if (inode->i_flags & S_APPEND)
stat->attributes |= STATX_ATTR_APPEND;
if (ni->linuxflags & NTFS_LINUXFLAGS_NODUMP)
stat->attributes |= STATX_ATTR_NODUMP;
stat->attributes_mask |= STATX_ATTR_COMPRESSED | STATX_ATTR_ENCRYPTED |
STATX_ATTR_IMMUTABLE | STATX_ATTR_APPEND;
STATX_ATTR_IMMUTABLE | STATX_ATTR_APPEND |
STATX_ATTR_NODUMP;
/*
* If it's a compressed or encrypted file, NTFS currently