diff options
-rw-r--r-- | fs/overlayfs/dir.c | 59 | ||||
-rw-r--r-- | fs/overlayfs/inode.c | 12 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 1 |
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 | /* |
233 | static 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 | */ | ||
237 | static 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 | ||
252 | static bool ovl_type_merge(struct dentry *dentry) | 282 | static 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; | ||
290 | out_unlock: | 321 | out_unlock: |
291 | inode_unlock(udir); | 322 | inode_unlock(udir); |
292 | return err; | 323 | return err; |
324 | |||
325 | out_cleanup: | ||
326 | ovl_cleanup(udir, newdentry); | ||
327 | dput(newdentry); | ||
328 | goto out_unlock; | ||
293 | } | 329 | } |
294 | 330 | ||
295 | static struct dentry *ovl_clear_empty(struct dentry *dentry, | 331 | static 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; | ||
479 | out_dput: | 516 | out_dput: |
480 | dput(upper); | 517 | dput(upper); |
481 | out_unlock: | 518 | out_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 | ||
573 | out_drop_write: | 612 | out_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 | ||
752 | static 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 | |||
752 | struct inode *ovl_get_inode(struct super_block *sb, | 761 | struct 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); | |||
329 | bool ovl_is_private_xattr(const char *name); | 329 | bool ovl_is_private_xattr(const char *name); |
330 | 330 | ||
331 | struct ovl_inode_params { | 331 | struct 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; |