diff options
| -rw-r--r-- | fs/overlayfs/copy_up.c | 49 |
1 files changed, 25 insertions, 24 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index f57043dace62..01e332725e94 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c | |||
| @@ -232,12 +232,14 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat) | |||
| 232 | 232 | ||
| 233 | static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, | 233 | static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, |
| 234 | struct dentry *dentry, struct path *lowerpath, | 234 | struct dentry *dentry, struct path *lowerpath, |
| 235 | struct kstat *stat, const char *link) | 235 | struct kstat *stat, const char *link, |
| 236 | struct kstat *pstat) | ||
| 236 | { | 237 | { |
| 237 | struct inode *wdir = workdir->d_inode; | 238 | struct inode *wdir = workdir->d_inode; |
| 238 | struct inode *udir = upperdir->d_inode; | 239 | struct inode *udir = upperdir->d_inode; |
| 239 | struct dentry *newdentry = NULL; | 240 | struct dentry *newdentry = NULL; |
| 240 | struct dentry *upper = NULL; | 241 | struct dentry *upper = NULL; |
| 242 | struct dentry *temp = NULL; | ||
| 241 | int err; | 243 | int err; |
| 242 | const struct cred *old_creds = NULL; | 244 | const struct cred *old_creds = NULL; |
| 243 | struct cred *new_creds = NULL; | 245 | struct cred *new_creds = NULL; |
| @@ -248,25 +250,25 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, | |||
| 248 | .link = link | 250 | .link = link |
| 249 | }; | 251 | }; |
| 250 | 252 | ||
| 251 | newdentry = ovl_lookup_temp(workdir, dentry); | ||
| 252 | err = PTR_ERR(newdentry); | ||
| 253 | if (IS_ERR(newdentry)) | ||
| 254 | goto out; | ||
| 255 | |||
| 256 | upper = lookup_one_len(dentry->d_name.name, upperdir, | 253 | upper = lookup_one_len(dentry->d_name.name, upperdir, |
| 257 | dentry->d_name.len); | 254 | dentry->d_name.len); |
| 258 | err = PTR_ERR(upper); | 255 | err = PTR_ERR(upper); |
| 259 | if (IS_ERR(upper)) | 256 | if (IS_ERR(upper)) |
| 260 | goto out1; | 257 | goto out; |
| 261 | 258 | ||
| 262 | err = security_inode_copy_up(dentry, &new_creds); | 259 | err = security_inode_copy_up(dentry, &new_creds); |
| 263 | if (err < 0) | 260 | if (err < 0) |
| 264 | goto out2; | 261 | goto out1; |
| 265 | 262 | ||
| 266 | if (new_creds) | 263 | if (new_creds) |
| 267 | old_creds = override_creds(new_creds); | 264 | old_creds = override_creds(new_creds); |
| 268 | 265 | ||
| 269 | err = ovl_create_real(wdir, newdentry, &cattr, NULL, true); | 266 | temp = ovl_lookup_temp(workdir, dentry); |
| 267 | err = PTR_ERR(temp); | ||
| 268 | if (IS_ERR(temp)) | ||
| 269 | goto out1; | ||
| 270 | |||
| 271 | err = ovl_create_real(wdir, temp, &cattr, NULL, true); | ||
| 270 | 272 | ||
| 271 | if (new_creds) { | 273 | if (new_creds) { |
| 272 | revert_creds(old_creds); | 274 | revert_creds(old_creds); |
| @@ -281,39 +283,42 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, | |||
| 281 | 283 | ||
| 282 | ovl_path_upper(dentry, &upperpath); | 284 | ovl_path_upper(dentry, &upperpath); |
| 283 | BUG_ON(upperpath.dentry != NULL); | 285 | BUG_ON(upperpath.dentry != NULL); |
| 284 | upperpath.dentry = newdentry; | 286 | upperpath.dentry = temp; |
| 285 | 287 | ||
| 286 | err = ovl_copy_up_data(lowerpath, &upperpath, stat->size); | 288 | err = ovl_copy_up_data(lowerpath, &upperpath, stat->size); |
| 287 | if (err) | 289 | if (err) |
| 288 | goto out_cleanup; | 290 | goto out_cleanup; |
| 289 | } | 291 | } |
| 290 | 292 | ||
| 291 | err = ovl_copy_xattr(lowerpath->dentry, newdentry); | 293 | err = ovl_copy_xattr(lowerpath->dentry, temp); |
| 292 | if (err) | 294 | if (err) |
| 293 | goto out_cleanup; | 295 | goto out_cleanup; |
| 294 | 296 | ||
| 295 | inode_lock(newdentry->d_inode); | 297 | inode_lock(temp->d_inode); |
| 296 | err = ovl_set_attr(newdentry, stat); | 298 | err = ovl_set_attr(temp, stat); |
| 297 | inode_unlock(newdentry->d_inode); | 299 | inode_unlock(temp->d_inode); |
| 298 | if (err) | 300 | if (err) |
| 299 | goto out_cleanup; | 301 | goto out_cleanup; |
| 300 | 302 | ||
| 301 | err = ovl_do_rename(wdir, newdentry, udir, upper, 0); | 303 | err = ovl_do_rename(wdir, temp, udir, upper, 0); |
| 302 | if (err) | 304 | if (err) |
| 303 | goto out_cleanup; | 305 | goto out_cleanup; |
| 304 | 306 | ||
| 307 | newdentry = dget(temp); | ||
| 305 | ovl_dentry_update(dentry, newdentry); | 308 | ovl_dentry_update(dentry, newdentry); |
| 306 | ovl_inode_update(d_inode(dentry), d_inode(newdentry)); | 309 | ovl_inode_update(d_inode(dentry), d_inode(newdentry)); |
| 307 | newdentry = NULL; | 310 | |
| 311 | /* Restore timestamps on parent (best effort) */ | ||
| 312 | ovl_set_timestamps(upperdir, pstat); | ||
| 308 | out2: | 313 | out2: |
| 309 | dput(upper); | 314 | dput(temp); |
| 310 | out1: | 315 | out1: |
| 311 | dput(newdentry); | 316 | dput(upper); |
| 312 | out: | 317 | out: |
| 313 | return err; | 318 | return err; |
| 314 | 319 | ||
| 315 | out_cleanup: | 320 | out_cleanup: |
| 316 | ovl_cleanup(wdir, newdentry); | 321 | ovl_cleanup(wdir, temp); |
| 317 | goto out2; | 322 | goto out2; |
| 318 | } | 323 | } |
| 319 | 324 | ||
| @@ -368,11 +373,7 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, | |||
| 368 | } | 373 | } |
| 369 | 374 | ||
| 370 | err = ovl_copy_up_locked(workdir, upperdir, dentry, lowerpath, | 375 | err = ovl_copy_up_locked(workdir, upperdir, dentry, lowerpath, |
| 371 | stat, link); | 376 | stat, link, &pstat); |
| 372 | if (!err) { | ||
| 373 | /* Restore timestamps on parent (best effort) */ | ||
| 374 | ovl_set_timestamps(upperdir, &pstat); | ||
| 375 | } | ||
| 376 | out_unlock: | 377 | out_unlock: |
| 377 | unlock_rename(workdir, upperdir); | 378 | unlock_rename(workdir, upperdir); |
| 378 | do_delayed_call(&done); | 379 | do_delayed_call(&done); |
