mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 09:36:22 +02:00
vfs-7.2-rc1.casefold
Please consider pulling these changes from the signed vfs-7.2-rc1.casefold tag. Thanks! Christian -----BEGIN PGP SIGNATURE----- iHUEABYKAB0WIQRAhzRXHqcMeLMyaSiRxhvAZXjcogUCaiwLKgAKCRCRxhvAZXjc omRSAP4valdmpvuSFbc84F6nn0LjDhTR+zg3uX2iGF6sWaQLjAEAyAhuDH23SQyz SSj2KCh/G2c/IXCVM5j0zn7fZxeKBA4= =GA7C -----END PGP SIGNATURE----- Merge tag 'vfs-7.2-rc1.casefold' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs Pull vfs casefolding updates from Christian Brauner: "This exposes the case folding behavior of local filesystems so that file servers - nfsd, ksmbd, and user space file servers - can report the actual behavior to clients instead of guessing. Filesystems report case-insensitive and case-nonpreserving behavior via new file_kattr flags in their fileattr_get implementations. fat, exfat, ntfs3, hfs, hfsplus, xfs, cifs, nfs, vboxsf, and isofs are wired up. Local filesystems that are not explicitly handled default to the usual POSIX behavior of case-sensitive and case-preserving. nfsd uses this to report case folding via NFSv3 PATHCONF and to implement the NFSv4 FATTR4_CASE_INSENSITIVE and FATTR4_CASE_PRESERVING attributes - both have been part of the NFS protocols for decades to support clients on non-POSIX systems - and ksmbd reports it via FS_ATTRIBUTE_INFORMATION. Exposing the information through the fileattr uapi covers user space file servers. The immediate motivation is interoperability: Windows NFS clients hard-require servers to report case-insensitivity for Win32 applications to work correctly, and a client that knows the server is case-insensitive can avoid issuing multiple LOOKUP/READDIR requests searching for case variants. The Linux NFS client already grew support for case-insensitive shares years ago in support of the Hammerspace NFS server - negative dentry caching must be disabled (a lookup for "FILE.TXT" failing must not cache a negative entry when "file.txt" exists) and directory change invalidation must drop cached case-folded name variants. Such servers often operate in multi-protocol environments where a single file service instance caters to both NFS and SMB clients, and nfsd needs to report case folding properly to participate as a first-class citizen there. A follow-up series brings fixes for the initial work: the nfsd case-info probe now uses kernel credentials, maps -ESTALE to NFS3ERR_STALE, and has its cost capped across READDIR entries; the nfs client avoids transiently zeroed case capability bits during the probe and skips the pathconf probe when neither field is consumed; the FS_CASEFOLD_FL semantics are clarified in the UAPI header; and the tools UAPI headers are synced" * tag 'vfs-7.2-rc1.casefold' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs: (22 commits) nfsd: Cap case-folding probe cost across READDIR entries nfsd: Map -ESTALE from case probe to NFS3ERR_STALE nfsd: Use kernel credentials for case-info probe fs: Clarify FS_CASEFOLD_FL semantics in UAPI header nfs: Skip pathconf probe when neither field is consumed nfs: Avoid transient zeroed case capability bits during probe tools headers UAPI: Sync case-sensitivity flags from linux/fs.h ksmbd: Report filesystem case sensitivity via FS_ATTRIBUTE_INFORMATION nfsd: Implement NFSv4 FATTR4_CASE_INSENSITIVE and FATTR4_CASE_PRESERVING nfsd: Report export case-folding via NFSv3 PATHCONF isofs: Implement fileattr_get for case sensitivity vboxsf: Implement fileattr_get for case sensitivity nfs: Implement fileattr_get for case sensitivity cifs: Implement fileattr_get for case sensitivity xfs: Report case sensitivity in fileattr_get hfsplus: Report case sensitivity in fileattr_get hfs: Implement fileattr_get for case sensitivity ntfs3: Implement fileattr_get for case sensitivity exfat: Implement fileattr_get for case sensitivity fat: Implement fileattr_get for case sensitivity ...
This commit is contained in:
commit
5d15ab717d
|
|
@ -496,6 +496,8 @@ int exfat_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
int exfat_getattr(struct mnt_idmap *idmap, const struct path *path,
|
||||
struct kstat *stat, unsigned int request_mask,
|
||||
unsigned int query_flags);
|
||||
struct file_kattr;
|
||||
int exfat_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
|
||||
int exfat_file_fsync(struct file *file, loff_t start, loff_t end, int datasync);
|
||||
long exfat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg);
|
||||
long exfat_compat_ioctl(struct file *filp, unsigned int cmd,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/writeback.h>
|
||||
#include <linux/filelock.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/fileattr.h>
|
||||
|
||||
#include "exfat_raw.h"
|
||||
#include "exfat_fs.h"
|
||||
|
|
@ -323,6 +324,18 @@ int exfat_getattr(struct mnt_idmap *idmap, const struct path *path,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int exfat_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
|
||||
{
|
||||
/*
|
||||
* exFAT compares filenames through an upcase table, so lookup
|
||||
* is always case-insensitive. Long names are stored in UTF-16
|
||||
* with case intact; CASENONPRESERVING stays clear.
|
||||
*/
|
||||
fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
|
||||
fa->flags |= FS_CASEFOLD_FL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exfat_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
struct iattr *attr)
|
||||
{
|
||||
|
|
@ -817,6 +830,7 @@ const struct file_operations exfat_file_operations = {
|
|||
};
|
||||
|
||||
const struct inode_operations exfat_file_inode_operations = {
|
||||
.setattr = exfat_setattr,
|
||||
.getattr = exfat_getattr,
|
||||
.setattr = exfat_setattr,
|
||||
.getattr = exfat_getattr,
|
||||
.fileattr_get = exfat_fileattr_get,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1311,4 +1311,5 @@ const struct inode_operations exfat_dir_inode_operations = {
|
|||
.rename = exfat_rename,
|
||||
.setattr = exfat_setattr,
|
||||
.getattr = exfat_getattr,
|
||||
.fileattr_get = exfat_fileattr_get,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@
|
|||
#include <linux/fs_context.h>
|
||||
#include <linux/fs_parser.h>
|
||||
|
||||
struct file_kattr;
|
||||
|
||||
/*
|
||||
* vfat shortname flags
|
||||
*/
|
||||
|
|
@ -408,6 +410,7 @@ extern void fat_truncate_blocks(struct inode *inode, loff_t offset);
|
|||
extern int fat_getattr(struct mnt_idmap *idmap,
|
||||
const struct path *path, struct kstat *stat,
|
||||
u32 request_mask, unsigned int flags);
|
||||
int fat_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
|
||||
extern int fat_file_fsync(struct file *file, loff_t start, loff_t end,
|
||||
int datasync);
|
||||
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
#include <linux/fsnotify.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/falloc.h>
|
||||
#include <linux/fileattr.h>
|
||||
#include "fat.h"
|
||||
|
||||
static long fat_fallocate(struct file *file, int mode,
|
||||
|
|
@ -398,6 +399,40 @@ void fat_truncate_blocks(struct inode *inode, loff_t offset)
|
|||
fat_flush_inodes(inode->i_sb, inode, NULL);
|
||||
}
|
||||
|
||||
int fat_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
|
||||
{
|
||||
struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
|
||||
bool case_sensitive;
|
||||
|
||||
/*
|
||||
* FAT filesystems are case-insensitive by default. VFAT
|
||||
* becomes case-sensitive when mounted with 'check=strict',
|
||||
* which installs vfat_dentry_ops. MSDOS has no such option;
|
||||
* its 'nocase' mount option selects case-sensitive matching.
|
||||
*
|
||||
* VFAT long filename entries preserve case. Without VFAT, only
|
||||
* uppercased 8.3 short names are stored. MSDOS with 'nocase'
|
||||
* also preserves case.
|
||||
*/
|
||||
if (sbi->options.isvfat)
|
||||
case_sensitive = sbi->options.name_check == 's';
|
||||
else
|
||||
case_sensitive = sbi->options.nocase;
|
||||
|
||||
if (!case_sensitive) {
|
||||
fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
|
||||
fa->flags |= FS_CASEFOLD_FL;
|
||||
if (!sbi->options.isvfat)
|
||||
fa->fsx_xflags |= FS_XFLAG_CASENONPRESERVING;
|
||||
}
|
||||
if (d_inode(dentry)->i_flags & S_IMMUTABLE) {
|
||||
fa->fsx_xflags |= FS_XFLAG_IMMUTABLE;
|
||||
fa->flags |= FS_IMMUTABLE_FL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(fat_fileattr_get);
|
||||
|
||||
int fat_getattr(struct mnt_idmap *idmap, const struct path *path,
|
||||
struct kstat *stat, u32 request_mask, unsigned int flags)
|
||||
{
|
||||
|
|
@ -575,5 +610,6 @@ EXPORT_SYMBOL_GPL(fat_setattr);
|
|||
const struct inode_operations fat_file_inode_operations = {
|
||||
.setattr = fat_setattr,
|
||||
.getattr = fat_getattr,
|
||||
.fileattr_get = fat_fileattr_get,
|
||||
.update_time = fat_update_time,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -644,6 +644,7 @@ static const struct inode_operations msdos_dir_inode_operations = {
|
|||
.rename = msdos_rename,
|
||||
.setattr = fat_setattr,
|
||||
.getattr = fat_getattr,
|
||||
.fileattr_get = fat_fileattr_get,
|
||||
.update_time = fat_update_time,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1185,6 +1185,7 @@ static const struct inode_operations vfat_dir_inode_operations = {
|
|||
.rename = vfat_rename2,
|
||||
.setattr = fat_setattr,
|
||||
.getattr = fat_getattr,
|
||||
.fileattr_get = fat_fileattr_get,
|
||||
.update_time = fat_update_time,
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -15,12 +15,10 @@
|
|||
* @fa: fileattr pointer
|
||||
* @xflags: FS_XFLAG_* flags
|
||||
*
|
||||
* Set ->fsx_xflags, ->fsx_valid and ->flags (translated xflags). All
|
||||
* other fields are zeroed.
|
||||
* Set ->fsx_xflags, ->fsx_valid and ->flags (translated xflags).
|
||||
*/
|
||||
void fileattr_fill_xflags(struct file_kattr *fa, u32 xflags)
|
||||
{
|
||||
memset(fa, 0, sizeof(*fa));
|
||||
fa->fsx_valid = true;
|
||||
fa->fsx_xflags = xflags;
|
||||
if (fa->fsx_xflags & FS_XFLAG_IMMUTABLE)
|
||||
|
|
@ -39,6 +37,8 @@ void fileattr_fill_xflags(struct file_kattr *fa, u32 xflags)
|
|||
fa->flags |= FS_PROJINHERIT_FL;
|
||||
if (fa->fsx_xflags & FS_XFLAG_VERITY)
|
||||
fa->flags |= FS_VERITY_FL;
|
||||
if (fa->fsx_xflags & FS_XFLAG_CASEFOLD)
|
||||
fa->flags |= FS_CASEFOLD_FL;
|
||||
}
|
||||
EXPORT_SYMBOL(fileattr_fill_xflags);
|
||||
|
||||
|
|
@ -48,11 +48,9 @@ EXPORT_SYMBOL(fileattr_fill_xflags);
|
|||
* @flags: FS_*_FL flags
|
||||
*
|
||||
* Set ->flags, ->flags_valid and ->fsx_xflags (translated flags).
|
||||
* All other fields are zeroed.
|
||||
*/
|
||||
void fileattr_fill_flags(struct file_kattr *fa, u32 flags)
|
||||
{
|
||||
memset(fa, 0, sizeof(*fa));
|
||||
fa->flags_valid = true;
|
||||
fa->flags = flags;
|
||||
if (fa->flags & FS_SYNC_FL)
|
||||
|
|
@ -71,6 +69,8 @@ void fileattr_fill_flags(struct file_kattr *fa, u32 flags)
|
|||
fa->fsx_xflags |= FS_XFLAG_PROJINHERIT;
|
||||
if (fa->flags & FS_VERITY_FL)
|
||||
fa->fsx_xflags |= FS_XFLAG_VERITY;
|
||||
if (fa->flags & FS_CASEFOLD_FL)
|
||||
fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
|
||||
}
|
||||
EXPORT_SYMBOL(fileattr_fill_flags);
|
||||
|
||||
|
|
@ -325,7 +325,7 @@ int ioctl_setflags(struct file *file, unsigned int __user *argp)
|
|||
{
|
||||
struct mnt_idmap *idmap = file_mnt_idmap(file);
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct file_kattr fa;
|
||||
struct file_kattr fa = {};
|
||||
unsigned int flags;
|
||||
int err;
|
||||
|
||||
|
|
@ -357,7 +357,7 @@ int ioctl_fssetxattr(struct file *file, void __user *argp)
|
|||
{
|
||||
struct mnt_idmap *idmap = file_mnt_idmap(file);
|
||||
struct dentry *dentry = file->f_path.dentry;
|
||||
struct file_kattr fa;
|
||||
struct file_kattr fa = {};
|
||||
int err;
|
||||
|
||||
err = copy_fsxattr_from_user(&fa, argp);
|
||||
|
|
@ -431,7 +431,7 @@ SYSCALL_DEFINE5(file_setattr, int, dfd, const char __user *, filename,
|
|||
struct path filepath __free(path_put) = {};
|
||||
unsigned int lookup_flags = 0;
|
||||
struct file_attr fattr;
|
||||
struct file_kattr fa;
|
||||
struct file_kattr fa = {};
|
||||
int error;
|
||||
|
||||
BUILD_BUG_ON(sizeof(struct file_attr) < FILE_ATTR_SIZE_VER0);
|
||||
|
|
|
|||
|
|
@ -328,4 +328,5 @@ const struct inode_operations hfs_dir_inode_operations = {
|
|||
.rmdir = hfs_remove,
|
||||
.rename = hfs_rename,
|
||||
.setattr = hfs_inode_setattr,
|
||||
.fileattr_get = hfs_fileattr_get,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -177,6 +177,8 @@ extern int hfs_get_block(struct inode *inode, sector_t block,
|
|||
extern const struct address_space_operations hfs_aops;
|
||||
extern const struct address_space_operations hfs_btree_aops;
|
||||
|
||||
struct file_kattr;
|
||||
int hfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
|
||||
int hfs_write_begin(const struct kiocb *iocb, struct address_space *mapping,
|
||||
loff_t pos, unsigned int len, struct folio **foliop,
|
||||
void **fsdata);
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@
|
|||
#include <linux/uio.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/fileattr.h>
|
||||
|
||||
#include "hfs_fs.h"
|
||||
#include "btree.h"
|
||||
|
|
@ -699,6 +700,18 @@ static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end,
|
|||
return ret;
|
||||
}
|
||||
|
||||
int hfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
|
||||
{
|
||||
/*
|
||||
* HFS compares filenames using Mac OS Roman case folding, so
|
||||
* lookup is always case-insensitive. Names are stored on disk
|
||||
* with case intact; CASENONPRESERVING stays clear.
|
||||
*/
|
||||
fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
|
||||
fa->flags |= FS_CASEFOLD_FL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct file_operations hfs_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read_iter = generic_file_read_iter,
|
||||
|
|
@ -715,4 +728,5 @@ static const struct inode_operations hfs_file_inode_operations = {
|
|||
.lookup = hfs_file_lookup,
|
||||
.setattr = hfs_inode_setattr,
|
||||
.listxattr = generic_listxattr,
|
||||
.fileattr_get = hfs_fileattr_get,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -740,6 +740,7 @@ int hfsplus_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
|
|||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
|
||||
struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
|
||||
unsigned int flags = 0;
|
||||
|
||||
if (inode->i_flags & S_IMMUTABLE)
|
||||
|
|
@ -748,6 +749,8 @@ int hfsplus_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
|
|||
flags |= FS_APPEND_FL;
|
||||
if (hip->userflags & HFSPLUS_FLG_NODUMP)
|
||||
flags |= FS_NODUMP_FL;
|
||||
if (test_bit(HFSPLUS_SB_CASEFOLD, &sbi->flags))
|
||||
flags |= FS_CASEFOLD_FL;
|
||||
|
||||
fileattr_fill_flags(fa, flags);
|
||||
|
||||
|
|
@ -759,13 +762,24 @@ int hfsplus_fileattr_set(struct mnt_idmap *idmap,
|
|||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
|
||||
struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
|
||||
unsigned int allowed = FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL;
|
||||
unsigned int new_fl = 0;
|
||||
|
||||
if (fileattr_has_fsx(fa))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/*
|
||||
* FS_CASEFOLD_FL reflects HFSPLUS_SB_CASEFOLD, a mount-time
|
||||
* property. Accept it as a no-op so chattr's RMW round-trip
|
||||
* succeeds; reject any attempt to enable it on a volume that
|
||||
* was not formatted case-insensitive.
|
||||
*/
|
||||
if (test_bit(HFSPLUS_SB_CASEFOLD, &sbi->flags))
|
||||
allowed |= FS_CASEFOLD_FL;
|
||||
|
||||
/* don't silently ignore unsupported ext2 flags */
|
||||
if (fa->flags & ~(FS_IMMUTABLE_FL|FS_APPEND_FL|FS_NODUMP_FL))
|
||||
if (fa->flags & ~allowed)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (fa->flags & FS_IMMUTABLE_FL)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/gfp.h>
|
||||
#include <linux/filelock.h>
|
||||
#include "isofs.h"
|
||||
#include <linux/fileattr.h>
|
||||
|
||||
int isofs_name_translate(struct iso_directory_record *de, char *new, struct inode *inode)
|
||||
{
|
||||
|
|
@ -267,6 +268,20 @@ static int isofs_readdir(struct file *file, struct dir_context *ctx)
|
|||
return result;
|
||||
}
|
||||
|
||||
int isofs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
|
||||
{
|
||||
struct isofs_sb_info *sbi = ISOFS_SB(dentry->d_sb);
|
||||
|
||||
if (sbi->s_check == 'r') {
|
||||
fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
|
||||
fa->flags |= FS_CASEFOLD_FL;
|
||||
}
|
||||
if (!sbi->s_joliet_level && !sbi->s_rock &&
|
||||
(sbi->s_mapping == 'n' || sbi->s_mapping == 'a'))
|
||||
fa->fsx_xflags |= FS_XFLAG_CASENONPRESERVING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct file_operations isofs_dir_operations =
|
||||
{
|
||||
.llseek = generic_file_llseek,
|
||||
|
|
@ -281,6 +296,7 @@ const struct file_operations isofs_dir_operations =
|
|||
const struct inode_operations isofs_dir_inode_operations =
|
||||
{
|
||||
.lookup = isofs_lookup,
|
||||
.fileattr_get = isofs_fileattr_get,
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -197,6 +197,9 @@ isofs_normalize_block_and_offset(struct iso_directory_record* de,
|
|||
}
|
||||
}
|
||||
|
||||
struct file_kattr;
|
||||
int isofs_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
|
||||
|
||||
extern const struct inode_operations isofs_dir_inode_operations;
|
||||
extern const struct file_operations isofs_dir_operations;
|
||||
extern const struct address_space_operations isofs_symlink_aops;
|
||||
|
|
|
|||
|
|
@ -914,6 +914,7 @@ static void nfs_server_set_fsinfo(struct nfs_server *server,
|
|||
*/
|
||||
static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, struct nfs_fattr *fattr)
|
||||
{
|
||||
struct nfs_pathconf pathinfo = { };
|
||||
struct nfs_fsinfo fsinfo;
|
||||
struct nfs_client *clp = server->nfs_client;
|
||||
int error;
|
||||
|
|
@ -933,15 +934,28 @@ static int nfs_probe_fsinfo(struct nfs_server *server, struct nfs_fh *mntfh, str
|
|||
|
||||
nfs_server_set_fsinfo(server, &fsinfo);
|
||||
|
||||
/* Get some general file system info */
|
||||
if (server->namelen == 0) {
|
||||
struct nfs_pathconf pathinfo;
|
||||
pathinfo.fattr = fattr;
|
||||
nfs_fattr_init(fattr);
|
||||
|
||||
pathinfo.fattr = fattr;
|
||||
nfs_fattr_init(fattr);
|
||||
if (clp->rpc_ops->version < 4 || server->namelen == 0) {
|
||||
if (clp->rpc_ops->pathconf(server, mntfh, &pathinfo) >= 0) {
|
||||
if (server->namelen == 0)
|
||||
server->namelen = pathinfo.max_namelen;
|
||||
if (clp->rpc_ops->version < 4) {
|
||||
unsigned int caps = server->caps;
|
||||
|
||||
if (clp->rpc_ops->pathconf(server, mntfh, &pathinfo) >= 0)
|
||||
server->namelen = pathinfo.max_namelen;
|
||||
caps &= ~(NFS_CAP_CASE_INSENSITIVE |
|
||||
NFS_CAP_CASE_NONPRESERVING);
|
||||
if (pathinfo.case_insensitive)
|
||||
caps |= NFS_CAP_CASE_INSENSITIVE;
|
||||
if (!pathinfo.case_preserving)
|
||||
caps |= NFS_CAP_CASE_NONPRESERVING;
|
||||
server->caps = caps;
|
||||
}
|
||||
} else if (clp->rpc_ops->version < 4) {
|
||||
server->caps &= ~(NFS_CAP_CASE_INSENSITIVE |
|
||||
NFS_CAP_CASE_NONPRESERVING);
|
||||
}
|
||||
}
|
||||
|
||||
if (clp->rpc_ops->discover_trunking != NULL &&
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include <linux/freezer.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/iversion.h>
|
||||
#include <linux/fileattr.h>
|
||||
|
||||
#include "nfs4_fs.h"
|
||||
#include "callback.h"
|
||||
|
|
@ -1095,6 +1096,20 @@ int nfs_getattr(struct mnt_idmap *idmap, const struct path *path,
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_getattr);
|
||||
|
||||
int nfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
|
||||
if (nfs_server_capable(inode, NFS_CAP_CASE_INSENSITIVE)) {
|
||||
fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
|
||||
fa->flags |= FS_CASEFOLD_FL;
|
||||
}
|
||||
if (nfs_server_capable(inode, NFS_CAP_CASE_NONPRESERVING))
|
||||
fa->fsx_xflags |= FS_XFLAG_CASENONPRESERVING;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nfs_fileattr_get);
|
||||
|
||||
static void nfs_init_lock_context(struct nfs_lock_context *l_ctx)
|
||||
{
|
||||
refcount_set(&l_ctx->count, 1);
|
||||
|
|
|
|||
|
|
@ -451,6 +451,9 @@ extern void nfs_set_cache_invalid(struct inode *inode, unsigned long flags);
|
|||
extern bool nfs_check_cache_invalid(struct inode *, unsigned long);
|
||||
extern int nfs_wait_bit_killable(struct wait_bit_key *key, int mode);
|
||||
|
||||
struct file_kattr;
|
||||
int nfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
|
||||
|
||||
#if IS_ENABLED(CONFIG_NFS_LOCALIO)
|
||||
/* localio.c */
|
||||
struct nfs_local_dio {
|
||||
|
|
|
|||
|
|
@ -246,11 +246,13 @@ nfs_namespace_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
|||
const struct inode_operations nfs_mountpoint_inode_operations = {
|
||||
.getattr = nfs_getattr,
|
||||
.setattr = nfs_setattr,
|
||||
.fileattr_get = nfs_fileattr_get,
|
||||
};
|
||||
|
||||
const struct inode_operations nfs_referral_inode_operations = {
|
||||
.getattr = nfs_namespace_getattr,
|
||||
.setattr = nfs_namespace_setattr,
|
||||
.fileattr_get = nfs_fileattr_get,
|
||||
};
|
||||
|
||||
static void nfs_expire_automounts(struct work_struct *work)
|
||||
|
|
|
|||
|
|
@ -1053,6 +1053,7 @@ static const struct inode_operations nfs3_dir_inode_operations = {
|
|||
.permission = nfs_permission,
|
||||
.getattr = nfs_getattr,
|
||||
.setattr = nfs_setattr,
|
||||
.fileattr_get = nfs_fileattr_get,
|
||||
#ifdef CONFIG_NFS_V3_ACL
|
||||
.listxattr = nfs3_listxattr,
|
||||
.get_inode_acl = nfs3_get_acl,
|
||||
|
|
@ -1064,6 +1065,7 @@ static const struct inode_operations nfs3_file_inode_operations = {
|
|||
.permission = nfs_permission,
|
||||
.getattr = nfs_getattr,
|
||||
.setattr = nfs_setattr,
|
||||
.fileattr_get = nfs_fileattr_get,
|
||||
#ifdef CONFIG_NFS_V3_ACL
|
||||
.listxattr = nfs3_listxattr,
|
||||
.get_inode_acl = nfs3_get_acl,
|
||||
|
|
|
|||
|
|
@ -2276,8 +2276,11 @@ static int decode_pathconf3resok(struct xdr_stream *xdr,
|
|||
if (unlikely(!p))
|
||||
return -EIO;
|
||||
result->max_link = be32_to_cpup(p++);
|
||||
result->max_namelen = be32_to_cpup(p);
|
||||
/* ignore remaining fields */
|
||||
result->max_namelen = be32_to_cpup(p++);
|
||||
p++; /* ignore no_trunc */
|
||||
p++; /* ignore chown_restricted */
|
||||
result->case_insensitive = be32_to_cpup(p++) != 0;
|
||||
result->case_preserving = be32_to_cpup(p) != 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3933,7 +3933,8 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
|
|||
server->caps &=
|
||||
~(NFS_CAP_ACLS | NFS_CAP_HARDLINKS | NFS_CAP_SYMLINKS |
|
||||
NFS_CAP_SECURITY_LABEL | NFS_CAP_FS_LOCATIONS |
|
||||
NFS_CAP_OPEN_XOR | NFS_CAP_DELEGTIME);
|
||||
NFS_CAP_OPEN_XOR | NFS_CAP_DELEGTIME |
|
||||
NFS_CAP_CASE_INSENSITIVE | NFS_CAP_CASE_NONPRESERVING);
|
||||
server->fattr_valid = NFS_ATTR_FATTR_V4;
|
||||
if (res.attr_bitmask[0] & FATTR4_WORD0_ACL &&
|
||||
res.acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
|
||||
|
|
@ -3944,8 +3945,9 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
|
|||
server->caps |= NFS_CAP_SYMLINKS;
|
||||
if (res.case_insensitive)
|
||||
server->caps |= NFS_CAP_CASE_INSENSITIVE;
|
||||
if (res.case_preserving)
|
||||
server->caps |= NFS_CAP_CASE_PRESERVING;
|
||||
if ((res.attr_bitmask[0] & FATTR4_WORD0_CASE_PRESERVING) &&
|
||||
!res.case_preserving)
|
||||
server->caps |= NFS_CAP_CASE_NONPRESERVING;
|
||||
#ifdef CONFIG_NFS_V4_SECURITY_LABEL
|
||||
if (res.attr_bitmask[2] & FATTR4_WORD2_SECURITY_LABEL)
|
||||
server->caps |= NFS_CAP_SECURITY_LABEL;
|
||||
|
|
@ -10617,6 +10619,7 @@ static const struct inode_operations nfs4_dir_inode_operations = {
|
|||
.getattr = nfs_getattr,
|
||||
.setattr = nfs_setattr,
|
||||
.listxattr = nfs4_listxattr,
|
||||
.fileattr_get = nfs_fileattr_get,
|
||||
};
|
||||
|
||||
static const struct inode_operations nfs4_file_inode_operations = {
|
||||
|
|
@ -10624,6 +10627,7 @@ static const struct inode_operations nfs4_file_inode_operations = {
|
|||
.getattr = nfs_getattr,
|
||||
.setattr = nfs_setattr,
|
||||
.listxattr = nfs4_listxattr,
|
||||
.fileattr_get = nfs_fileattr_get,
|
||||
};
|
||||
|
||||
static struct nfs_server *nfs4_clone_server(struct nfs_server *source,
|
||||
|
|
|
|||
|
|
@ -598,6 +598,7 @@ nfs_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle,
|
|||
{
|
||||
info->max_link = 0;
|
||||
info->max_namelen = NFS2_MAXNAMLEN;
|
||||
info->case_preserving = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -718,12 +719,14 @@ static const struct inode_operations nfs_dir_inode_operations = {
|
|||
.permission = nfs_permission,
|
||||
.getattr = nfs_getattr,
|
||||
.setattr = nfs_setattr,
|
||||
.fileattr_get = nfs_fileattr_get,
|
||||
};
|
||||
|
||||
static const struct inode_operations nfs_file_inode_operations = {
|
||||
.permission = nfs_permission,
|
||||
.getattr = nfs_getattr,
|
||||
.setattr = nfs_setattr,
|
||||
.fileattr_get = nfs_fileattr_get,
|
||||
};
|
||||
|
||||
const struct nfs_rpc_ops nfs_v2_clientops = {
|
||||
|
|
|
|||
|
|
@ -22,6 +22,8 @@
|
|||
#include <linux/mm.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "internal.h"
|
||||
|
||||
/* Symlink caching in the page cache is even more simplistic
|
||||
* and straight-forward than readdir caching.
|
||||
*/
|
||||
|
|
@ -74,4 +76,5 @@ const struct inode_operations nfs_symlink_inode_operations = {
|
|||
.get_link = nfs_get_link,
|
||||
.getattr = nfs_getattr,
|
||||
.setattr = nfs_setattr,
|
||||
.fileattr_get = nfs_fileattr_get,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -710,23 +710,46 @@ nfsd3_proc_pathconf(struct svc_rqst *rqstp)
|
|||
resp->p_name_max = 255; /* at least */
|
||||
resp->p_no_trunc = 0;
|
||||
resp->p_chown_restricted = 1;
|
||||
resp->p_case_insensitive = 0;
|
||||
resp->p_case_preserving = 1;
|
||||
resp->p_case_insensitive = false;
|
||||
resp->p_case_preserving = true;
|
||||
|
||||
resp->status = fh_verify(rqstp, &argp->fh, 0, NFSD_MAY_NOP);
|
||||
|
||||
if (resp->status == nfs_ok) {
|
||||
struct super_block *sb = argp->fh.fh_dentry->d_sb;
|
||||
int err;
|
||||
|
||||
/* Note that we don't care for remote fs's here */
|
||||
switch (sb->s_magic) {
|
||||
case EXT2_SUPER_MAGIC:
|
||||
if (sb->s_magic == EXT2_SUPER_MAGIC) {
|
||||
resp->p_link_max = EXT2_LINK_MAX;
|
||||
resp->p_name_max = EXT2_NAME_LEN;
|
||||
}
|
||||
|
||||
err = nfsd_get_case_info(argp->fh.fh_dentry,
|
||||
&resp->p_case_insensitive,
|
||||
&resp->p_case_preserving);
|
||||
/*
|
||||
* RFC 1813 lists NFS3ERR_STALE, NFS3ERR_BADHANDLE, and
|
||||
* NFS3ERR_SERVERFAULT as the only PATHCONF errors.
|
||||
*/
|
||||
switch (err) {
|
||||
case 0:
|
||||
case -EOPNOTSUPP:
|
||||
/* Both arms leave the output booleans valid. */
|
||||
break;
|
||||
case MSDOS_SUPER_MAGIC:
|
||||
resp->p_case_insensitive = 1;
|
||||
resp->p_case_preserving = 0;
|
||||
case -EACCES:
|
||||
case -EPERM:
|
||||
/*
|
||||
* Policy denied the query. Report STALE so the
|
||||
* handle is unusable without implying a server
|
||||
* malfunction.
|
||||
*/
|
||||
resp->status = nfserr_stale;
|
||||
break;
|
||||
case -ESTALE:
|
||||
resp->status = nfserr_stale;
|
||||
break;
|
||||
default:
|
||||
resp->status = nfserr_serverfault;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3158,6 +3158,8 @@ struct nfsd4_fattr_args {
|
|||
u32 rdattr_err;
|
||||
bool contextsupport;
|
||||
bool ignore_crossmnt;
|
||||
bool case_insensitive;
|
||||
bool case_preserving;
|
||||
};
|
||||
|
||||
typedef __be32(*nfsd4_enc_attr)(struct xdr_stream *xdr,
|
||||
|
|
@ -3356,6 +3358,33 @@ static __be32 nfsd4_encode_fattr4_acl(struct xdr_stream *xdr,
|
|||
return nfs_ok;
|
||||
}
|
||||
|
||||
static __be32 nfsd4_encode_fattr4_case_insensitive(struct xdr_stream *xdr,
|
||||
const struct nfsd4_fattr_args *args)
|
||||
{
|
||||
return nfsd4_encode_bool(xdr, args->case_insensitive);
|
||||
}
|
||||
|
||||
static __be32 nfsd4_encode_fattr4_case_preserving(struct xdr_stream *xdr,
|
||||
const struct nfsd4_fattr_args *args)
|
||||
{
|
||||
return nfsd4_encode_bool(xdr, args->case_preserving);
|
||||
}
|
||||
|
||||
static __be32 nfsd4_encode_fattr4_homogeneous(struct xdr_stream *xdr,
|
||||
const struct nfsd4_fattr_args *args)
|
||||
{
|
||||
/*
|
||||
* Casefold-capable filesystems (e.g. ext4 or f2fs with the
|
||||
* casefold feature) attach a Unicode encoding at mount time
|
||||
* but apply case folding per directory. The per-file-system
|
||||
* case_insensitive and case_preserving values can therefore
|
||||
* legitimately differ across objects that share the same fsid.
|
||||
* Report FATTR4_HOMOGENEOUS = FALSE on such filesystems to
|
||||
* keep that variation consistent with RFC 8881 Section 5.8.2.16.
|
||||
*/
|
||||
return nfsd4_encode_bool(xdr, !sb_has_encoding(args->dentry->d_sb));
|
||||
}
|
||||
|
||||
static __be32 nfsd4_encode_fattr4_filehandle(struct xdr_stream *xdr,
|
||||
const struct nfsd4_fattr_args *args)
|
||||
{
|
||||
|
|
@ -3748,8 +3777,8 @@ static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = {
|
|||
[FATTR4_ACLSUPPORT] = nfsd4_encode_fattr4_aclsupport,
|
||||
[FATTR4_ARCHIVE] = nfsd4_encode_fattr4__noop,
|
||||
[FATTR4_CANSETTIME] = nfsd4_encode_fattr4__true,
|
||||
[FATTR4_CASE_INSENSITIVE] = nfsd4_encode_fattr4__false,
|
||||
[FATTR4_CASE_PRESERVING] = nfsd4_encode_fattr4__true,
|
||||
[FATTR4_CASE_INSENSITIVE] = nfsd4_encode_fattr4_case_insensitive,
|
||||
[FATTR4_CASE_PRESERVING] = nfsd4_encode_fattr4_case_preserving,
|
||||
[FATTR4_CHOWN_RESTRICTED] = nfsd4_encode_fattr4__true,
|
||||
[FATTR4_FILEHANDLE] = nfsd4_encode_fattr4_filehandle,
|
||||
[FATTR4_FILEID] = nfsd4_encode_fattr4_fileid,
|
||||
|
|
@ -3758,7 +3787,7 @@ static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = {
|
|||
[FATTR4_FILES_TOTAL] = nfsd4_encode_fattr4_files_total,
|
||||
[FATTR4_FS_LOCATIONS] = nfsd4_encode_fattr4_fs_locations,
|
||||
[FATTR4_HIDDEN] = nfsd4_encode_fattr4__noop,
|
||||
[FATTR4_HOMOGENEOUS] = nfsd4_encode_fattr4__true,
|
||||
[FATTR4_HOMOGENEOUS] = nfsd4_encode_fattr4_homogeneous,
|
||||
[FATTR4_MAXFILESIZE] = nfsd4_encode_fattr4_maxfilesize,
|
||||
[FATTR4_MAXLINK] = nfsd4_encode_fattr4_maxlink,
|
||||
[FATTR4_MAXNAME] = nfsd4_encode_fattr4_maxname,
|
||||
|
|
@ -3854,13 +3883,16 @@ static const nfsd4_enc_attr nfsd4_enc_fattr4_encode_ops[] = {
|
|||
|
||||
/*
|
||||
* Note: @fhp can be NULL; in this case, we might have to compose the filehandle
|
||||
* ourselves.
|
||||
* ourselves. @case_cache is NULL for callers that encode a single dentry
|
||||
* (GETATTR, the buffer wrapper); READDIR passes a per-request cache so
|
||||
* non-directory children share the parent's case-folding probe result.
|
||||
*/
|
||||
static __be32
|
||||
nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
|
||||
struct svc_fh *fhp, struct svc_export *exp,
|
||||
struct dentry *dentry, const u32 *bmval,
|
||||
int ignore_crossmnt)
|
||||
int ignore_crossmnt,
|
||||
struct nfsd_case_attrs_cache *case_cache)
|
||||
{
|
||||
DECLARE_BITMAP(attr_bitmap, ARRAY_SIZE(nfsd4_enc_fattr4_encode_ops));
|
||||
struct nfs4_delegation *dp = NULL;
|
||||
|
|
@ -3968,6 +4000,47 @@ nfsd4_encode_fattr4(struct svc_rqst *rqstp, struct xdr_stream *xdr,
|
|||
args.fhp = tempfh;
|
||||
} else
|
||||
args.fhp = fhp;
|
||||
if (attrmask[0] & (FATTR4_WORD0_CASE_INSENSITIVE |
|
||||
FATTR4_WORD0_CASE_PRESERVING)) {
|
||||
/*
|
||||
* In a batched encoder (READDIR) every non-directory
|
||||
* child shares the same case-folding answer, so the
|
||||
* directory being read is probed once and the result is
|
||||
* cached. The probe targets case_cache->dir, the held
|
||||
* readdir filehandle's dentry, instead of the child's
|
||||
* locklessly-acquired dentry, which a concurrent rename
|
||||
* could move under an unrelated parent. Directory
|
||||
* entries are queried directly because casefold-capable
|
||||
* filesystems answer per directory.
|
||||
*
|
||||
* Per RFC 8881 Section 18.7.3, an attribute advertised
|
||||
* in SUPPORTED_ATTRS must come back with a value or the
|
||||
* GETATTR must fail. nfsd_get_case_info() fills POSIX
|
||||
* defaults and returns -EOPNOTSUPP when the underlying
|
||||
* filesystem does not expose case state; encode those
|
||||
* defaults so the reply agrees with what SUPPORTED_ATTRS
|
||||
* advertises. Other errors fail the operation as the
|
||||
* spec requires.
|
||||
*/
|
||||
if (case_cache && !d_is_dir(dentry)) {
|
||||
if (!case_cache->valid) {
|
||||
err = nfsd_get_case_info(case_cache->dir,
|
||||
&case_cache->insensitive,
|
||||
&case_cache->preserving);
|
||||
if (err && err != -EOPNOTSUPP)
|
||||
goto out_nfserr;
|
||||
case_cache->valid = true;
|
||||
}
|
||||
args.case_insensitive = case_cache->insensitive;
|
||||
args.case_preserving = case_cache->preserving;
|
||||
} else {
|
||||
err = nfsd_get_case_info(dentry,
|
||||
&args.case_insensitive,
|
||||
&args.case_preserving);
|
||||
if (err && err != -EOPNOTSUPP)
|
||||
goto out_nfserr;
|
||||
}
|
||||
}
|
||||
|
||||
if (attrmask[0] & FATTR4_WORD0_ACL) {
|
||||
err = nfsd4_get_nfs4_acl(rqstp, dentry, &args.acl);
|
||||
|
|
@ -4124,7 +4197,7 @@ __be32 nfsd4_encode_fattr_to_buf(__be32 **p, int words,
|
|||
|
||||
svcxdr_init_encode_from_buffer(&xdr, &dummy, *p, words << 2);
|
||||
ret = nfsd4_encode_fattr4(rqstp, &xdr, fhp, exp, dentry, bmval,
|
||||
ignore_crossmnt);
|
||||
ignore_crossmnt, NULL);
|
||||
*p = xdr.p;
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -4162,6 +4235,7 @@ nfsd4_encode_entry4_fattr(struct nfsd4_readdir *cd, const char *name,
|
|||
struct dentry *dentry;
|
||||
__be32 nfserr;
|
||||
int ignore_crossmnt = 0;
|
||||
bool crossed = false;
|
||||
|
||||
dentry = lookup_one_positive_unlocked(&nop_mnt_idmap,
|
||||
&QSTR_LEN(name, namlen),
|
||||
|
|
@ -4198,11 +4272,18 @@ nfsd4_encode_entry4_fattr(struct nfsd4_readdir *cd, const char *name,
|
|||
nfserr = check_nfsd_access(exp, cd->rd_rqstp, false);
|
||||
if (nfserr)
|
||||
goto out_put;
|
||||
crossed = true;
|
||||
|
||||
}
|
||||
out_encode:
|
||||
/*
|
||||
* A crossed entry no longer shares a parent with the directory
|
||||
* being read, so it must neither consume nor populate the
|
||||
* per-readdir case-folding cache.
|
||||
*/
|
||||
nfserr = nfsd4_encode_fattr4(cd->rd_rqstp, cd->xdr, NULL, exp, dentry,
|
||||
cd->rd_bmval, ignore_crossmnt);
|
||||
cd->rd_bmval, ignore_crossmnt,
|
||||
crossed ? NULL : &cd->rd_case_cache);
|
||||
out_put:
|
||||
dput(dentry);
|
||||
exp_put(exp);
|
||||
|
|
@ -4449,7 +4530,7 @@ nfsd4_encode_getattr(struct nfsd4_compoundres *resp, __be32 nfserr,
|
|||
|
||||
/* obj_attributes */
|
||||
return nfsd4_encode_fattr4(resp->rqstp, xdr, fhp, fhp->fh_export,
|
||||
fhp->fh_dentry, getattr->ga_bmval, 0);
|
||||
fhp->fh_dentry, getattr->ga_bmval, 0, NULL);
|
||||
}
|
||||
|
||||
static __be32
|
||||
|
|
@ -4976,6 +5057,8 @@ static __be32 nfsd4_encode_dirlist4(struct xdr_stream *xdr,
|
|||
readdir->rd_maxcount = maxcount;
|
||||
readdir->common.err = 0;
|
||||
readdir->cookie_offset = 0;
|
||||
readdir->rd_case_cache.dir = readdir->rd_fhp->fh_dentry;
|
||||
readdir->rd_case_cache.valid = false;
|
||||
offset = readdir->rd_cookie;
|
||||
status = nfsd_readdir(readdir->rd_rqstp, readdir->rd_fhp, &offset,
|
||||
&readdir->common, nfsd4_encode_entry4);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/writeback.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/sunrpc/xdr.h>
|
||||
#include <linux/fileattr.h>
|
||||
|
||||
#include "xdr3.h"
|
||||
|
||||
|
|
@ -2891,3 +2892,88 @@ nfsd_permission(struct svc_cred *cred, struct svc_export *exp,
|
|||
|
||||
return err? nfserrno(err) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* nfsd_get_case_info - get case sensitivity info for a dentry
|
||||
* @dentry: dentry to query
|
||||
* @case_insensitive: set to true if name comparison ignores case
|
||||
* @case_preserving: set to true if case is preserved on disk
|
||||
*
|
||||
* On casefold-capable filesystems the flag lives on the directory,
|
||||
* not on its entries, so for a non-directory @dentry the parent is
|
||||
* queried instead. A directory (including an export root, whose
|
||||
* parent lies outside the export) is queried as-is so its own
|
||||
* contents' lookup behavior is reported. NFSD advertises
|
||||
* fattr4_homogeneous as FALSE, so per-directory answers may differ
|
||||
* within an export.
|
||||
*
|
||||
* The probe runs with kernel credentials. case_insensitive and
|
||||
* case_preserving describe the directory's structural lookup
|
||||
* behavior, not the caller's identity; running under the calling
|
||||
* client's mapped credentials would let per-client MAC policy on
|
||||
* the parent directory turn this query into NFS4ERR_ACCESS even
|
||||
* though the underlying property is the same for every client.
|
||||
*
|
||||
* When the filesystem does not expose case-folding state (no
|
||||
* ->fileattr_get, or the callback returns -EOPNOTSUPP /
|
||||
* -ENOIOCTLCMD / -ENOTTY / -EINVAL), the outputs are filled with
|
||||
* POSIX defaults (case-sensitive, case-preserving) on the premise
|
||||
* that a filesystem with case-folding support wires up
|
||||
* fileattr_get.
|
||||
*
|
||||
* Return: 0 with outputs filled, -EOPNOTSUPP with outputs filled
|
||||
* to POSIX defaults, or a negative errno (e.g., -EIO,
|
||||
* -ESTALE, -ENOMEM) with outputs unmodified.
|
||||
*/
|
||||
int
|
||||
nfsd_get_case_info(struct dentry *dentry, bool *case_insensitive,
|
||||
bool *case_preserving)
|
||||
{
|
||||
struct file_kattr fa = {};
|
||||
const struct cred *saved;
|
||||
struct cred *probe;
|
||||
struct dentry *cd;
|
||||
bool put = false;
|
||||
int err;
|
||||
|
||||
if (d_is_dir(dentry)) {
|
||||
cd = dentry;
|
||||
} else {
|
||||
cd = dget_parent(dentry);
|
||||
put = true;
|
||||
}
|
||||
|
||||
probe = prepare_kernel_cred(&init_task);
|
||||
if (!probe) {
|
||||
err = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
saved = override_creds(probe);
|
||||
|
||||
err = vfs_fileattr_get(cd, &fa);
|
||||
|
||||
put_cred(revert_creds(saved));
|
||||
out:
|
||||
if (put)
|
||||
dput(cd);
|
||||
switch (err) {
|
||||
case 0:
|
||||
*case_insensitive = fa.fsx_xflags & FS_XFLAG_CASEFOLD;
|
||||
*case_preserving =
|
||||
!(fa.fsx_xflags & FS_XFLAG_CASENONPRESERVING);
|
||||
return 0;
|
||||
case -EINVAL:
|
||||
case -ENOTTY:
|
||||
case -ENOIOCTLCMD:
|
||||
case -EOPNOTSUPP:
|
||||
/*
|
||||
* Filesystem does not expose case state.
|
||||
* Report POSIX defaults.
|
||||
*/
|
||||
*case_insensitive = false;
|
||||
*case_preserving = true;
|
||||
return -EOPNOTSUPP;
|
||||
default:
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,6 +156,9 @@ __be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *,
|
|||
loff_t *, struct readdir_cd *, nfsd_filldir_t);
|
||||
__be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
|
||||
struct kstatfs *, int access);
|
||||
int nfsd_get_case_info(struct dentry *dentry,
|
||||
bool *case_insensitive,
|
||||
bool *case_preserving);
|
||||
|
||||
__be32 nfsd_permission(struct svc_cred *cred, struct svc_export *exp,
|
||||
struct dentry *dentry, int acc);
|
||||
|
|
|
|||
|
|
@ -209,8 +209,8 @@ struct nfsd3_pathconfres {
|
|||
__u32 p_name_max;
|
||||
__u32 p_no_trunc;
|
||||
__u32 p_chown_restricted;
|
||||
__u32 p_case_insensitive;
|
||||
__u32 p_case_preserving;
|
||||
bool p_case_insensitive;
|
||||
bool p_case_preserving;
|
||||
};
|
||||
|
||||
struct nfsd3_commitres {
|
||||
|
|
|
|||
|
|
@ -432,6 +432,19 @@ struct nfsd4_read {
|
|||
u32 rd_eof; /* response */
|
||||
};
|
||||
|
||||
/*
|
||||
* Cache the case-folding properties of @dir so a batched encoder
|
||||
* (e.g., READDIR) does not re-probe per child. @dir is the
|
||||
* directory being read, held by the request, so it is stable
|
||||
* against rename for the duration of the cache's lifetime.
|
||||
*/
|
||||
struct nfsd_case_attrs_cache {
|
||||
struct dentry *dir;
|
||||
bool valid;
|
||||
bool insensitive;
|
||||
bool preserving;
|
||||
};
|
||||
|
||||
struct nfsd4_readdir {
|
||||
u64 rd_cookie; /* request */
|
||||
nfs4_verifier rd_verf; /* request */
|
||||
|
|
@ -444,6 +457,7 @@ struct nfsd4_readdir {
|
|||
struct readdir_cd common;
|
||||
struct xdr_stream *xdr;
|
||||
int cookie_offset;
|
||||
struct nfsd_case_attrs_cache rd_case_cache;
|
||||
};
|
||||
|
||||
struct nfsd4_release_lockowner {
|
||||
|
|
|
|||
|
|
@ -180,6 +180,34 @@ long ntfs_compat_ioctl(struct file *filp, u32 cmd, unsigned long arg)
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ntfs_fileattr_get - inode_operations::fileattr_get
|
||||
*/
|
||||
int ntfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct ntfs_sb_info *sbi = inode->i_sb->s_fs_info;
|
||||
|
||||
/* Avoid any operation if inode is bad. */
|
||||
if (unlikely(is_bad_ni(ntfs_i(inode))))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* NTFS preserves case (the default). Case sensitivity depends on
|
||||
* mount options: with "nocase", NTFS is case-insensitive;
|
||||
* otherwise it is case-sensitive.
|
||||
*/
|
||||
if (sbi->options->nocase) {
|
||||
fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
|
||||
fa->flags |= FS_CASEFOLD_FL;
|
||||
}
|
||||
if (inode->i_flags & S_IMMUTABLE) {
|
||||
fa->fsx_xflags |= FS_XFLAG_IMMUTABLE;
|
||||
fa->flags |= FS_IMMUTABLE_FL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ntfs_getattr - inode_operations::getattr
|
||||
*/
|
||||
|
|
@ -1547,6 +1575,7 @@ const struct inode_operations ntfs_file_inode_operations = {
|
|||
.get_acl = ntfs_get_acl,
|
||||
.set_acl = ntfs_set_acl,
|
||||
.fiemap = ntfs_fiemap,
|
||||
.fileattr_get = ntfs_fileattr_get,
|
||||
};
|
||||
|
||||
const struct file_operations ntfs_file_operations = {
|
||||
|
|
|
|||
|
|
@ -518,6 +518,7 @@ const struct inode_operations ntfs_dir_inode_operations = {
|
|||
.getattr = ntfs_getattr,
|
||||
.listxattr = ntfs_listxattr,
|
||||
.fiemap = ntfs_fiemap,
|
||||
.fileattr_get = ntfs_fileattr_get,
|
||||
};
|
||||
|
||||
const struct inode_operations ntfs_special_inode_operations = {
|
||||
|
|
|
|||
|
|
@ -529,6 +529,7 @@ bool dir_is_empty(struct inode *dir);
|
|||
extern const struct file_operations ntfs_dir_operations;
|
||||
|
||||
/* Globals from file.c */
|
||||
int ntfs_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
|
||||
int ntfs_getattr(struct mnt_idmap *idmap, const struct path *path,
|
||||
struct kstat *stat, u32 request_mask, u32 flags);
|
||||
int ntfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include <linux/xattr.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/key-type.h>
|
||||
#include <linux/fileattr.h>
|
||||
#include <uapi/linux/magic.h>
|
||||
#include <net/ipv6.h>
|
||||
#include "cifsfs.h"
|
||||
|
|
@ -1165,6 +1166,56 @@ struct file_system_type smb3_fs_type = {
|
|||
MODULE_ALIAS_FS("smb3");
|
||||
MODULE_ALIAS("smb3");
|
||||
|
||||
int cifs_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(dentry->d_sb);
|
||||
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
|
||||
struct inode *inode = d_inode(dentry);
|
||||
u32 attrs;
|
||||
|
||||
/* Preserve FS_COMPR_FL previously reported by cifs_ioctl(). */
|
||||
if (CIFS_I(inode)->cifsAttrs & ATTR_COMPRESSED)
|
||||
fa->flags |= FS_COMPR_FL;
|
||||
|
||||
/*
|
||||
* FS_CASEFOLD_FL is defined by UAPI as a folder attribute,
|
||||
* and userspace tools (e.g., lsattr) display it only on
|
||||
* directories. Confine the case-handling bits to directories
|
||||
* to match that convention; for non-directories the share's
|
||||
* case semantics are still discoverable through the parent.
|
||||
*/
|
||||
if (!S_ISDIR(inode->i_mode))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* The server's FS_ATTRIBUTE_INFORMATION response, cached on
|
||||
* the tcon at mount, reflects the share's case-handling
|
||||
* semantics after any POSIX extensions negotiation. Prefer
|
||||
* it over the client-local nocase mount option, which only
|
||||
* governs dentry comparison on this superblock.
|
||||
*
|
||||
* QueryFSInfo is best-effort at mount; when it did not
|
||||
* populate fsAttrInfo, MaxPathNameComponentLength remains
|
||||
* zero. In that case fall back to nocase so the reporting
|
||||
* matches the comparison behavior installed on the sb.
|
||||
*/
|
||||
if (le32_to_cpu(tcon->fsAttrInfo.MaxPathNameComponentLength) == 0) {
|
||||
if (tcon->nocase) {
|
||||
fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
|
||||
fa->flags |= FS_CASEFOLD_FL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
attrs = le32_to_cpu(tcon->fsAttrInfo.Attributes);
|
||||
if (!(attrs & FILE_CASE_SENSITIVE_SEARCH)) {
|
||||
fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
|
||||
fa->flags |= FS_CASEFOLD_FL;
|
||||
}
|
||||
if (!(attrs & FILE_CASE_PRESERVED_NAMES))
|
||||
fa->fsx_xflags |= FS_XFLAG_CASENONPRESERVING;
|
||||
return 0;
|
||||
}
|
||||
|
||||
const struct inode_operations cifs_dir_inode_ops = {
|
||||
.create = cifs_create,
|
||||
.atomic_open = cifs_atomic_open,
|
||||
|
|
@ -1183,6 +1234,7 @@ const struct inode_operations cifs_dir_inode_ops = {
|
|||
.listxattr = cifs_listxattr,
|
||||
.get_acl = cifs_get_acl,
|
||||
.set_acl = cifs_set_acl,
|
||||
.fileattr_get = cifs_fileattr_get,
|
||||
};
|
||||
|
||||
const struct inode_operations cifs_file_inode_ops = {
|
||||
|
|
@ -1193,6 +1245,7 @@ const struct inode_operations cifs_file_inode_ops = {
|
|||
.fiemap = cifs_fiemap,
|
||||
.get_acl = cifs_get_acl,
|
||||
.set_acl = cifs_set_acl,
|
||||
.fileattr_get = cifs_fileattr_get,
|
||||
};
|
||||
|
||||
const char *cifs_get_link(struct dentry *dentry, struct inode *inode,
|
||||
|
|
|
|||
|
|
@ -89,6 +89,9 @@ extern const struct inode_operations cifs_file_inode_ops;
|
|||
extern const struct inode_operations cifs_symlink_inode_ops;
|
||||
extern const struct inode_operations cifs_namespace_inode_operations;
|
||||
|
||||
struct file_kattr;
|
||||
int cifs_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
|
||||
|
||||
|
||||
/* Functions related to files and directories */
|
||||
extern const struct netfs_request_ops cifs_req_ops;
|
||||
|
|
|
|||
|
|
@ -294,4 +294,5 @@ struct vfsmount *cifs_d_automount(struct path *path)
|
|||
}
|
||||
|
||||
const struct inode_operations cifs_namespace_inode_operations = {
|
||||
.fileattr_get = cifs_fileattr_get,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/falloc.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/filelock.h>
|
||||
#include <linux/fileattr.h>
|
||||
|
||||
#include "glob.h"
|
||||
#include "smbfsctl.h"
|
||||
|
|
@ -5561,16 +5562,33 @@ static int smb2_get_info_filesystem(struct ksmbd_work *work,
|
|||
case FS_ATTRIBUTE_INFORMATION:
|
||||
{
|
||||
FILE_SYSTEM_ATTRIBUTE_INFO *info;
|
||||
struct file_kattr fa = {};
|
||||
size_t sz;
|
||||
u32 attrs;
|
||||
int err;
|
||||
|
||||
info = (FILE_SYSTEM_ATTRIBUTE_INFO *)rsp->Buffer;
|
||||
info->Attributes = cpu_to_le32(FILE_SUPPORTS_OBJECT_IDS |
|
||||
FILE_PERSISTENT_ACLS |
|
||||
FILE_UNICODE_ON_DISK |
|
||||
FILE_CASE_PRESERVED_NAMES |
|
||||
FILE_CASE_SENSITIVE_SEARCH |
|
||||
FILE_SUPPORTS_BLOCK_REFCOUNTING);
|
||||
attrs = FILE_SUPPORTS_OBJECT_IDS |
|
||||
FILE_PERSISTENT_ACLS |
|
||||
FILE_UNICODE_ON_DISK |
|
||||
FILE_SUPPORTS_BLOCK_REFCOUNTING;
|
||||
|
||||
err = vfs_fileattr_get(path.dentry, &fa);
|
||||
/*
|
||||
* -EINVAL, -EOPNOTSUPP: ntfs-3g and other FUSE
|
||||
* filesystems that lack FS_IOC_FSGETXATTR support.
|
||||
*/
|
||||
if (err && err != -ENOIOCTLCMD && err != -ENOTTY &&
|
||||
err != -EINVAL && err != -EOPNOTSUPP) {
|
||||
path_put(&path);
|
||||
return err;
|
||||
}
|
||||
if (!(fa.fsx_xflags & FS_XFLAG_CASEFOLD))
|
||||
attrs |= FILE_CASE_SENSITIVE_SEARCH;
|
||||
if (!(fa.fsx_xflags & FS_XFLAG_CASENONPRESERVING))
|
||||
attrs |= FILE_CASE_PRESERVED_NAMES;
|
||||
|
||||
info->Attributes = cpu_to_le32(attrs);
|
||||
info->Attributes |= cpu_to_le32(server_conf.share_fake_fscaps);
|
||||
|
||||
if (test_share_config_flag(work->tcon->share_conf,
|
||||
|
|
|
|||
|
|
@ -477,4 +477,5 @@ const struct inode_operations vboxsf_dir_iops = {
|
|||
.symlink = vboxsf_dir_symlink,
|
||||
.getattr = vboxsf_getattr,
|
||||
.setattr = vboxsf_setattr,
|
||||
.fileattr_get = vboxsf_fileattr_get,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -222,7 +222,8 @@ const struct file_operations vboxsf_reg_fops = {
|
|||
|
||||
const struct inode_operations vboxsf_reg_iops = {
|
||||
.getattr = vboxsf_getattr,
|
||||
.setattr = vboxsf_setattr
|
||||
.setattr = vboxsf_setattr,
|
||||
.fileattr_get = vboxsf_fileattr_get,
|
||||
};
|
||||
|
||||
static int vboxsf_read_folio(struct file *file, struct folio *folio)
|
||||
|
|
@ -389,5 +390,6 @@ static const char *vboxsf_get_link(struct dentry *dentry, struct inode *inode,
|
|||
}
|
||||
|
||||
const struct inode_operations vboxsf_lnk_iops = {
|
||||
.get_link = vboxsf_get_link
|
||||
.get_link = vboxsf_get_link,
|
||||
.fileattr_get = vboxsf_fileattr_get,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -185,6 +185,13 @@ static int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc)
|
|||
if (err)
|
||||
goto fail_unmap;
|
||||
|
||||
/*
|
||||
* A failed query leaves sbi->case_insensitive false, so the
|
||||
* mount defaults to reporting case-sensitive behavior. Do not
|
||||
* fail the mount over an advisory attribute.
|
||||
*/
|
||||
vboxsf_query_case_sensitive(sbi);
|
||||
|
||||
sb->s_magic = VBOXSF_SUPER_MAGIC;
|
||||
sb->s_blocksize = 1024;
|
||||
sb->s_maxbytes = MAX_LFS_FILESIZE;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
#include <linux/sizes.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/fileattr.h>
|
||||
#include "vfsmod.h"
|
||||
|
||||
struct inode *vboxsf_new_inode(struct super_block *sb)
|
||||
|
|
@ -567,3 +568,32 @@ int vboxsf_dir_read_all(struct vboxsf_sbi *sbi, struct vboxsf_dir_info *sf_d,
|
|||
|
||||
return err;
|
||||
}
|
||||
|
||||
int vboxsf_query_case_sensitive(struct vboxsf_sbi *sbi)
|
||||
{
|
||||
struct shfl_volinfo volinfo = {};
|
||||
u32 buf_len;
|
||||
int err;
|
||||
|
||||
buf_len = sizeof(volinfo);
|
||||
err = vboxsf_fsinfo(sbi->root, 0, SHFL_INFO_GET | SHFL_INFO_VOLUME,
|
||||
&buf_len, &volinfo);
|
||||
if (err)
|
||||
return err;
|
||||
if (buf_len < sizeof(volinfo))
|
||||
return 0;
|
||||
|
||||
sbi->case_insensitive = !volinfo.properties.case_sensitive;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int vboxsf_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
|
||||
{
|
||||
struct vboxsf_sbi *sbi = VBOXSF_SBI(dentry->d_sb);
|
||||
|
||||
if (sbi->case_insensitive) {
|
||||
fa->fsx_xflags |= FS_XFLAG_CASEFOLD;
|
||||
fa->flags |= FS_CASEFOLD_FL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ struct vboxsf_sbi {
|
|||
u32 next_generation;
|
||||
u32 root;
|
||||
int bdi_id;
|
||||
bool case_insensitive;
|
||||
};
|
||||
|
||||
/* per-inode information */
|
||||
|
|
@ -111,6 +112,11 @@ void vboxsf_dir_info_free(struct vboxsf_dir_info *p);
|
|||
int vboxsf_dir_read_all(struct vboxsf_sbi *sbi, struct vboxsf_dir_info *sf_d,
|
||||
u64 handle);
|
||||
|
||||
int vboxsf_query_case_sensitive(struct vboxsf_sbi *sbi);
|
||||
|
||||
struct file_kattr;
|
||||
int vboxsf_fileattr_get(struct dentry *dentry, struct file_kattr *fa);
|
||||
|
||||
/* from vboxsf_wrappers.c */
|
||||
int vboxsf_connect(void);
|
||||
void vboxsf_disconnect(void);
|
||||
|
|
|
|||
|
|
@ -130,6 +130,8 @@ xfs_ip2xflags(
|
|||
|
||||
if (xfs_inode_has_attr_fork(ip))
|
||||
flags |= FS_XFLAG_HASATTR;
|
||||
if (xfs_has_asciici(ip->i_mount))
|
||||
flags |= FS_XFLAG_CASEFOLD;
|
||||
return flags;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -524,7 +524,7 @@ xfs_ioc_fsgetxattra(
|
|||
xfs_inode_t *ip,
|
||||
void __user *arg)
|
||||
{
|
||||
struct file_kattr fa;
|
||||
struct file_kattr fa = {};
|
||||
|
||||
xfs_ilock(ip, XFS_ILOCK_SHARED);
|
||||
xfs_fill_fsxattr(ip, XFS_ATTR_FORK, &fa);
|
||||
|
|
@ -762,9 +762,23 @@ xfs_fileattr_set(
|
|||
trace_xfs_ioctl_setattr(ip);
|
||||
|
||||
if (!fa->fsx_valid) {
|
||||
if (fa->flags & ~(FS_IMMUTABLE_FL | FS_APPEND_FL |
|
||||
FS_NOATIME_FL | FS_NODUMP_FL |
|
||||
FS_SYNC_FL | FS_DAX_FL | FS_PROJINHERIT_FL))
|
||||
unsigned int allowed = FS_IMMUTABLE_FL | FS_APPEND_FL |
|
||||
FS_NOATIME_FL | FS_NODUMP_FL |
|
||||
FS_SYNC_FL | FS_DAX_FL |
|
||||
FS_PROJINHERIT_FL;
|
||||
|
||||
/*
|
||||
* FS_CASEFOLD_FL reflects the ASCIICI superblock feature,
|
||||
* a read-only property. Accept it as a no-op so chattr's
|
||||
* RMW round-trip succeeds; reject any attempt to enable
|
||||
* it on a non-ASCIICI filesystem. xfs_flags2diflags()
|
||||
* has no clause for CASEFOLD, so the bit is dropped from
|
||||
* the on-disk diflags regardless.
|
||||
*/
|
||||
if (xfs_has_asciici(mp))
|
||||
allowed |= FS_CASEFOLD_FL;
|
||||
|
||||
if (fa->flags & ~allowed)
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@
|
|||
|
||||
/* Read-only inode flags */
|
||||
#define FS_XFLAG_RDONLY_MASK \
|
||||
(FS_XFLAG_PREALLOC | FS_XFLAG_HASATTR | FS_XFLAG_VERITY)
|
||||
(FS_XFLAG_PREALLOC | FS_XFLAG_HASATTR | FS_XFLAG_VERITY | \
|
||||
FS_XFLAG_CASEFOLD | FS_XFLAG_CASENONPRESERVING)
|
||||
|
||||
/* Flags to indicate valid value of fsx_ fields */
|
||||
#define FS_XFLAG_VALUES_MASK \
|
||||
|
|
|
|||
|
|
@ -306,7 +306,7 @@ struct nfs_server {
|
|||
#define NFS_CAP_ATOMIC_OPEN (1U << 4)
|
||||
#define NFS_CAP_LGOPEN (1U << 5)
|
||||
#define NFS_CAP_CASE_INSENSITIVE (1U << 6)
|
||||
#define NFS_CAP_CASE_PRESERVING (1U << 7)
|
||||
#define NFS_CAP_CASE_NONPRESERVING (1U << 7)
|
||||
#define NFS_CAP_REBOOT_LAYOUTRETURN (1U << 8)
|
||||
#define NFS_CAP_OFFLOAD_STATUS (1U << 9)
|
||||
#define NFS_CAP_ZERO_RANGE (1U << 10)
|
||||
|
|
|
|||
|
|
@ -182,6 +182,8 @@ struct nfs_pathconf {
|
|||
struct nfs_fattr *fattr; /* Post-op attributes */
|
||||
__u32 max_link; /* max # of hard links */
|
||||
__u32 max_namelen; /* max name length */
|
||||
bool case_insensitive;
|
||||
bool case_preserving;
|
||||
};
|
||||
|
||||
struct nfs4_change_info {
|
||||
|
|
|
|||
|
|
@ -254,6 +254,13 @@ struct file_attr {
|
|||
#define FS_XFLAG_DAX 0x00008000 /* use DAX for IO */
|
||||
#define FS_XFLAG_COWEXTSIZE 0x00010000 /* CoW extent size allocator hint */
|
||||
#define FS_XFLAG_VERITY 0x00020000 /* fs-verity enabled */
|
||||
/*
|
||||
* Case handling flags (read-only, cannot be set via ioctl).
|
||||
* Default (neither set) indicates POSIX semantics: case-sensitive
|
||||
* lookups and case-preserving storage.
|
||||
*/
|
||||
#define FS_XFLAG_CASEFOLD 0x00040000 /* case-insensitive lookups */
|
||||
#define FS_XFLAG_CASENONPRESERVING 0x00080000 /* case not preserved */
|
||||
#define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
|
||||
|
||||
/* the read-only stuff doesn't really belong here, but any other place is
|
||||
|
|
@ -388,7 +395,16 @@ struct file_attr {
|
|||
#define FS_DAX_FL 0x02000000 /* Inode is DAX */
|
||||
#define FS_INLINE_DATA_FL 0x10000000 /* Reserved for ext4 */
|
||||
#define FS_PROJINHERIT_FL 0x20000000 /* Create with parents projid */
|
||||
#define FS_CASEFOLD_FL 0x40000000 /* Folder is case insensitive */
|
||||
/*
|
||||
* FS_CASEFOLD_FL indicates case-insensitive name lookup. The
|
||||
* bit is most often reported on directories, where it controls
|
||||
* lookups of entries within. Filesystems that derive
|
||||
* case-insensitivity from mount or volume state may also report
|
||||
* it on non-directory inodes; userspace must not assume the bit
|
||||
* is directory-only. FS_XFLAG_CASEFOLD reports the same
|
||||
* information read-only via FS_IOC_FSGETXATTR.
|
||||
*/
|
||||
#define FS_CASEFOLD_FL 0x40000000
|
||||
#define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
|
||||
|
||||
#define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */
|
||||
|
|
|
|||
|
|
@ -254,6 +254,13 @@ struct file_attr {
|
|||
#define FS_XFLAG_DAX 0x00008000 /* use DAX for IO */
|
||||
#define FS_XFLAG_COWEXTSIZE 0x00010000 /* CoW extent size allocator hint */
|
||||
#define FS_XFLAG_VERITY 0x00020000 /* fs-verity enabled */
|
||||
/*
|
||||
* Case handling flags (read-only, cannot be set via ioctl).
|
||||
* Default (neither set) indicates POSIX semantics: case-sensitive
|
||||
* lookups and case-preserving storage.
|
||||
*/
|
||||
#define FS_XFLAG_CASEFOLD 0x00040000 /* case-insensitive lookups */
|
||||
#define FS_XFLAG_CASENONPRESERVING 0x00080000 /* case not preserved */
|
||||
#define FS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */
|
||||
|
||||
/* the read-only stuff doesn't really belong here, but any other place is
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user