aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/overlayfs/copy_up.c27
1 files changed, 20 insertions, 7 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 01e332725e94..6e39e90b5605 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -20,6 +20,7 @@
20#include <linux/fdtable.h> 20#include <linux/fdtable.h>
21#include <linux/ratelimit.h> 21#include <linux/ratelimit.h>
22#include "overlayfs.h" 22#include "overlayfs.h"
23#include "ovl_entry.h"
23 24
24#define OVL_COPY_UP_CHUNK_SIZE (1 << 20) 25#define OVL_COPY_UP_CHUNK_SIZE (1 << 20)
25 26
@@ -233,7 +234,7 @@ int ovl_set_attr(struct dentry *upperdentry, struct kstat *stat)
233static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, 234static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
234 struct dentry *dentry, struct path *lowerpath, 235 struct dentry *dentry, struct path *lowerpath,
235 struct kstat *stat, const char *link, 236 struct kstat *stat, const char *link,
236 struct kstat *pstat) 237 struct kstat *pstat, bool tmpfile)
237{ 238{
238 struct inode *wdir = workdir->d_inode; 239 struct inode *wdir = workdir->d_inode;
239 struct inode *udir = upperdir->d_inode; 240 struct inode *udir = upperdir->d_inode;
@@ -263,12 +264,17 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
263 if (new_creds) 264 if (new_creds)
264 old_creds = override_creds(new_creds); 265 old_creds = override_creds(new_creds);
265 266
266 temp = ovl_lookup_temp(workdir, dentry); 267 if (tmpfile)
268 temp = ovl_do_tmpfile(upperdir, stat->mode);
269 else
270 temp = ovl_lookup_temp(workdir, dentry);
267 err = PTR_ERR(temp); 271 err = PTR_ERR(temp);
268 if (IS_ERR(temp)) 272 if (IS_ERR(temp))
269 goto out1; 273 goto out1;
270 274
271 err = ovl_create_real(wdir, temp, &cattr, NULL, true); 275 err = 0;
276 if (!tmpfile)
277 err = ovl_create_real(wdir, temp, &cattr, NULL, true);
272 278
273 if (new_creds) { 279 if (new_creds) {
274 revert_creds(old_creds); 280 revert_creds(old_creds);
@@ -300,11 +306,14 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
300 if (err) 306 if (err)
301 goto out_cleanup; 307 goto out_cleanup;
302 308
303 err = ovl_do_rename(wdir, temp, udir, upper, 0); 309 if (tmpfile)
310 err = ovl_do_link(temp, udir, upper, true);
311 else
312 err = ovl_do_rename(wdir, temp, udir, upper, 0);
304 if (err) 313 if (err)
305 goto out_cleanup; 314 goto out_cleanup;
306 315
307 newdentry = dget(temp); 316 newdentry = dget(tmpfile ? upper : temp);
308 ovl_dentry_update(dentry, newdentry); 317 ovl_dentry_update(dentry, newdentry);
309 ovl_inode_update(d_inode(dentry), d_inode(newdentry)); 318 ovl_inode_update(d_inode(dentry), d_inode(newdentry));
310 319
@@ -318,7 +327,8 @@ out:
318 return err; 327 return err;
319 328
320out_cleanup: 329out_cleanup:
321 ovl_cleanup(wdir, temp); 330 if (!tmpfile)
331 ovl_cleanup(wdir, temp);
322 goto out2; 332 goto out2;
323} 333}
324 334
@@ -342,6 +352,9 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
342 struct dentry *lowerdentry = lowerpath->dentry; 352 struct dentry *lowerdentry = lowerpath->dentry;
343 struct dentry *upperdir; 353 struct dentry *upperdir;
344 const char *link = NULL; 354 const char *link = NULL;
355 struct ovl_fs *ofs = dentry->d_sb->s_fs_info;
356 /* Should we copyup with O_TMPFILE or with workdir? */
357 bool tmpfile = S_ISREG(stat->mode) && ofs->tmpfile;
345 358
346 if (WARN_ON(!workdir)) 359 if (WARN_ON(!workdir))
347 return -EROFS; 360 return -EROFS;
@@ -373,7 +386,7 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
373 } 386 }
374 387
375 err = ovl_copy_up_locked(workdir, upperdir, dentry, lowerpath, 388 err = ovl_copy_up_locked(workdir, upperdir, dentry, lowerpath,
376 stat, link, &pstat); 389 stat, link, &pstat, tmpfile);
377out_unlock: 390out_unlock:
378 unlock_rename(workdir, upperdir); 391 unlock_rename(workdir, upperdir);
379 do_delayed_call(&done); 392 do_delayed_call(&done);