aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/overlayfs/dir.c59
-rw-r--r--fs/overlayfs/inode.c12
-rw-r--r--fs/overlayfs/overlayfs.h1
3 files changed, 60 insertions, 12 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index e8c7df070fed..f480b1a2cd2e 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -229,24 +229,54 @@ static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry)
229 return ovl_set_opaque_xerr(dentry, upperdentry, -EIO); 229 return ovl_set_opaque_xerr(dentry, upperdentry, -EIO);
230} 230}
231 231
232/* Common operations required to be done after creation of file on upper */ 232/*
233static void ovl_instantiate(struct dentry *dentry, struct inode *inode, 233 * Common operations required to be done after creation of file on upper.
234 struct dentry *newdentry, bool hardlink) 234 * If @hardlink is false, then @inode is a pre-allocated inode, we may or
235 * may not use to instantiate the new dentry.
236 */
237static int ovl_instantiate(struct dentry *dentry, struct inode *inode,
238 struct dentry *newdentry, bool hardlink)
235{ 239{
240 struct ovl_inode_params oip = {
241 .upperdentry = newdentry,
242 .newinode = inode,
243 };
244
236 ovl_dentry_version_inc(dentry->d_parent, false); 245 ovl_dentry_version_inc(dentry->d_parent, false);
237 ovl_dentry_set_upper_alias(dentry); 246 ovl_dentry_set_upper_alias(dentry);
238 if (!hardlink) { 247 if (!hardlink) {
239 ovl_inode_update(inode, newdentry); 248 /*
240 ovl_copyattr(newdentry->d_inode, inode); 249 * ovl_obtain_alias() can be called after ovl_create_real()
250 * and before we get here, so we may get an inode from cache
251 * with the same real upperdentry that is not the inode we
252 * pre-allocated. In this case we will use the cached inode
253 * to instantiate the new dentry.
254 *
255 * XXX: if we ever use ovl_obtain_alias() to decode directory
256 * file handles, need to use ovl_get_inode_locked() and
257 * d_instantiate_new() here to prevent from creating two
258 * hashed directory inode aliases.
259 */
260 inode = ovl_get_inode(dentry->d_sb, &oip);
261 if (WARN_ON(IS_ERR(inode)))
262 return PTR_ERR(inode);
241 } else { 263 } else {
242 WARN_ON(ovl_inode_real(inode) != d_inode(newdentry)); 264 WARN_ON(ovl_inode_real(inode) != d_inode(newdentry));
243 dput(newdentry); 265 dput(newdentry);
244 inc_nlink(inode); 266 inc_nlink(inode);
245 } 267 }
268
246 d_instantiate(dentry, inode); 269 d_instantiate(dentry, inode);
270 if (inode != oip.newinode) {
271 pr_warn_ratelimited("overlayfs: newly created inode found in cache (%pd2)\n",
272 dentry);
273 }
274
247 /* Force lookup of new upper hardlink to find its lower */ 275 /* Force lookup of new upper hardlink to find its lower */
248 if (hardlink) 276 if (hardlink)
249 d_drop(dentry); 277 d_drop(dentry);
278
279 return 0;
250} 280}
251 281
252static bool ovl_type_merge(struct dentry *dentry) 282static bool ovl_type_merge(struct dentry *dentry)
@@ -285,11 +315,17 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
285 ovl_set_opaque(dentry, newdentry); 315 ovl_set_opaque(dentry, newdentry);
286 } 316 }
287 317
288 ovl_instantiate(dentry, inode, newdentry, !!attr->hardlink); 318 err = ovl_instantiate(dentry, inode, newdentry, !!attr->hardlink);
289 err = 0; 319 if (err)
320 goto out_cleanup;
290out_unlock: 321out_unlock:
291 inode_unlock(udir); 322 inode_unlock(udir);
292 return err; 323 return err;
324
325out_cleanup:
326 ovl_cleanup(udir, newdentry);
327 dput(newdentry);
328 goto out_unlock;
293} 329}
294 330
295static struct dentry *ovl_clear_empty(struct dentry *dentry, 331static struct dentry *ovl_clear_empty(struct dentry *dentry,
@@ -474,8 +510,9 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode,
474 if (err) 510 if (err)
475 goto out_cleanup; 511 goto out_cleanup;
476 } 512 }
477 ovl_instantiate(dentry, inode, newdentry, hardlink); 513 err = ovl_instantiate(dentry, inode, newdentry, hardlink);
478 err = 0; 514 if (err)
515 goto out_cleanup;
479out_dput: 516out_dput:
480 dput(upper); 517 dput(upper);
481out_unlock: 518out_unlock:
@@ -558,6 +595,7 @@ static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev,
558 if (err) 595 if (err)
559 goto out; 596 goto out;
560 597
598 /* Preallocate inode to be used by ovl_get_inode() */
561 err = -ENOMEM; 599 err = -ENOMEM;
562 inode = ovl_new_inode(dentry->d_sb, mode, rdev); 600 inode = ovl_new_inode(dentry->d_sb, mode, rdev);
563 if (!inode) 601 if (!inode)
@@ -567,7 +605,8 @@ static int ovl_create_object(struct dentry *dentry, int mode, dev_t rdev,
567 attr.mode = inode->i_mode; 605 attr.mode = inode->i_mode;
568 606
569 err = ovl_create_or_link(dentry, inode, &attr, false); 607 err = ovl_create_or_link(dentry, inode, &attr, false);
570 if (err) 608 /* Did we end up using the preallocated inode? */
609 if (inode != d_inode(dentry))
571 iput(inode); 610 iput(inode);
572 611
573out_drop_write: 612out_drop_write:
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index 2b9e8370500c..1db5b3b458a1 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -749,6 +749,15 @@ static bool ovl_hash_bylower(struct super_block *sb, struct dentry *upper,
749 return true; 749 return true;
750} 750}
751 751
752static struct inode *ovl_iget5(struct super_block *sb, struct inode *newinode,
753 struct inode *key)
754{
755 return newinode ? inode_insert5(newinode, (unsigned long) key,
756 ovl_inode_test, ovl_inode_set, key) :
757 iget5_locked(sb, (unsigned long) key,
758 ovl_inode_test, ovl_inode_set, key);
759}
760
752struct inode *ovl_get_inode(struct super_block *sb, 761struct inode *ovl_get_inode(struct super_block *sb,
753 struct ovl_inode_params *oip) 762 struct ovl_inode_params *oip)
754{ 763{
@@ -776,8 +785,7 @@ struct inode *ovl_get_inode(struct super_block *sb,
776 upperdentry); 785 upperdentry);
777 unsigned int nlink = is_dir ? 1 : realinode->i_nlink; 786 unsigned int nlink = is_dir ? 1 : realinode->i_nlink;
778 787
779 inode = iget5_locked(sb, (unsigned long) key, ovl_inode_test, 788 inode = ovl_iget5(sb, oip->newinode, key);
780 ovl_inode_set, key);
781 if (!inode) 789 if (!inode)
782 goto out_nomem; 790 goto out_nomem;
783 if (!(inode->i_state & I_NEW)) { 791 if (!(inode->i_state & I_NEW)) {
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index b8a0160742b2..3c5e9f18b0d9 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -329,6 +329,7 @@ int ovl_update_time(struct inode *inode, struct timespec *ts, int flags);
329bool ovl_is_private_xattr(const char *name); 329bool ovl_is_private_xattr(const char *name);
330 330
331struct ovl_inode_params { 331struct ovl_inode_params {
332 struct inode *newinode;
332 struct dentry *upperdentry; 333 struct dentry *upperdentry;
333 struct ovl_path *lowerpath; 334 struct ovl_path *lowerpath;
334 struct dentry *index; 335 struct dentry *index;