summaryrefslogtreecommitdiff
path: root/fs/overlayfs/ovl_entry.h
diff options
context:
space:
mode:
Diffstat (limited to 'fs/overlayfs/ovl_entry.h')
-rw-r--r--fs/overlayfs/ovl_entry.h107
1 files changed, 77 insertions, 30 deletions
diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h
index e1af8f660698..1d4828dbcf7a 100644
--- a/fs/overlayfs/ovl_entry.h
+++ b/fs/overlayfs/ovl_entry.h
@@ -6,15 +6,14 @@
*/
struct ovl_config {
- char *lowerdir;
char *upperdir;
char *workdir;
+ char **lowerdirs;
bool default_permissions;
- bool redirect_dir;
- bool redirect_follow;
- const char *redirect_mode;
+ int redirect_mode;
+ int verity_mode;
bool index;
- bool uuid;
+ int uuid;
bool nfs_export;
int xino;
bool metacopy;
@@ -32,6 +31,7 @@ struct ovl_sb {
};
struct ovl_layer {
+ /* ovl_free_fs() relies on @mnt being the first member! */
struct vfsmount *mnt;
/* Trap in ovl inode cache */
struct inode *trap;
@@ -40,6 +40,8 @@ struct ovl_layer {
int idx;
/* One fsid per unique underlying sb (upper fsid == 0) */
int fsid;
+ /* xwhiteouts were found on this layer */
+ bool has_xwhiteouts;
};
struct ovl_path {
@@ -47,19 +49,24 @@ struct ovl_path {
struct dentry *dentry;
};
+struct ovl_entry {
+ unsigned int __numlower;
+ struct ovl_path __lowerstack[] __counted_by(__numlower);
+};
+
/* private information held for overlayfs's superblock */
struct ovl_fs {
unsigned int numlayer;
/* Number of unique fs among layers including upper fs */
unsigned int numfs;
- const struct ovl_layer *layers;
+ /* Number of data-only lower layers */
+ unsigned int numdatalayer;
+ struct ovl_layer *layers;
struct ovl_sb *fs;
/* workbasedir is the path at workdir= mount option */
struct dentry *workbasedir;
- /* workdir is the 'work' directory under workbasedir */
+ /* workdir is the 'work' or 'index' directory under workbasedir */
struct dentry *workdir;
- /* index directory listing overlay inodes by origin file handle */
- struct dentry *indexdir;
long namelen;
/* pathnames of lower and upper dirs, for show_options */
struct ovl_config config;
@@ -67,36 +74,49 @@ struct ovl_fs {
const struct cred *creator_cred;
bool tmpfile;
bool noxattr;
+ bool nofh;
/* Did we take the inuse lock? */
bool upperdir_locked;
bool workdir_locked;
- bool share_whiteout;
/* Traps in ovl inode cache */
struct inode *workbasedir_trap;
struct inode *workdir_trap;
- struct inode *indexdir_trap;
/* -1: disabled, 0: same fs, 1..32: number of unused ino bits */
int xino_mode;
/* For allocation of non-persistent inode numbers */
atomic_long_t last_ino;
- /* Whiteout dentry cache */
+ /* Shared whiteout cache */
struct dentry *whiteout;
+ bool no_shared_whiteout;
+ struct mutex whiteout_lock;
/* r/o snapshot of upperdir sb's only taken on volatile mounts */
errseq_t errseq;
+ bool casefold;
};
+/* Number of lower layers, not including data-only layers */
+static inline unsigned int ovl_numlowerlayer(struct ovl_fs *ofs)
+{
+ return ofs->numlayer - ofs->numdatalayer - 1;
+}
+
static inline struct vfsmount *ovl_upper_mnt(struct ovl_fs *ofs)
{
return ofs->layers[0].mnt;
}
-static inline struct user_namespace *ovl_upper_mnt_userns(struct ovl_fs *ofs)
+static inline struct mnt_idmap *ovl_upper_mnt_idmap(struct ovl_fs *ofs)
{
- return mnt_user_ns(ovl_upper_mnt(ofs));
+ return mnt_idmap(ovl_upper_mnt(ofs));
}
+extern struct file_system_type ovl_fs_type;
+
static inline struct ovl_fs *OVL_FS(struct super_block *sb)
{
+ if (IS_ENABLED(CONFIG_OVERLAY_FS_DEBUG))
+ WARN_ON_ONCE(sb->s_type != &ovl_fs_type);
+
return (struct ovl_fs *)sb->s_fs_info;
}
@@ -105,36 +125,53 @@ static inline bool ovl_should_sync(struct ovl_fs *ofs)
return !ofs->config.ovl_volatile;
}
-/* private information held for every overlayfs dentry */
-struct ovl_entry {
- union {
- struct {
- unsigned long flags;
- };
- struct rcu_head rcu;
- };
- unsigned numlower;
- struct ovl_path lowerstack[];
-};
+static inline unsigned int ovl_numlower(struct ovl_entry *oe)
+{
+ return oe ? oe->__numlower : 0;
+}
-struct ovl_entry *ovl_alloc_entry(unsigned int numlower);
+static inline struct ovl_path *ovl_lowerstack(struct ovl_entry *oe)
+{
+ return ovl_numlower(oe) ? oe->__lowerstack : NULL;
+}
-static inline struct ovl_entry *OVL_E(struct dentry *dentry)
+static inline struct ovl_path *ovl_lowerpath(struct ovl_entry *oe)
{
- return (struct ovl_entry *) dentry->d_fsdata;
+ return ovl_lowerstack(oe);
+}
+
+static inline struct ovl_path *ovl_lowerdata(struct ovl_entry *oe)
+{
+ struct ovl_path *lowerstack = ovl_lowerstack(oe);
+
+ return lowerstack ? &lowerstack[oe->__numlower - 1] : NULL;
+}
+
+/* May return NULL if lazy lookup of lowerdata is needed */
+static inline struct dentry *ovl_lowerdata_dentry(struct ovl_entry *oe)
+{
+ struct ovl_path *lowerdata = ovl_lowerdata(oe);
+
+ return lowerdata ? READ_ONCE(lowerdata->dentry) : NULL;
+}
+
+/* private information held for every overlayfs dentry */
+static inline unsigned long *OVL_E_FLAGS(struct dentry *dentry)
+{
+ return (unsigned long *) &dentry->d_fsdata;
}
struct ovl_inode {
union {
struct ovl_dir_cache *cache; /* directory */
- struct inode *lowerdata; /* regular file */
+ const char *lowerdata_redirect; /* regular file */
};
const char *redirect;
u64 version;
unsigned long flags;
struct inode vfs_inode;
struct dentry *__upperdentry;
- struct ovl_path lowerpath;
+ struct ovl_entry *oe;
/* synchronize copy up and more */
struct mutex lock;
@@ -145,6 +182,16 @@ static inline struct ovl_inode *OVL_I(struct inode *inode)
return container_of(inode, struct ovl_inode, vfs_inode);
}
+static inline struct ovl_entry *OVL_I_E(struct inode *inode)
+{
+ return inode ? OVL_I(inode)->oe : NULL;
+}
+
+static inline struct ovl_entry *OVL_E(struct dentry *dentry)
+{
+ return OVL_I_E(d_inode(dentry));
+}
+
static inline struct dentry *ovl_upperdentry_dereference(struct ovl_inode *oi)
{
return READ_ONCE(oi->__upperdentry);