diff mbox

[NOMERGE,01/13] vfs: Add support for mounting with MS_CASEFOLD

Message ID 20180522203818.14666-2-krisman@collabora.co.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Gabriel Krisman Bertazi May 22, 2018, 8:38 p.m. UTC
At this point, negative dentries are ignored for LOOKUP_CASEFOLD.  This
will be addressed later in the series.

Signed-off-by: Gabriel Krisman Bertazi <krisman@collabora.co.uk>
---
 fs/namei.c              | 27 +++++++++++++++++++++++++--
 fs/namespace.c          | 11 ++++++++++-
 include/linux/fs.h      |  2 ++
 include/linux/mount.h   |  1 +
 include/linux/namei.h   |  1 +
 include/uapi/linux/fs.h |  1 +
 6 files changed, 40 insertions(+), 3 deletions(-)
diff mbox

Patch

diff --git a/fs/namei.c b/fs/namei.c
index 921ae32dbc80..ddd5c9e9ab3c 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -761,8 +761,15 @@  static inline int d_revalidate(struct dentry *dentry, unsigned int flags)
 {
 	if (unlikely(dentry->d_flags & DCACHE_OP_REVALIDATE))
 		return dentry->d_op->d_revalidate(dentry, flags);
-	else
-		return 1;
+
+	/* Completely ignore negative dentries
+	   for LOOKUP_CASEFOLD. */
+	if (unlikely(flags & LOOKUP_CASEFOLD)) {
+		if (d_is_negative(dentry))
+			return 0;
+	}
+
+	return 1;
 }
 
 /**
@@ -1159,6 +1166,15 @@  static int follow_automount(struct path *path, struct nameidata *nd,
 
 }
 
+static void set_casefold_lookup(struct nameidata *nd, struct path *path)
+{
+	if (path && path->mnt &&
+	    path->mnt->mnt_flags & MNT_CASEFOLD)
+		nd->flags |= LOOKUP_CASEFOLD;
+	else
+		nd->flags &= ~LOOKUP_CASEFOLD;
+}
+
 /*
  * Handle a dentry that is managed in some way.
  * - Flagged for transit management (autofs)
@@ -1202,6 +1218,7 @@  static int follow_managed(struct path *path, struct nameidata *nd)
 				path->mnt = mounted;
 				path->dentry = dget(mounted->mnt_root);
 				need_mntput = true;
+				set_casefold_lookup(nd, path);
 				continue;
 			}
 
@@ -1288,6 +1305,7 @@  static bool __follow_mount_rcu(struct nameidata *nd, struct path *path,
 		path->mnt = &mounted->mnt;
 		path->dentry = mounted->mnt.mnt_root;
 		nd->flags |= LOOKUP_JUMPED;
+		set_casefold_lookup(nd, path);
 		*seqp = read_seqcount_begin(&path->dentry->d_seq);
 		/*
 		 * Update the inode too. We don't need to re-check the
@@ -1336,6 +1354,7 @@  static int follow_dotdot_rcu(struct nameidata *nd)
 			nd->path.mnt = &mparent->mnt;
 			inode = inode2;
 			nd->seq = seq;
+			set_casefold_lookup(nd, &nd->path);
 		}
 	}
 	while (unlikely(d_mountpoint(nd->path.dentry))) {
@@ -1350,6 +1369,7 @@  static int follow_dotdot_rcu(struct nameidata *nd)
 		inode = nd->path.dentry->d_inode;
 		nd->seq = read_seqcount_begin(&nd->path.dentry->d_seq);
 	}
+	set_casefold_lookup(nd, &nd->path);
 	nd->inode = inode;
 	return 0;
 }
@@ -2143,6 +2163,7 @@  static const char *path_init(struct nameidata *nd, unsigned flags)
 		} else {
 			path_get(&nd->path);
 		}
+		set_casefold_lookup(nd, &nd->path);
 		return s;
 	}
 
@@ -2177,6 +2198,7 @@  static const char *path_init(struct nameidata *nd, unsigned flags)
 			get_fs_pwd(current->fs, &nd->path);
 			nd->inode = nd->path.dentry->d_inode;
 		}
+		set_casefold_lookup(nd, &nd->path);
 		return s;
 	} else {
 		/* Caller must check execute permissions on the starting path component */
@@ -2205,6 +2227,7 @@  static const char *path_init(struct nameidata *nd, unsigned flags)
 			nd->inode = nd->path.dentry->d_inode;
 		}
 		fdput(f);
+		set_casefold_lookup(nd, &nd->path);
 		return s;
 	}
 }
