aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMiklos Szeredi <mszeredi@redhat.com>2016-07-29 06:05:24 -0400
committerMiklos Szeredi <mszeredi@redhat.com>2016-07-29 06:05:24 -0400
commit39b681f8026c170a73972517269efc830db0d7ce (patch)
tree592a1c87e7b3f16d5422577ee9aa9bd6e93f49e9
parenta999d7e161a085e30181d0a88f049bd92112e172 (diff)
ovl: store real inode pointer in ->i_private
To get from overlay inode to real inode we currently use 'struct ovl_entry', which has lifetime connected to overlay dentry. This is okay, since each overlay dentry had a new overlay inode allocated. Following patch will break that assumption, so need to leave out ovl_entry. This patch stores the real inode directly in i_private, with the lowest bit used to indicate whether the inode is upper or lower. Lifetime rules remain, using ovl_inode_real() must only be done while caller holds ref on overlay dentry (and hence on real dentry), or within RCU protected regions. Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
-rw-r--r--fs/overlayfs/copy_up.c1
-rw-r--r--fs/overlayfs/dir.c3
-rw-r--r--fs/overlayfs/inode.c11
-rw-r--r--fs/overlayfs/overlayfs.h18
-rw-r--r--fs/overlayfs/super.c44
5 files changed, 40 insertions, 37 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 80aa6f1eb336..54e5d6681786 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -292,6 +292,7 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
292 goto out_cleanup; 292 goto out_cleanup;
293 293
294 ovl_dentry_update(dentry, newdentry); 294 ovl_dentry_update(dentry, newdentry);
295 ovl_inode_update(d_inode(dentry), d_inode(newdentry));
295 newdentry = NULL; 296 newdentry = NULL;
296 297
297 /* 298 /*
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index b4eac8173f93..96b1bdcf3674 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -167,6 +167,7 @@ static void ovl_instantiate(struct dentry *dentry, struct inode *inode,
167{ 167{
168 ovl_dentry_version_inc(dentry->d_parent); 168 ovl_dentry_version_inc(dentry->d_parent);
169 ovl_dentry_update(dentry, newdentry); 169 ovl_dentry_update(dentry, newdentry);
170 ovl_inode_update(inode, d_inode(newdentry));
170 ovl_copyattr(newdentry->d_inode, inode); 171 ovl_copyattr(newdentry->d_inode, inode);
171 d_instantiate(dentry, inode); 172 d_instantiate(dentry, inode);
172} 173}
@@ -416,7 +417,7 @@ static int ovl_create_or_link(struct dentry *dentry, int mode, dev_t rdev,
416 }; 417 };
417 418
418 err = -ENOMEM; 419 err = -ENOMEM;
419 inode = ovl_new_inode(dentry->d_sb, mode, dentry->d_fsdata); 420 inode = ovl_new_inode(dentry->d_sb, mode);
420 if (!inode) 421 if (!inode)
421 goto out; 422 goto out;
422 423
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 0598c169ce41..2bdd3cae0f71 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -117,15 +117,12 @@ static int ovl_getattr(struct vfsmount *mnt, struct dentry *dentry,
117 117
118int ovl_permission(struct inode *inode, int mask) 118int ovl_permission(struct inode *inode, int mask)
119{ 119{
120 struct ovl_entry *oe = inode->i_private;
121 bool is_upper; 120 bool is_upper;
122 struct dentry *realdentry = ovl_entry_real(oe, &is_upper); 121 struct inode *realinode = ovl_inode_real(inode, &is_upper);
123 struct inode *realinode;
124 const struct cred *old_cred; 122 const struct cred *old_cred;
125 int err; 123 int err;
126 124
127 /* Careful in RCU walk mode */ 125 /* Careful in RCU walk mode */
128 realinode = d_inode_rcu(realdentry);
129 if (!realinode) { 126 if (!realinode) {
130 WARN_ON(!(mask & MAY_NOT_BLOCK)); 127 WARN_ON(!(mask & MAY_NOT_BLOCK));
131 return -ECHILD; 128 return -ECHILD;
@@ -312,7 +309,7 @@ out:
312 309
313struct posix_acl *ovl_get_acl(struct inode *inode, int type) 310struct posix_acl *ovl_get_acl(struct inode *inode, int type)
314{ 311{
315 struct inode *realinode = ovl_inode_real(inode); 312 struct inode *realinode = ovl_inode_real(inode, NULL);
316 const struct cred *old_cred; 313 const struct cred *old_cred;
317 struct posix_acl *acl; 314 struct posix_acl *acl;
318 315
@@ -412,8 +409,7 @@ static const struct inode_operations ovl_symlink_inode_operations = {
412 .update_time = ovl_update_time, 409 .update_time = ovl_update_time,
413}; 410};
414 411
415struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, 412struct inode *ovl_new_inode(struct super_block *sb, umode_t mode)
416 struct ovl_entry *oe)
417{ 413{
418 struct inode *inode; 414 struct inode *inode;
419 415
@@ -424,7 +420,6 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
424 inode->i_ino = get_next_ino(); 420 inode->i_ino = get_next_ino();
425 inode->i_mode = mode; 421 inode->i_mode = mode;
426 inode->i_flags |= S_NOCMTIME; 422 inode->i_flags |= S_NOCMTIME;
427 inode->i_private = oe;
428 423
429 mode &= S_IFMT; 424 mode &= S_IFMT;
430 switch (mode) { 425 switch (mode) {
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index fb73c09a84e7..6410209ea616 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -27,6 +27,8 @@ enum ovl_path_type {
27#define OVL_XATTR_PRE_LEN 16 27#define OVL_XATTR_PRE_LEN 16
28#define OVL_XATTR_OPAQUE OVL_XATTR_PRE_NAME"opaque" 28#define OVL_XATTR_OPAQUE OVL_XATTR_PRE_NAME"opaque"
29 29
30#define OVL_ISUPPER_MASK 1UL
31
30static inline int ovl_do_rmdir(struct inode *dir, struct dentry *dentry) 32static inline int ovl_do_rmdir(struct inode *dir, struct dentry *dentry)
31{ 33{
32 int err = vfs_rmdir(dir, dentry); 34 int err = vfs_rmdir(dir, dentry);
@@ -131,6 +133,16 @@ static inline int ovl_do_whiteout(struct inode *dir, struct dentry *dentry)
131 return err; 133 return err;
132} 134}
133 135
136static inline struct inode *ovl_inode_real(struct inode *inode, bool *is_upper)
137{
138 unsigned long x = (unsigned long) READ_ONCE(inode->i_private);
139
140 if (is_upper)
141 *is_upper = x & OVL_ISUPPER_MASK;
142
143 return (struct inode *) (x & ~OVL_ISUPPER_MASK);
144}
145
134enum ovl_path_type ovl_path_type(struct dentry *dentry); 146enum ovl_path_type ovl_path_type(struct dentry *dentry);
135u64 ovl_dentry_version_get(struct dentry *dentry); 147u64 ovl_dentry_version_get(struct dentry *dentry);
136void ovl_dentry_version_inc(struct dentry *dentry); 148void ovl_dentry_version_inc(struct dentry *dentry);
@@ -141,8 +153,6 @@ int ovl_path_next(int idx, struct dentry *dentry, struct path *path);
141struct dentry *ovl_dentry_upper(struct dentry *dentry); 153struct dentry *ovl_dentry_upper(struct dentry *dentry);
142struct dentry *ovl_dentry_lower(struct dentry *dentry); 154struct dentry *ovl_dentry_lower(struct dentry *dentry);
143struct dentry *ovl_dentry_real(struct dentry *dentry); 155struct dentry *ovl_dentry_real(struct dentry *dentry);
144struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper);
145struct inode *ovl_inode_real(struct inode *inode);
146struct vfsmount *ovl_entry_mnt_real(struct ovl_entry *oe, struct inode *inode, 156struct vfsmount *ovl_entry_mnt_real(struct ovl_entry *oe, struct inode *inode,
147 bool is_upper); 157 bool is_upper);
148struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry); 158struct ovl_dir_cache *ovl_dir_cache(struct dentry *dentry);
@@ -155,6 +165,7 @@ void ovl_dentry_set_opaque(struct dentry *dentry, bool opaque);
155bool ovl_is_whiteout(struct dentry *dentry); 165bool ovl_is_whiteout(struct dentry *dentry);
156const struct cred *ovl_override_creds(struct super_block *sb); 166const struct cred *ovl_override_creds(struct super_block *sb);
157void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry); 167void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry);
168void ovl_inode_update(struct inode *inode, struct inode *upperinode);
158struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, 169struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
159 unsigned int flags); 170 unsigned int flags);
160struct file *ovl_path_open(struct path *path, int flags); 171struct file *ovl_path_open(struct path *path, int flags);
@@ -183,8 +194,7 @@ struct posix_acl *ovl_get_acl(struct inode *inode, int type);
183int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags); 194int ovl_open_maybe_copy_up(struct dentry *dentry, unsigned int file_flags);
184int ovl_update_time(struct inode *inode, struct timespec *ts, int flags); 195int ovl_update_time(struct inode *inode, struct timespec *ts, int flags);
185 196
186struct inode *ovl_new_inode(struct super_block *sb, umode_t mode, 197struct inode *ovl_new_inode(struct super_block *sb, umode_t mode);
187 struct ovl_entry *oe);
188static inline void ovl_copyattr(struct inode *from, struct inode *to) 198static inline void ovl_copyattr(struct inode *from, struct inode *to)
189{ 199{
190 to->i_uid = from->i_uid; 200 to->i_uid = from->i_uid;
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c
index 058103c60f54..313f773652ff 100644
--- a/fs/overlayfs/super.c
+++ b/fs/overlayfs/super.c
@@ -145,25 +145,11 @@ struct dentry *ovl_dentry_real(struct dentry *dentry)
145 return realdentry; 145 return realdentry;
146} 146}
147 147
148struct dentry *ovl_entry_real(struct ovl_entry *oe, bool *is_upper) 148static void ovl_inode_init(struct inode *inode, struct inode *realinode,
149 bool is_upper)
149{ 150{
150 struct dentry *realdentry; 151 WRITE_ONCE(inode->i_private, (unsigned long) realinode |
151 152 (is_upper ? OVL_ISUPPER_MASK : 0));
152 realdentry = ovl_upperdentry_dereference(oe);
153 if (realdentry) {
154 *is_upper = true;
155 } else {
156 realdentry = __ovl_dentry_lower(oe);
157 *is_upper = false;
158 }
159 return realdentry;
160}
161
162struct inode *ovl_inode_real(struct inode *inode)
163{
164 bool tmp;
165
166 return d_inode(ovl_entry_real(inode->i_private, &tmp));
167} 153}
168 154
169struct vfsmount *ovl_entry_mnt_real(struct ovl_entry *oe, struct inode *inode, 155struct vfsmount *ovl_entry_mnt_real(struct ovl_entry *oe, struct inode *inode,
@@ -235,7 +221,6 @@ void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry)
235 221
236 WARN_ON(!inode_is_locked(upperdentry->d_parent->d_inode)); 222 WARN_ON(!inode_is_locked(upperdentry->d_parent->d_inode));
237 WARN_ON(oe->__upperdentry); 223 WARN_ON(oe->__upperdentry);
238 BUG_ON(!upperdentry->d_inode);
239 /* 224 /*
240 * Make sure upperdentry is consistent before making it visible to 225 * Make sure upperdentry is consistent before making it visible to
241 * ovl_upperdentry_dereference(). 226 * ovl_upperdentry_dereference().
@@ -244,6 +229,13 @@ void ovl_dentry_update(struct dentry *dentry, struct dentry *upperdentry)
244 oe->__upperdentry = upperdentry; 229 oe->__upperdentry = upperdentry;
245} 230}
246 231
232void ovl_inode_update(struct inode *inode, struct inode *upperinode)
233{
234 WARN_ON(!upperinode);
235 WRITE_ONCE(inode->i_private,
236 (unsigned long) upperinode | OVL_ISUPPER_MASK);
237}
238
247void ovl_dentry_version_inc(struct dentry *dentry) 239void ovl_dentry_version_inc(struct dentry *dentry)
248{ 240{
249 struct ovl_entry *oe = dentry->d_fsdata; 241 struct ovl_entry *oe = dentry->d_fsdata;
@@ -574,14 +566,16 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
574 566
575 if (upperdentry || ctr) { 567 if (upperdentry || ctr) {
576 struct dentry *realdentry; 568 struct dentry *realdentry;
569 struct inode *realinode;
577 570
578 realdentry = upperdentry ? upperdentry : stack[0].dentry; 571 realdentry = upperdentry ? upperdentry : stack[0].dentry;
572 realinode = d_inode(realdentry);
579 573
580 err = -ENOMEM; 574 err = -ENOMEM;
581 inode = ovl_new_inode(dentry->d_sb, realdentry->d_inode->i_mode, 575 inode = ovl_new_inode(dentry->d_sb, realinode->i_mode);
582 oe);
583 if (!inode) 576 if (!inode)
584 goto out_free_oe; 577 goto out_free_oe;
578 ovl_inode_init(inode, realinode, !!upperdentry);
585 ovl_copyattr(realdentry->d_inode, inode); 579 ovl_copyattr(realdentry->d_inode, inode);
586 } 580 }
587 581
@@ -969,6 +963,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
969 struct path upperpath = { NULL, NULL }; 963 struct path upperpath = { NULL, NULL };
970 struct path workpath = { NULL, NULL }; 964 struct path workpath = { NULL, NULL };
971 struct dentry *root_dentry; 965 struct dentry *root_dentry;
966 struct inode *realinode;
972 struct ovl_entry *oe; 967 struct ovl_entry *oe;
973 struct ovl_fs *ufs; 968 struct ovl_fs *ufs;
974 struct path *stack = NULL; 969 struct path *stack = NULL;
@@ -1150,7 +1145,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
1150 if (!oe) 1145 if (!oe)
1151 goto out_put_cred; 1146 goto out_put_cred;
1152 1147
1153 root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR, oe)); 1148 root_dentry = d_make_root(ovl_new_inode(sb, S_IFDIR));
1154 if (!root_dentry) 1149 if (!root_dentry)
1155 goto out_free_oe; 1150 goto out_free_oe;
1156 1151
@@ -1169,8 +1164,9 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
1169 1164
1170 root_dentry->d_fsdata = oe; 1165 root_dentry->d_fsdata = oe;
1171 1166
1172 ovl_copyattr(ovl_dentry_real(root_dentry)->d_inode, 1167 realinode = d_inode(ovl_dentry_real(root_dentry));
1173 root_dentry->d_inode); 1168 ovl_inode_init(d_inode(root_dentry), realinode, !!upperpath.dentry);
1169 ovl_copyattr(realinode, d_inode(root_dentry));
1174 1170
1175 sb->s_magic = OVERLAYFS_SUPER_MAGIC; 1171 sb->s_magic = OVERLAYFS_SUPER_MAGIC;
1176 sb->s_op = &ovl_super_operations; 1172 sb->s_op = &ovl_super_operations;