Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs

Pull overlayfs updates from Miklos Szeredi:
"Because copy up can take a long time, serialized copy ups could be a
big performance bottleneck. This update allows concurrent copy up of
regular files eliminating this potential problem.

There are also minor fixes"

* 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
ovl: drop CAP_SYS_RESOURCE from saved mounter's credentials
ovl: properly implement sync_filesystem()
ovl: concurrent copy up of regular files
ovl: introduce copy up waitqueue
ovl: copy up regular file using O_TMPFILE
ovl: rearrange code in ovl_copy_up_locked()
ovl: check if upperdir fs supports O_TMPFILE

+148 -27
+66 -25
fs/overlayfs/copy_up.c
··· 21 21 #include <linux/fdtable.h> 22 22 #include <linux/ratelimit.h> 23 23 #include "overlayfs.h" 24 + #include "ovl_entry.h" 24 25 25 26 #define OVL_COPY_UP_CHUNK_SIZE (1 << 20) 26 27 ··· 234 233 235 234 static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, 236 235 struct dentry *dentry, struct path *lowerpath, 237 - struct kstat *stat, const char *link) 236 + struct kstat *stat, const char *link, 237 + struct kstat *pstat, bool tmpfile) 238 238 { 239 239 struct inode *wdir = workdir->d_inode; 240 240 struct inode *udir = upperdir->d_inode; 241 241 struct dentry *newdentry = NULL; 242 242 struct dentry *upper = NULL; 243 + struct dentry *temp = NULL; 243 244 int err; 244 245 const struct cred *old_creds = NULL; 245 246 struct cred *new_creds = NULL; ··· 252 249 .link = link 253 250 }; 254 251 255 - newdentry = ovl_lookup_temp(workdir, dentry); 256 - err = PTR_ERR(newdentry); 257 - if (IS_ERR(newdentry)) 258 - goto out; 259 - 260 252 upper = lookup_one_len(dentry->d_name.name, upperdir, 261 253 dentry->d_name.len); 262 254 err = PTR_ERR(upper); 263 255 if (IS_ERR(upper)) 264 - goto out1; 256 + goto out; 265 257 266 258 err = security_inode_copy_up(dentry, &new_creds); 267 259 if (err < 0) 268 - goto out2; 260 + goto out1; 269 261 270 262 if (new_creds) 271 263 old_creds = override_creds(new_creds); 272 264 273 - err = ovl_create_real(wdir, newdentry, &cattr, NULL, true); 265 + if (tmpfile) 266 + temp = ovl_do_tmpfile(upperdir, stat->mode); 267 + else 268 + temp = ovl_lookup_temp(workdir, dentry); 269 + err = PTR_ERR(temp); 270 + if (IS_ERR(temp)) 271 + goto out1; 272 + 273 + err = 0; 274 + if (!tmpfile) 275 + err = ovl_create_real(wdir, temp, &cattr, NULL, true); 274 276 275 277 if (new_creds) { 276 278 revert_creds(old_creds); ··· 290 282 291 283 ovl_path_upper(dentry, &upperpath); 292 284 BUG_ON(upperpath.dentry != NULL); 293 - upperpath.dentry = newdentry; 285 + upperpath.dentry = temp; 294 286 295 - err = ovl_copy_up_data(lowerpath, &upperpath, stat->size); 287 + if (tmpfile) { 288 + inode_unlock(udir); 289 + err = ovl_copy_up_data(lowerpath, &upperpath, 290 + stat->size); 291 + inode_lock_nested(udir, I_MUTEX_PARENT); 292 + } else { 293 + err = ovl_copy_up_data(lowerpath, &upperpath, 294 + stat->size); 295 + } 296 + 296 297 if (err) 297 298 goto out_cleanup; 298 299 } 299 300 300 - err = ovl_copy_xattr(lowerpath->dentry, newdentry); 301 + err = ovl_copy_xattr(lowerpath->dentry, temp); 301 302 if (err) 302 303 goto out_cleanup; 303 304 304 - inode_lock(newdentry->d_inode); 305 - err = ovl_set_attr(newdentry, stat); 306 - inode_unlock(newdentry->d_inode); 305 + inode_lock(temp->d_inode); 306 + err = ovl_set_attr(temp, stat); 307 + inode_unlock(temp->d_inode); 307 308 if (err) 308 309 goto out_cleanup; 309 310 310 - err = ovl_do_rename(wdir, newdentry, udir, upper, 0); 311 + if (tmpfile) 312 + err = ovl_do_link(temp, udir, upper, true); 313 + else 314 + err = ovl_do_rename(wdir, temp, udir, upper, 0); 311 315 if (err) 312 316 goto out_cleanup; 313 317 318 + newdentry = dget(tmpfile ? upper : temp); 314 319 ovl_dentry_update(dentry, newdentry); 315 320 ovl_inode_update(d_inode(dentry), d_inode(newdentry)); 316 - newdentry = NULL; 321 + 322 + /* Restore timestamps on parent (best effort) */ 323 + ovl_set_timestamps(upperdir, pstat); 317 324 out2: 318 - dput(upper); 325 + dput(temp); 319 326 out1: 320 - dput(newdentry); 327 + dput(upper); 321 328 out: 322 329 return err; 323 330 324 331 out_cleanup: 325 - ovl_cleanup(wdir, newdentry); 332 + if (!tmpfile) 333 + ovl_cleanup(wdir, temp); 326 334 goto out2; 327 335 } 328 336 ··· 362 338 struct dentry *lowerdentry = lowerpath->dentry; 363 339 struct dentry *upperdir; 364 340 const char *link = NULL; 341 + struct ovl_fs *ofs = dentry->d_sb->s_fs_info; 365 342 366 343 if (WARN_ON(!workdir)) 367 344 return -EROFS; ··· 383 358 return PTR_ERR(link); 384 359 } 385 360 361 + /* Should we copyup with O_TMPFILE or with workdir? */ 362 + if (S_ISREG(stat->mode) && ofs->tmpfile) { 363 + err = ovl_copy_up_start(dentry); 364 + /* err < 0: interrupted, err > 0: raced with another copy-up */ 365 + if (unlikely(err)) { 366 + pr_debug("ovl_copy_up_start(%pd2) = %i\n", dentry, err); 367 + if (err > 0) 368 + err = 0; 369 + goto out_done; 370 + } 371 + 372 + inode_lock_nested(upperdir->d_inode, I_MUTEX_PARENT); 373 + err = ovl_copy_up_locked(workdir, upperdir, dentry, lowerpath, 374 + stat, link, &pstat, true); 375 + inode_unlock(upperdir->d_inode); 376 + ovl_copy_up_end(dentry); 377 + goto out_done; 378 + } 379 + 386 380 err = -EIO; 387 381 if (lock_rename(workdir, upperdir) != NULL) { 388 382 pr_err("overlayfs: failed to lock workdir+upperdir\n"); ··· 414 370 } 415 371 416 372 err = ovl_copy_up_locked(workdir, upperdir, dentry, lowerpath, 417 - stat, link); 418 - if (!err) { 419 - /* Restore timestamps on parent (best effort) */ 420 - ovl_set_timestamps(upperdir, &pstat); 421 - } 373 + stat, link, &pstat, false); 422 374 out_unlock: 423 375 unlock_rename(workdir, upperdir); 376 + out_done: 424 377 do_delayed_call(&done); 425 378 426 379 return err;
+11
fs/overlayfs/overlayfs.h
··· 127 127 return err; 128 128 } 129 129 130 + static inline struct dentry *ovl_do_tmpfile(struct dentry *dentry, umode_t mode) 131 + { 132 + struct dentry *ret = vfs_tmpfile(dentry, mode, 0); 133 + int err = IS_ERR(ret) ? PTR_ERR(ret) : 0; 134 + 135 + pr_debug("tmpfile(%pd2, 0%o) = %i\n", dentry, mode, err); 136 + return ret; 137 + } 138 + 130 139 static inline struct inode *ovl_inode_real(struct inode *inode, bool *is_upper) 131 140 { 132 141 unsigned long x = (unsigned long) READ_ONCE(inode->i_private); ··· 178 169 u64 ovl_dentry_version_get(struct dentry *dentry); 179 170 bool ovl_is_whiteout(struct dentry *dentry); 180 171 struct file *ovl_path_open(struct path *path, int flags); 172 + int ovl_copy_up_start(struct dentry *dentry); 173 + void ovl_copy_up_end(struct dentry *dentry); 181 174 182 175 /* namei.c */ 183 176 int ovl_path_next(int idx, struct dentry *dentry, struct path *path);
+3
fs/overlayfs/ovl_entry.h
··· 27 27 struct ovl_config config; 28 28 /* creds of process who forced instantiation of super block */ 29 29 const struct cred *creator_cred; 30 + bool tmpfile; 31 + wait_queue_head_t copyup_wq; 30 32 }; 31 33 32 34 /* private information held for every overlayfs dentry */ ··· 40 38 u64 version; 41 39 const char *redirect; 42 40 bool opaque; 41 + bool copying; 43 42 }; 44 43 struct rcu_head rcu; 45 44 };
+37 -2
fs/overlayfs/super.c
··· 161 161 kfree(ufs); 162 162 } 163 163 164 + static int ovl_sync_fs(struct super_block *sb, int wait) 165 + { 166 + struct ovl_fs *ufs = sb->s_fs_info; 167 + struct super_block *upper_sb; 168 + int ret; 169 + 170 + if (!ufs->upper_mnt) 171 + return 0; 172 + upper_sb = ufs->upper_mnt->mnt_sb; 173 + if (!upper_sb->s_op->sync_fs) 174 + return 0; 175 + 176 + /* real inodes have already been synced by sync_filesystem(ovl_sb) */ 177 + down_read(&upper_sb->s_umount); 178 + ret = upper_sb->s_op->sync_fs(upper_sb, wait); 179 + up_read(&upper_sb->s_umount); 180 + return ret; 181 + } 182 + 164 183 /** 165 184 * ovl_statfs 166 185 * @sb: The overlayfs super block ··· 242 223 243 224 static const struct super_operations ovl_super_operations = { 244 225 .put_super = ovl_put_super, 226 + .sync_fs = ovl_sync_fs, 245 227 .statfs = ovl_statfs, 246 228 .show_options = ovl_show_options, 247 229 .remount_fs = ovl_remount, ··· 722 702 unsigned int stacklen = 0; 723 703 unsigned int i; 724 704 bool remote = false; 705 + struct cred *cred; 725 706 int err; 726 707 727 708 err = -ENOMEM; ··· 730 709 if (!ufs) 731 710 goto out; 732 711 712 + init_waitqueue_head(&ufs->copyup_wq); 733 713 ufs->config.redirect_dir = ovl_redirect_dir_def; 734 714 err = ovl_parse_opt((char *) data, &ufs->config); 735 715 if (err) ··· 848 826 * creation of workdir in previous step. 849 827 */ 850 828 if (ufs->workdir) { 829 + struct dentry *temp; 830 + 851 831 err = ovl_check_d_type_supported(&workpath); 852 832 if (err < 0) 853 833 goto out_put_workdir; ··· 861 837 */ 862 838 if (!err) 863 839 pr_warn("overlayfs: upper fs needs to support d_type.\n"); 840 + 841 + /* Check if upper/work fs supports O_TMPFILE */ 842 + temp = ovl_do_tmpfile(ufs->workdir, S_IFREG | 0); 843 + ufs->tmpfile = !IS_ERR(temp); 844 + if (ufs->tmpfile) 845 + dput(temp); 846 + else 847 + pr_warn("overlayfs: upper fs does not support tmpfile.\n"); 864 848 } 865 849 } 866 850 ··· 903 871 else 904 872 sb->s_d_op = &ovl_dentry_operations; 905 873 906 - ufs->creator_cred = prepare_creds(); 907 - if (!ufs->creator_cred) 874 + ufs->creator_cred = cred = prepare_creds(); 875 + if (!cred) 908 876 goto out_put_lower_mnt; 877 + 878 + /* Never override disk quota limits or use reserved space */ 879 + cap_lower(cred->cap_effective, CAP_SYS_RESOURCE); 909 880 910 881 err = -ENOMEM; 911 882 oe = ovl_alloc_entry(numlower);
+31
fs/overlayfs/util.c
··· 12 12 #include <linux/slab.h> 13 13 #include <linux/cred.h> 14 14 #include <linux/xattr.h> 15 + #include <linux/sched/signal.h> 15 16 #include "overlayfs.h" 16 17 #include "ovl_entry.h" 17 18 ··· 264 263 struct file *ovl_path_open(struct path *path, int flags) 265 264 { 266 265 return dentry_open(path, flags | O_NOATIME, current_cred()); 266 + } 267 + 268 + int ovl_copy_up_start(struct dentry *dentry) 269 + { 270 + struct ovl_fs *ofs = dentry->d_sb->s_fs_info; 271 + struct ovl_entry *oe = dentry->d_fsdata; 272 + int err; 273 + 274 + spin_lock(&ofs->copyup_wq.lock); 275 + err = wait_event_interruptible_locked(ofs->copyup_wq, !oe->copying); 276 + if (!err) { 277 + if (oe->__upperdentry) 278 + err = 1; /* Already copied up */ 279 + else 280 + oe->copying = true; 281 + } 282 + spin_unlock(&ofs->copyup_wq.lock); 283 + 284 + return err; 285 + } 286 + 287 + void ovl_copy_up_end(struct dentry *dentry) 288 + { 289 + struct ovl_fs *ofs = dentry->d_sb->s_fs_info; 290 + struct ovl_entry *oe = dentry->d_fsdata; 291 + 292 + spin_lock(&ofs->copyup_wq.lock); 293 + oe->copying = false; 294 + wake_up_locked(&ofs->copyup_wq); 295 + spin_unlock(&ofs->copyup_wq.lock); 267 296 }