diff --git a/fs/namespace.c b/fs/namespace.c
index 9d1374ab6e06..0053e29b73cc 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -2509,6 +2509,12 @@  static int do_new_mount(struct path *path, const char *fstype, int sb_flags,
 	if (!type)
 		return -ENODEV;
 
+	if (mnt_flags & MNT_CASEFOLD &&
+	    !(type->fs_flags & FS_HAS_CASEFOLD)) {
+		put_filesystem(type);
+		return -EINVAL;
+	}
+
 	mnt = vfs_kern_mount(type, sb_flags, name, data);
 	if (!IS_ERR(mnt) && (type->fs_flags & FS_HAS_SUBTYPE) &&
 	    !mnt->mnt_sb->s_subtype)
@@ -2809,6 +2815,8 @@  long do_mount(const char *dev_name, const char __user *dir_name,
 		mnt_flags |= MNT_NODIRATIME;
 	if (flags & MS_STRICTATIME)
 		mnt_flags &= ~(MNT_RELATIME | MNT_NOATIME);
+	if (flags & MS_CASEFOLD)
+		mnt_flags |= MNT_CASEFOLD;
 	if (flags & SB_RDONLY)
 		mnt_flags |= MNT_READONLY;
 
@@ -2827,7 +2835,8 @@  long do_mount(const char *dev_name, const char __user *dir_name,
 			    SB_SILENT |
 			    SB_POSIXACL |
 			    SB_LAZYTIME |
-			    SB_I_VERSION);
+			    SB_I_VERSION |
+			    SB_CASEFOLD);
 
 	if (flags & MS_REMOUNT)
 		retval = do_remount(&path, flags, sb_flags, mnt_flags,
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 2a815560fda0..743d38876a51 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -1287,6 +1287,7 @@  extern int send_sigurg(struct fown_struct *fown);
 #define SB_SYNCHRONOUS	16	/* Writes are synced at once */
 #define SB_MANDLOCK	64	/* Allow mandatory locks on an FS */
 #define SB_DIRSYNC	128	/* Directory modifications are synchronous */
+#define SB_CASEFOLD	256	/* Directory lookups are case-insensitive */
 #define SB_NOATIME	1024	/* Do not update access times. */
 #define SB_NODIRATIME	2048	/* Do not update directory access times */
 #define SB_SILENT	32768
@@ -2069,6 +2070,7 @@  struct file_system_type {
 #define FS_BINARY_MOUNTDATA	2
 #define FS_HAS_SUBTYPE		4
 #define FS_USERNS_MOUNT		8	/* Can be mounted by userns root */
+#define FS_HAS_CASEFOLD	        16
 #define FS_RENAME_DOES_D_MOVE	32768	/* FS will handle d_move() during rename() internally. */
 	struct dentry *(*mount) (struct file_system_type *, int,
 		       const char *, void *);
diff --git a/include/linux/mount.h b/include/linux/mount.h
index 45b1f56c6c2f..05f5d6f71108 100644
--- a/include/linux/mount.h
+++ b/include/linux/mount.h
@@ -52,6 +52,7 @@  struct mnt_namespace;
 			    MNT_DOOMED | MNT_SYNC_UMOUNT | MNT_MARKED)
 
 #define MNT_INTERNAL	0x4000
+#define MNT_CASEFOLD	0x8000
 
 #define MNT_LOCK_ATIME		0x040000
 #define MNT_LOCK_NOEXEC		0x080000
diff --git a/include/linux/namei.h b/include/linux/namei.h
index a982bb7cd480..fb74ab4c86f3 100644
--- a/include/linux/namei.h
+++ b/include/linux/namei.h
@@ -46,6 +46,7 @@  enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
 #define LOOKUP_ROOT		0x2000
 #define LOOKUP_EMPTY		0x4000
 #define LOOKUP_DOWN		0x8000
+#define LOOKUP_CASEFOLD	      0x010000
 
 extern int path_pts(struct path *path);
 
diff --git a/include/uapi/linux/fs.h b/include/uapi/linux/fs.h
index d2a8313fabd7..7fa23e5f49d6 100644
--- a/include/uapi/linux/fs.h
+++ b/include/uapi/linux/fs.h
@@ -113,6 +113,7 @@  struct inodes_stat_t {
 #define MS_REMOUNT	32	/* Alter flags of a mounted FS */
 #define MS_MANDLOCK	64	/* Allow mandatory locks on an FS */
 #define MS_DIRSYNC	128	/* Directory modifications are synchronous */
+#define MS_CASEFOLD	256	/* Directory lookups are case-insensitive */
 #define MS_NOATIME	1024	/* Do not update access times. */
 #define MS_NODIRATIME	2048	/* Do not update directory access times */
 #define MS_BIND		4096