Skip to content

Commit 2b1a774

Browse files
author
Miklos Szeredi
committed
ovl: use vfs_tmpfile_open() helper
If tmpfile is used for copy up, then use this helper to create the tmpfile and open it at the same time. This will later allow filesystems such as fuse to do this operation atomically. Reviewed-by: Christian Brauner (Microsoft) <[email protected]> Signed-off-by: Miklos Szeredi <[email protected]>
1 parent 24a8175 commit 2b1a774

File tree

4 files changed

+72
-62
lines changed

4 files changed

+72
-62
lines changed

fs/overlayfs/copy_up.c

Lines changed: 57 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -193,11 +193,11 @@ static int ovl_copy_fileattr(struct inode *inode, struct path *old,
193193
return ovl_real_fileattr_set(new, &newfa);
194194
}
195195

196-
static int ovl_copy_up_data(struct ovl_fs *ofs, struct path *old,
197-
struct path *new, loff_t len)
196+
static int ovl_copy_up_file(struct ovl_fs *ofs, struct dentry *dentry,
197+
struct file *new_file, loff_t len)
198198
{
199+
struct path datapath;
199200
struct file *old_file;
200-
struct file *new_file;
201201
loff_t old_pos = 0;
202202
loff_t new_pos = 0;
203203
loff_t cloned;
@@ -206,23 +206,18 @@ static int ovl_copy_up_data(struct ovl_fs *ofs, struct path *old,
206206
bool skip_hole = false;
207207
int error = 0;
208208

209-
if (len == 0)
210-
return 0;
209+
ovl_path_lowerdata(dentry, &datapath);
210+
if (WARN_ON(datapath.dentry == NULL))
211+
return -EIO;
211212

212-
old_file = ovl_path_open(old, O_LARGEFILE | O_RDONLY);
213+
old_file = ovl_path_open(&datapath, O_LARGEFILE | O_RDONLY);
213214
if (IS_ERR(old_file))
214215
return PTR_ERR(old_file);
215216

216-
new_file = ovl_path_open(new, O_LARGEFILE | O_WRONLY);
217-
if (IS_ERR(new_file)) {
218-
error = PTR_ERR(new_file);
219-
goto out_fput;
220-
}
221-
222217
/* Try to use clone_file_range to clone up within the same fs */
223218
cloned = do_clone_file_range(old_file, 0, new_file, 0, len, 0);
224219
if (cloned == len)
225-
goto out;
220+
goto out_fput;
226221
/* Couldn't clone, so now we try to copy the data */
227222

228223
/* Check if lower fs supports seek operation */
@@ -282,10 +277,8 @@ static int ovl_copy_up_data(struct ovl_fs *ofs, struct path *old,
282277

283278
len -= bytes;
284279
}
285-
out:
286280
if (!error && ovl_should_sync(ofs))
287281
error = vfs_fsync(new_file, 0);
288-
fput(new_file);
289282
out_fput:
290283
fput(old_file);
291284
return error;
@@ -556,30 +549,31 @@ static int ovl_link_up(struct ovl_copy_up_ctx *c)
556549
return err;
557550
}
558551

559-
static int ovl_copy_up_inode(struct ovl_copy_up_ctx *c, struct dentry *temp)
552+
static int ovl_copy_up_data(struct ovl_copy_up_ctx *c, const struct path *temp)
560553
{
561554
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
562-
struct inode *inode = d_inode(c->dentry);
563-
struct path upperpath, datapath;
555+
struct file *new_file;
564556
int err;
565557

566-
ovl_path_upper(c->dentry, &upperpath);
567-
if (WARN_ON(upperpath.dentry != NULL))
568-
return -EIO;
558+
if (!S_ISREG(c->stat.mode) || c->metacopy || !c->stat.size)
559+
return 0;
569560

570-
upperpath.dentry = temp;
561+
new_file = ovl_path_open(temp, O_LARGEFILE | O_WRONLY);
562+
if (IS_ERR(new_file))
563+
return PTR_ERR(new_file);
571564

572-
/*
573-
* Copy up data first and then xattrs. Writing data after
574-
* xattrs will remove security.capability xattr automatically.
575-
*/
576-
if (S_ISREG(c->stat.mode) && !c->metacopy) {
577-
ovl_path_lowerdata(c->dentry, &datapath);
578-
err = ovl_copy_up_data(ofs, &datapath, &upperpath,
579-
c->stat.size);
580-
if (err)
581-
return err;
582-
}
565+
err = ovl_copy_up_file(ofs, c->dentry, new_file, c->stat.size);
566+
fput(new_file);
567+
568+
return err;
569+
}
570+
571+
static int ovl_copy_up_metadata(struct ovl_copy_up_ctx *c, struct dentry *temp)
572+
{
573+
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
574+
struct inode *inode = d_inode(c->dentry);
575+
struct path upperpath = { .mnt = ovl_upper_mnt(ofs), .dentry = temp };
576+
int err;
583577

584578
err = ovl_copy_xattr(c->dentry->d_sb, &c->lowerpath, temp);
585579
if (err)
@@ -662,6 +656,7 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
662656
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
663657
struct inode *inode;
664658
struct inode *udir = d_inode(c->destdir), *wdir = d_inode(c->workdir);
659+
struct path path = { .mnt = ovl_upper_mnt(ofs) };
665660
struct dentry *temp, *upper;
666661
struct ovl_cu_creds cc;
667662
int err;
@@ -688,7 +683,16 @@ static int ovl_copy_up_workdir(struct ovl_copy_up_ctx *c)
688683
if (IS_ERR(temp))
689684
goto unlock;
690685

691-
err = ovl_copy_up_inode(c, temp);
686+
/*
687+
* Copy up data first and then xattrs. Writing data after
688+
* xattrs will remove security.capability xattr automatically.
689+
*/
690+
path.dentry = temp;
691+
err = ovl_copy_up_data(c, &path);
692+
if (err)
693+
goto cleanup;
694+
695+
err = ovl_copy_up_metadata(c, temp);
692696
if (err)
693697
goto cleanup;
694698

@@ -732,22 +736,30 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
732736
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
733737
struct inode *udir = d_inode(c->destdir);
734738
struct dentry *temp, *upper;
739+
struct file *tmpfile;
735740
struct ovl_cu_creds cc;
736741
int err;
737742

738743
err = ovl_prep_cu_creds(c->dentry, &cc);
739744
if (err)
740745
return err;
741746

742-
temp = ovl_do_tmpfile(ofs, c->workdir, c->stat.mode);
747+
tmpfile = ovl_do_tmpfile(ofs, c->workdir, c->stat.mode);
743748
ovl_revert_cu_creds(&cc);
744749

745-
if (IS_ERR(temp))
746-
return PTR_ERR(temp);
750+
if (IS_ERR(tmpfile))
751+
return PTR_ERR(tmpfile);
747752

748-
err = ovl_copy_up_inode(c, temp);
753+
temp = tmpfile->f_path.dentry;
754+
if (!c->metacopy && c->stat.size) {
755+
err = ovl_copy_up_file(ofs, c->dentry, tmpfile, c->stat.size);
756+
if (err)
757+
return err;
758+
}
759+
760+
err = ovl_copy_up_metadata(c, temp);
749761
if (err)
750-
goto out_dput;
762+
goto out_fput;
751763

752764
inode_lock_nested(udir, I_MUTEX_PARENT);
753765

@@ -761,16 +773,14 @@ static int ovl_copy_up_tmpfile(struct ovl_copy_up_ctx *c)
761773
inode_unlock(udir);
762774

763775
if (err)
764-
goto out_dput;
776+
goto out_fput;
765777

766778
if (!c->metacopy)
767779
ovl_set_upperdata(d_inode(c->dentry));
768-
ovl_inode_update(d_inode(c->dentry), temp);
780+
ovl_inode_update(d_inode(c->dentry), dget(temp));
769781

770-
return 0;
771-
772-
out_dput:
773-
dput(temp);
782+
out_fput:
783+
fput(tmpfile);
774784
return err;
775785
}
776786

@@ -899,7 +909,7 @@ static ssize_t ovl_getxattr_value(struct path *path, char *name, char **value)
899909
static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
900910
{
901911
struct ovl_fs *ofs = OVL_FS(c->dentry->d_sb);
902-
struct path upperpath, datapath;
912+
struct path upperpath;
903913
int err;
904914
char *capability = NULL;
905915
ssize_t cap_size;
@@ -908,18 +918,14 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
908918
if (WARN_ON(upperpath.dentry == NULL))
909919
return -EIO;
910920

911-
ovl_path_lowerdata(c->dentry, &datapath);
912-
if (WARN_ON(datapath.dentry == NULL))
913-
return -EIO;
914-
915921
if (c->stat.size) {
916922
err = cap_size = ovl_getxattr_value(&upperpath, XATTR_NAME_CAPS,
917923
&capability);
918924
if (cap_size < 0)
919925
goto out;
920926
}
921927

922-
err = ovl_copy_up_data(ofs, &datapath, &upperpath, c->stat.size);
928+
err = ovl_copy_up_data(c, &upperpath);
923929
if (err)
924930
goto out_free;
925931

fs/overlayfs/overlayfs.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -310,14 +310,16 @@ static inline int ovl_do_whiteout(struct ovl_fs *ofs,
310310
return err;
311311
}
312312

313-
static inline struct dentry *ovl_do_tmpfile(struct ovl_fs *ofs,
314-
struct dentry *dentry, umode_t mode)
313+
static inline struct file *ovl_do_tmpfile(struct ovl_fs *ofs,
314+
struct dentry *dentry, umode_t mode)
315315
{
316-
struct dentry *ret = vfs_tmpfile(ovl_upper_mnt_userns(ofs), dentry, mode, 0);
317-
int err = PTR_ERR_OR_ZERO(ret);
316+
struct path path = { .mnt = ovl_upper_mnt(ofs), .dentry = dentry };
317+
struct file *file = vfs_tmpfile_open(ovl_upper_mnt_userns(ofs), &path, mode,
318+
O_LARGEFILE | O_WRONLY, current_cred());
319+
int err = PTR_ERR_OR_ZERO(file);
318320

319321
pr_debug("tmpfile(%pd2, 0%o) = %i\n", dentry, mode, err);
320-
return ret;
322+
return file;
321323
}
322324

323325
static inline struct dentry *ovl_lookup_upper(struct ovl_fs *ofs,
@@ -401,7 +403,7 @@ void ovl_inode_update(struct inode *inode, struct dentry *upperdentry);
401403
void ovl_dir_modified(struct dentry *dentry, bool impurity);
402404
u64 ovl_dentry_version_get(struct dentry *dentry);
403405
bool ovl_is_whiteout(struct dentry *dentry);
404-
struct file *ovl_path_open(struct path *path, int flags);
406+
struct file *ovl_path_open(const struct path *path, int flags);
405407
int ovl_copy_up_start(struct dentry *dentry, int flags);
406408
void ovl_copy_up_end(struct dentry *dentry);
407409
bool ovl_already_copied_up(struct dentry *dentry, int flags);

fs/overlayfs/super.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include <linux/seq_file.h>
1616
#include <linux/posix_acl_xattr.h>
1717
#include <linux/exportfs.h>
18+
#include <linux/file.h>
1819
#include "overlayfs.h"
1920

2021
MODULE_AUTHOR("Miklos Szeredi <[email protected]>");
@@ -1356,7 +1357,8 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
13561357
struct path *workpath)
13571358
{
13581359
struct vfsmount *mnt = ovl_upper_mnt(ofs);
1359-
struct dentry *temp, *workdir;
1360+
struct dentry *workdir;
1361+
struct file *tmpfile;
13601362
bool rename_whiteout;
13611363
bool d_type;
13621364
int fh_type;
@@ -1392,10 +1394,10 @@ static int ovl_make_workdir(struct super_block *sb, struct ovl_fs *ofs,
13921394
pr_warn("upper fs needs to support d_type.\n");
13931395

13941396
/* Check if upper/work fs supports O_TMPFILE */
1395-
temp = ovl_do_tmpfile(ofs, ofs->workdir, S_IFREG | 0);
1396-
ofs->tmpfile = !IS_ERR(temp);
1397+
tmpfile = ovl_do_tmpfile(ofs, ofs->workdir, S_IFREG | 0);
1398+
ofs->tmpfile = !IS_ERR(tmpfile);
13971399
if (ofs->tmpfile)
1398-
dput(temp);
1400+
fput(tmpfile);
13991401
else
14001402
pr_warn("upper fs does not support tmpfile.\n");
14011403

fs/overlayfs/util.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -490,7 +490,7 @@ bool ovl_is_whiteout(struct dentry *dentry)
490490
return inode && IS_WHITEOUT(inode);
491491
}
492492

493-
struct file *ovl_path_open(struct path *path, int flags)
493+
struct file *ovl_path_open(const struct path *path, int flags)
494494
{
495495
struct inode *inode = d_inode(path->dentry);
496496
struct user_namespace *real_mnt_userns = mnt_user_ns(path->mnt);

0 commit comments

Comments
 (0)