aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/overlayfs/copy_up.c49
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
233static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, 233static 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);
308out2: 313out2:
309 dput(upper); 314 dput(temp);
310out1: 315out1:
311 dput(newdentry); 316 dput(upper);
312out: 317out:
313 return err; 318 return err;
314 319
315out_cleanup: 320out_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 }
376out_unlock: 377out_unlock:
377 unlock_rename(workdir, upperdir); 378 unlock_rename(workdir, upperdir);
378 do_delayed_call(&done); 379 do_delayed_call(&done);