diff options
| -rw-r--r-- | Documentation/filesystems/overlayfs.txt | 2 | ||||
| -rw-r--r-- | MAINTAINERS | 7 | ||||
| -rw-r--r-- | fs/Makefile | 2 | ||||
| -rw-r--r-- | fs/dcache.c | 1 | ||||
| -rw-r--r-- | fs/isofs/inode.c | 42 | ||||
| -rw-r--r-- | fs/overlayfs/Kconfig | 2 | ||||
| -rw-r--r-- | fs/overlayfs/Makefile | 4 | ||||
| -rw-r--r-- | fs/overlayfs/dir.c | 31 | ||||
| -rw-r--r-- | fs/overlayfs/inode.c | 27 | ||||
| -rw-r--r-- | fs/overlayfs/readdir.c | 39 | ||||
| -rw-r--r-- | fs/overlayfs/super.c | 61 |
11 files changed, 133 insertions, 85 deletions
diff --git a/Documentation/filesystems/overlayfs.txt b/Documentation/filesystems/overlayfs.txt index 530850a72735..a27c950ece61 100644 --- a/Documentation/filesystems/overlayfs.txt +++ b/Documentation/filesystems/overlayfs.txt | |||
| @@ -64,7 +64,7 @@ is formed. | |||
| 64 | At mount time, the two directories given as mount options "lowerdir" and | 64 | At mount time, the two directories given as mount options "lowerdir" and |
| 65 | "upperdir" are combined into a merged directory: | 65 | "upperdir" are combined into a merged directory: |
| 66 | 66 | ||
| 67 | mount -t overlayfs overlayfs -olowerdir=/lower,upperdir=/upper,\ | 67 | mount -t overlay overlay -olowerdir=/lower,upperdir=/upper,\ |
| 68 | workdir=/work /merged | 68 | workdir=/work /merged |
| 69 | 69 | ||
| 70 | The "workdir" needs to be an empty directory on the same filesystem | 70 | The "workdir" needs to be an empty directory on the same filesystem |
diff --git a/MAINTAINERS b/MAINTAINERS index c444907ccd69..0ff630de8a6d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
| @@ -6888,11 +6888,12 @@ F: drivers/scsi/osd/ | |||
| 6888 | F: include/scsi/osd_* | 6888 | F: include/scsi/osd_* |
| 6889 | F: fs/exofs/ | 6889 | F: fs/exofs/ |
| 6890 | 6890 | ||
| 6891 | OVERLAYFS FILESYSTEM | 6891 | OVERLAY FILESYSTEM |
| 6892 | M: Miklos Szeredi <miklos@szeredi.hu> | 6892 | M: Miklos Szeredi <miklos@szeredi.hu> |
| 6893 | L: linux-fsdevel@vger.kernel.org | 6893 | L: linux-unionfs@vger.kernel.org |
| 6894 | T: git git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs.git | ||
| 6894 | S: Supported | 6895 | S: Supported |
| 6895 | F: fs/overlayfs/* | 6896 | F: fs/overlayfs/ |
| 6896 | F: Documentation/filesystems/overlayfs.txt | 6897 | F: Documentation/filesystems/overlayfs.txt |
| 6897 | 6898 | ||
| 6898 | P54 WIRELESS DRIVER | 6899 | P54 WIRELESS DRIVER |
diff --git a/fs/Makefile b/fs/Makefile index 34a1b9dea6dd..da0bbb456d3f 100644 --- a/fs/Makefile +++ b/fs/Makefile | |||
| @@ -104,7 +104,7 @@ obj-$(CONFIG_QNX6FS_FS) += qnx6/ | |||
| 104 | obj-$(CONFIG_AUTOFS4_FS) += autofs4/ | 104 | obj-$(CONFIG_AUTOFS4_FS) += autofs4/ |
| 105 | obj-$(CONFIG_ADFS_FS) += adfs/ | 105 | obj-$(CONFIG_ADFS_FS) += adfs/ |
| 106 | obj-$(CONFIG_FUSE_FS) += fuse/ | 106 | obj-$(CONFIG_FUSE_FS) += fuse/ |
| 107 | obj-$(CONFIG_OVERLAYFS_FS) += overlayfs/ | 107 | obj-$(CONFIG_OVERLAY_FS) += overlayfs/ |
| 108 | obj-$(CONFIG_UDF_FS) += udf/ | 108 | obj-$(CONFIG_UDF_FS) += udf/ |
| 109 | obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ | 109 | obj-$(CONFIG_SUN_OPENPROMFS) += openpromfs/ |
| 110 | obj-$(CONFIG_OMFS_FS) += omfs/ | 110 | obj-$(CONFIG_OMFS_FS) += omfs/ |
diff --git a/fs/dcache.c b/fs/dcache.c index 3ffef7f4e5cd..5bc72b07fde2 100644 --- a/fs/dcache.c +++ b/fs/dcache.c | |||
| @@ -778,6 +778,7 @@ restart: | |||
| 778 | struct dentry *parent = lock_parent(dentry); | 778 | struct dentry *parent = lock_parent(dentry); |
| 779 | if (likely(!dentry->d_lockref.count)) { | 779 | if (likely(!dentry->d_lockref.count)) { |
| 780 | __dentry_kill(dentry); | 780 | __dentry_kill(dentry); |
| 781 | dput(parent); | ||
| 781 | goto restart; | 782 | goto restart; |
| 782 | } | 783 | } |
| 783 | if (parent) | 784 | if (parent) |
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index fe839b915116..d67a16f2a45d 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c | |||
| @@ -174,27 +174,6 @@ struct iso9660_options{ | |||
| 174 | * Compute the hash for the isofs name corresponding to the dentry. | 174 | * Compute the hash for the isofs name corresponding to the dentry. |
| 175 | */ | 175 | */ |
| 176 | static int | 176 | static int |
| 177 | isofs_hash_common(struct qstr *qstr, int ms) | ||
| 178 | { | ||
| 179 | const char *name; | ||
| 180 | int len; | ||
| 181 | |||
| 182 | len = qstr->len; | ||
| 183 | name = qstr->name; | ||
| 184 | if (ms) { | ||
| 185 | while (len && name[len-1] == '.') | ||
| 186 | len--; | ||
| 187 | } | ||
| 188 | |||
| 189 | qstr->hash = full_name_hash(name, len); | ||
| 190 | |||
| 191 | return 0; | ||
| 192 | } | ||
| 193 | |||
| 194 | /* | ||
| 195 | * Compute the hash for the isofs name corresponding to the dentry. | ||
| 196 | */ | ||
| 197 | static int | ||
| 198 | isofs_hashi_common(struct qstr *qstr, int ms) | 177 | isofs_hashi_common(struct qstr *qstr, int ms) |
| 199 | { | 178 | { |
| 200 | const char *name; | 179 | const char *name; |
| @@ -263,6 +242,27 @@ isofs_dentry_cmpi(const struct dentry *parent, const struct dentry *dentry, | |||
| 263 | } | 242 | } |
| 264 | 243 | ||
| 265 | #ifdef CONFIG_JOLIET | 244 | #ifdef CONFIG_JOLIET |
| 245 | /* | ||
| 246 | * Compute the hash for the isofs name corresponding to the dentry. | ||
| 247 | */ | ||
| 248 | static int | ||
| 249 | isofs_hash_common(struct qstr *qstr, int ms) | ||
| 250 | { | ||
| 251 | const char *name; | ||
| 252 | int len; | ||
| 253 | |||
| 254 | len = qstr->len; | ||
| 255 | name = qstr->name; | ||
| 256 | if (ms) { | ||
| 257 | while (len && name[len-1] == '.') | ||
| 258 | len--; | ||
| 259 | } | ||
| 260 | |||
| 261 | qstr->hash = full_name_hash(name, len); | ||
| 262 | |||
| 263 | return 0; | ||
| 264 | } | ||
| 265 | |||
| 266 | static int | 266 | static int |
| 267 | isofs_hash_ms(const struct dentry *dentry, struct qstr *qstr) | 267 | isofs_hash_ms(const struct dentry *dentry, struct qstr *qstr) |
| 268 | { | 268 | { |
diff --git a/fs/overlayfs/Kconfig b/fs/overlayfs/Kconfig index e60125976873..34355818a2e0 100644 --- a/fs/overlayfs/Kconfig +++ b/fs/overlayfs/Kconfig | |||
| @@ -1,4 +1,4 @@ | |||
| 1 | config OVERLAYFS_FS | 1 | config OVERLAY_FS |
| 2 | tristate "Overlay filesystem support" | 2 | tristate "Overlay filesystem support" |
| 3 | help | 3 | help |
| 4 | An overlay filesystem combines two filesystems - an 'upper' filesystem | 4 | An overlay filesystem combines two filesystems - an 'upper' filesystem |
diff --git a/fs/overlayfs/Makefile b/fs/overlayfs/Makefile index 8f91889480d0..900daed3e91d 100644 --- a/fs/overlayfs/Makefile +++ b/fs/overlayfs/Makefile | |||
| @@ -2,6 +2,6 @@ | |||
| 2 | # Makefile for the overlay filesystem. | 2 | # Makefile for the overlay filesystem. |
| 3 | # | 3 | # |
| 4 | 4 | ||
| 5 | obj-$(CONFIG_OVERLAYFS_FS) += overlayfs.o | 5 | obj-$(CONFIG_OVERLAY_FS) += overlay.o |
| 6 | 6 | ||
| 7 | overlayfs-objs := super.o inode.o dir.o readdir.o copy_up.o | 7 | overlay-objs := super.o inode.o dir.o readdir.o copy_up.o |
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 15cd91ad9940..8ffc4b980f1b 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c | |||
| @@ -284,8 +284,7 @@ out: | |||
| 284 | return ERR_PTR(err); | 284 | return ERR_PTR(err); |
| 285 | } | 285 | } |
| 286 | 286 | ||
| 287 | static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry, | 287 | static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry) |
| 288 | enum ovl_path_type type) | ||
| 289 | { | 288 | { |
| 290 | int err; | 289 | int err; |
| 291 | struct dentry *ret = NULL; | 290 | struct dentry *ret = NULL; |
| @@ -294,8 +293,17 @@ static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry, | |||
| 294 | err = ovl_check_empty_dir(dentry, &list); | 293 | err = ovl_check_empty_dir(dentry, &list); |
| 295 | if (err) | 294 | if (err) |
| 296 | ret = ERR_PTR(err); | 295 | ret = ERR_PTR(err); |
| 297 | else if (type == OVL_PATH_MERGE) | 296 | else { |
| 298 | ret = ovl_clear_empty(dentry, &list); | 297 | /* |
| 298 | * If no upperdentry then skip clearing whiteouts. | ||
| 299 | * | ||
| 300 | * Can race with copy-up, since we don't hold the upperdir | ||
| 301 | * mutex. Doesn't matter, since copy-up can't create a | ||
| 302 | * non-empty directory from an empty one. | ||
| 303 | */ | ||
| 304 | if (ovl_dentry_upper(dentry)) | ||
| 305 | ret = ovl_clear_empty(dentry, &list); | ||
| 306 | } | ||
| 299 | 307 | ||
| 300 | ovl_cache_free(&list); | 308 | ovl_cache_free(&list); |
| 301 | 309 | ||
| @@ -487,8 +495,7 @@ out: | |||
| 487 | return err; | 495 | return err; |
| 488 | } | 496 | } |
| 489 | 497 | ||
| 490 | static int ovl_remove_and_whiteout(struct dentry *dentry, | 498 | static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir) |
| 491 | enum ovl_path_type type, bool is_dir) | ||
| 492 | { | 499 | { |
| 493 | struct dentry *workdir = ovl_workdir(dentry); | 500 | struct dentry *workdir = ovl_workdir(dentry); |
| 494 | struct inode *wdir = workdir->d_inode; | 501 | struct inode *wdir = workdir->d_inode; |
| @@ -500,7 +507,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, | |||
| 500 | int err; | 507 | int err; |
| 501 | 508 | ||
| 502 | if (is_dir) { | 509 | if (is_dir) { |
| 503 | opaquedir = ovl_check_empty_and_clear(dentry, type); | 510 | opaquedir = ovl_check_empty_and_clear(dentry); |
| 504 | err = PTR_ERR(opaquedir); | 511 | err = PTR_ERR(opaquedir); |
| 505 | if (IS_ERR(opaquedir)) | 512 | if (IS_ERR(opaquedir)) |
| 506 | goto out; | 513 | goto out; |
| @@ -515,9 +522,10 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, | |||
| 515 | if (IS_ERR(whiteout)) | 522 | if (IS_ERR(whiteout)) |
| 516 | goto out_unlock; | 523 | goto out_unlock; |
| 517 | 524 | ||
| 518 | if (type == OVL_PATH_LOWER) { | 525 | upper = ovl_dentry_upper(dentry); |
| 526 | if (!upper) { | ||
| 519 | upper = lookup_one_len(dentry->d_name.name, upperdir, | 527 | upper = lookup_one_len(dentry->d_name.name, upperdir, |
| 520 | dentry->d_name.len); | 528 | dentry->d_name.len); |
| 521 | err = PTR_ERR(upper); | 529 | err = PTR_ERR(upper); |
| 522 | if (IS_ERR(upper)) | 530 | if (IS_ERR(upper)) |
| 523 | goto kill_whiteout; | 531 | goto kill_whiteout; |
| @@ -529,7 +537,6 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, | |||
| 529 | } else { | 537 | } else { |
| 530 | int flags = 0; | 538 | int flags = 0; |
| 531 | 539 | ||
| 532 | upper = ovl_dentry_upper(dentry); | ||
| 533 | if (opaquedir) | 540 | if (opaquedir) |
| 534 | upper = opaquedir; | 541 | upper = opaquedir; |
| 535 | err = -ESTALE; | 542 | err = -ESTALE; |
| @@ -648,7 +655,7 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir) | |||
| 648 | cap_raise(override_cred->cap_effective, CAP_CHOWN); | 655 | cap_raise(override_cred->cap_effective, CAP_CHOWN); |
| 649 | old_cred = override_creds(override_cred); | 656 | old_cred = override_creds(override_cred); |
| 650 | 657 | ||
| 651 | err = ovl_remove_and_whiteout(dentry, type, is_dir); | 658 | err = ovl_remove_and_whiteout(dentry, is_dir); |
| 652 | 659 | ||
| 653 | revert_creds(old_cred); | 660 | revert_creds(old_cred); |
| 654 | put_cred(override_cred); | 661 | put_cred(override_cred); |
| @@ -781,7 +788,7 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old, | |||
| 781 | } | 788 | } |
| 782 | 789 | ||
| 783 | if (overwrite && (new_type == OVL_PATH_LOWER || new_type == OVL_PATH_MERGE) && new_is_dir) { | 790 | if (overwrite && (new_type == OVL_PATH_LOWER || new_type == OVL_PATH_MERGE) && new_is_dir) { |
| 784 | opaquedir = ovl_check_empty_and_clear(new, new_type); | 791 | opaquedir = ovl_check_empty_and_clear(new); |
| 785 | err = PTR_ERR(opaquedir); | 792 | err = PTR_ERR(opaquedir); |
| 786 | if (IS_ERR(opaquedir)) { | 793 | if (IS_ERR(opaquedir)) { |
| 787 | opaquedir = NULL; | 794 | opaquedir = NULL; |
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c index af2d18c9fcee..07d74b24913b 100644 --- a/fs/overlayfs/inode.c +++ b/fs/overlayfs/inode.c | |||
| @@ -235,26 +235,36 @@ out: | |||
| 235 | return err; | 235 | return err; |
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | static bool ovl_need_xattr_filter(struct dentry *dentry, | ||
| 239 | enum ovl_path_type type) | ||
| 240 | { | ||
| 241 | return type == OVL_PATH_UPPER && S_ISDIR(dentry->d_inode->i_mode); | ||
| 242 | } | ||
| 243 | |||
| 238 | ssize_t ovl_getxattr(struct dentry *dentry, const char *name, | 244 | ssize_t ovl_getxattr(struct dentry *dentry, const char *name, |
| 239 | void *value, size_t size) | 245 | void *value, size_t size) |
| 240 | { | 246 | { |
| 241 | if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE && | 247 | struct path realpath; |
| 242 | ovl_is_private_xattr(name)) | 248 | enum ovl_path_type type = ovl_path_real(dentry, &realpath); |
| 249 | |||
| 250 | if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name)) | ||
| 243 | return -ENODATA; | 251 | return -ENODATA; |
| 244 | 252 | ||
| 245 | return vfs_getxattr(ovl_dentry_real(dentry), name, value, size); | 253 | return vfs_getxattr(realpath.dentry, name, value, size); |
| 246 | } | 254 | } |
| 247 | 255 | ||
| 248 | ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) | 256 | ssize_t ovl_listxattr(struct dentry *dentry, char *list, size_t size) |
| 249 | { | 257 | { |
| 258 | struct path realpath; | ||
| 259 | enum ovl_path_type type = ovl_path_real(dentry, &realpath); | ||
| 250 | ssize_t res; | 260 | ssize_t res; |
| 251 | int off; | 261 | int off; |
| 252 | 262 | ||
| 253 | res = vfs_listxattr(ovl_dentry_real(dentry), list, size); | 263 | res = vfs_listxattr(realpath.dentry, list, size); |
| 254 | if (res <= 0 || size == 0) | 264 | if (res <= 0 || size == 0) |
| 255 | return res; | 265 | return res; |
| 256 | 266 | ||
| 257 | if (ovl_path_type(dentry->d_parent) != OVL_PATH_MERGE) | 267 | if (!ovl_need_xattr_filter(dentry, type)) |
| 258 | return res; | 268 | return res; |
| 259 | 269 | ||
| 260 | /* filter out private xattrs */ | 270 | /* filter out private xattrs */ |
| @@ -279,17 +289,16 @@ int ovl_removexattr(struct dentry *dentry, const char *name) | |||
| 279 | { | 289 | { |
| 280 | int err; | 290 | int err; |
| 281 | struct path realpath; | 291 | struct path realpath; |
| 282 | enum ovl_path_type type; | 292 | enum ovl_path_type type = ovl_path_real(dentry, &realpath); |
| 283 | 293 | ||
| 284 | err = ovl_want_write(dentry); | 294 | err = ovl_want_write(dentry); |
| 285 | if (err) | 295 | if (err) |
| 286 | goto out; | 296 | goto out; |
| 287 | 297 | ||
| 288 | if (ovl_path_type(dentry->d_parent) == OVL_PATH_MERGE && | 298 | err = -ENODATA; |
| 289 | ovl_is_private_xattr(name)) | 299 | if (ovl_need_xattr_filter(dentry, type) && ovl_is_private_xattr(name)) |
| 290 | goto out_drop_write; | 300 | goto out_drop_write; |
| 291 | 301 | ||
| 292 | type = ovl_path_real(dentry, &realpath); | ||
| 293 | if (type == OVL_PATH_LOWER) { | 302 | if (type == OVL_PATH_LOWER) { |
| 294 | err = vfs_getxattr(realpath.dentry, name, NULL, 0); | 303 | err = vfs_getxattr(realpath.dentry, name, NULL, 0); |
| 295 | if (err < 0) | 304 | if (err < 0) |
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c index 2a7ef4f8e2a6..ab1e3dcbed95 100644 --- a/fs/overlayfs/readdir.c +++ b/fs/overlayfs/readdir.c | |||
| @@ -274,11 +274,11 @@ static int ovl_dir_mark_whiteouts(struct dentry *dir, | |||
| 274 | return 0; | 274 | return 0; |
| 275 | } | 275 | } |
| 276 | 276 | ||
| 277 | static inline int ovl_dir_read_merged(struct path *upperpath, | 277 | static int ovl_dir_read_merged(struct dentry *dentry, struct list_head *list) |
| 278 | struct path *lowerpath, | ||
| 279 | struct list_head *list) | ||
| 280 | { | 278 | { |
| 281 | int err; | 279 | int err; |
| 280 | struct path lowerpath; | ||
| 281 | struct path upperpath; | ||
| 282 | struct ovl_readdir_data rdd = { | 282 | struct ovl_readdir_data rdd = { |
| 283 | .ctx.actor = ovl_fill_merge, | 283 | .ctx.actor = ovl_fill_merge, |
| 284 | .list = list, | 284 | .list = list, |
| @@ -286,25 +286,28 @@ static inline int ovl_dir_read_merged(struct path *upperpath, | |||
| 286 | .is_merge = false, | 286 | .is_merge = false, |
| 287 | }; | 287 | }; |
| 288 | 288 | ||
| 289 | if (upperpath->dentry) { | 289 | ovl_path_lower(dentry, &lowerpath); |
| 290 | err = ovl_dir_read(upperpath, &rdd); | 290 | ovl_path_upper(dentry, &upperpath); |
| 291 | |||
| 292 | if (upperpath.dentry) { | ||
| 293 | err = ovl_dir_read(&upperpath, &rdd); | ||
| 291 | if (err) | 294 | if (err) |
| 292 | goto out; | 295 | goto out; |
| 293 | 296 | ||
| 294 | if (lowerpath->dentry) { | 297 | if (lowerpath.dentry) { |
| 295 | err = ovl_dir_mark_whiteouts(upperpath->dentry, &rdd); | 298 | err = ovl_dir_mark_whiteouts(upperpath.dentry, &rdd); |
| 296 | if (err) | 299 | if (err) |
| 297 | goto out; | 300 | goto out; |
| 298 | } | 301 | } |
| 299 | } | 302 | } |
| 300 | if (lowerpath->dentry) { | 303 | if (lowerpath.dentry) { |
| 301 | /* | 304 | /* |
| 302 | * Insert lowerpath entries before upperpath ones, this allows | 305 | * Insert lowerpath entries before upperpath ones, this allows |
| 303 | * offsets to be reasonably constant | 306 | * offsets to be reasonably constant |
| 304 | */ | 307 | */ |
| 305 | list_add(&rdd.middle, rdd.list); | 308 | list_add(&rdd.middle, rdd.list); |
| 306 | rdd.is_merge = true; | 309 | rdd.is_merge = true; |
| 307 | err = ovl_dir_read(lowerpath, &rdd); | 310 | err = ovl_dir_read(&lowerpath, &rdd); |
| 308 | list_del(&rdd.middle); | 311 | list_del(&rdd.middle); |
| 309 | } | 312 | } |
| 310 | out: | 313 | out: |
| @@ -329,8 +332,6 @@ static void ovl_seek_cursor(struct ovl_dir_file *od, loff_t pos) | |||
| 329 | static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry) | 332 | static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry) |
| 330 | { | 333 | { |
| 331 | int res; | 334 | int res; |
| 332 | struct path lowerpath; | ||
| 333 | struct path upperpath; | ||
| 334 | struct ovl_dir_cache *cache; | 335 | struct ovl_dir_cache *cache; |
| 335 | 336 | ||
| 336 | cache = ovl_dir_cache(dentry); | 337 | cache = ovl_dir_cache(dentry); |
| @@ -347,10 +348,7 @@ static struct ovl_dir_cache *ovl_cache_get(struct dentry *dentry) | |||
| 347 | cache->refcount = 1; | 348 | cache->refcount = 1; |
| 348 | INIT_LIST_HEAD(&cache->entries); | 349 | INIT_LIST_HEAD(&cache->entries); |
| 349 | 350 | ||
| 350 | ovl_path_lower(dentry, &lowerpath); | 351 | res = ovl_dir_read_merged(dentry, &cache->entries); |
| 351 | ovl_path_upper(dentry, &upperpath); | ||
| 352 | |||
| 353 | res = ovl_dir_read_merged(&upperpath, &lowerpath, &cache->entries); | ||
| 354 | if (res) { | 352 | if (res) { |
| 355 | ovl_cache_free(&cache->entries); | 353 | ovl_cache_free(&cache->entries); |
| 356 | kfree(cache); | 354 | kfree(cache); |
| @@ -452,10 +450,10 @@ static int ovl_dir_fsync(struct file *file, loff_t start, loff_t end, | |||
| 452 | /* | 450 | /* |
| 453 | * Need to check if we started out being a lower dir, but got copied up | 451 | * Need to check if we started out being a lower dir, but got copied up |
| 454 | */ | 452 | */ |
| 455 | if (!od->is_upper && ovl_path_type(dentry) == OVL_PATH_MERGE) { | 453 | if (!od->is_upper && ovl_path_type(dentry) != OVL_PATH_LOWER) { |
| 456 | struct inode *inode = file_inode(file); | 454 | struct inode *inode = file_inode(file); |
| 457 | 455 | ||
| 458 | realfile =lockless_dereference(od->upperfile); | 456 | realfile = lockless_dereference(od->upperfile); |
| 459 | if (!realfile) { | 457 | if (!realfile) { |
| 460 | struct path upperpath; | 458 | struct path upperpath; |
| 461 | 459 | ||
| @@ -538,14 +536,9 @@ const struct file_operations ovl_dir_operations = { | |||
| 538 | int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list) | 536 | int ovl_check_empty_dir(struct dentry *dentry, struct list_head *list) |
| 539 | { | 537 | { |
| 540 | int err; | 538 | int err; |
| 541 | struct path lowerpath; | ||
| 542 | struct path upperpath; | ||
| 543 | struct ovl_cache_entry *p; | 539 | struct ovl_cache_entry *p; |
| 544 | 540 | ||
| 545 | ovl_path_upper(dentry, &upperpath); | 541 | err = ovl_dir_read_merged(dentry, list); |
| 546 | ovl_path_lower(dentry, &lowerpath); | ||
| 547 | |||
| 548 | err = ovl_dir_read_merged(&upperpath, &lowerpath, list); | ||
| 549 | if (err) | 542 | if (err) |
| 550 | return err; | 543 | return err; |
| 551 | 544 | ||
diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index 08b704cebfc4..f16d318b71f8 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c | |||
| @@ -24,7 +24,7 @@ MODULE_AUTHOR("Miklos Szeredi <miklos@szeredi.hu>"); | |||
| 24 | MODULE_DESCRIPTION("Overlay filesystem"); | 24 | MODULE_DESCRIPTION("Overlay filesystem"); |
| 25 | MODULE_LICENSE("GPL"); | 25 | MODULE_LICENSE("GPL"); |
| 26 | 26 | ||
| 27 | #define OVERLAYFS_SUPER_MAGIC 0x794c764f | 27 | #define OVERLAYFS_SUPER_MAGIC 0x794c7630 |
| 28 | 28 | ||
| 29 | struct ovl_config { | 29 | struct ovl_config { |
| 30 | char *lowerdir; | 30 | char *lowerdir; |
| @@ -84,12 +84,7 @@ enum ovl_path_type ovl_path_type(struct dentry *dentry) | |||
| 84 | 84 | ||
| 85 | static struct dentry *ovl_upperdentry_dereference(struct ovl_entry *oe) | 85 | static struct dentry *ovl_upperdentry_dereference(struct ovl_entry *oe) |
| 86 | { | 86 | { |
| 87 | struct dentry *upperdentry = ACCESS_ONCE(oe->__upperdentry); | 87 | return lockless_dereference(oe->__upperdentry); |
| 88 | /* | ||
| 89 | * Make sure to order reads to upperdentry wrt ovl_dentry_update() | ||
| 90 | */ | ||
| 91 | smp_read_barrier_depends(); | ||
| 92 | return upperdentry; | ||
| 93 | } | 88 | } |
| 94 | 89 | ||
| 95 | void ovl_path_upper(struct dentry *dentry, struct path *path) | 90 | void ovl_path_upper(struct dentry *dentry, struct path *path) |
| @@ -462,11 +457,34 @@ static const match_table_t ovl_tokens = { | |||
| 462 | {OPT_ERR, NULL} | 457 | {OPT_ERR, NULL} |
| 463 | }; | 458 | }; |
| 464 | 459 | ||
| 460 | static char *ovl_next_opt(char **s) | ||
| 461 | { | ||
| 462 | char *sbegin = *s; | ||
| 463 | char *p; | ||
| 464 | |||
| 465 | if (sbegin == NULL) | ||
| 466 | return NULL; | ||
| 467 | |||
| 468 | for (p = sbegin; *p; p++) { | ||
| 469 | if (*p == '\\') { | ||
| 470 | p++; | ||
| 471 | if (!*p) | ||
| 472 | break; | ||
| 473 | } else if (*p == ',') { | ||
| 474 | *p = '\0'; | ||
| 475 | *s = p + 1; | ||
| 476 | return sbegin; | ||
| 477 | } | ||
| 478 | } | ||
| 479 | *s = NULL; | ||
| 480 | return sbegin; | ||
| 481 | } | ||
| 482 | |||
| 465 | static int ovl_parse_opt(char *opt, struct ovl_config *config) | 483 | static int ovl_parse_opt(char *opt, struct ovl_config *config) |
| 466 | { | 484 | { |
| 467 | char *p; | 485 | char *p; |
| 468 | 486 | ||
| 469 | while ((p = strsep(&opt, ",")) != NULL) { | 487 | while ((p = ovl_next_opt(&opt)) != NULL) { |
| 470 | int token; | 488 | int token; |
| 471 | substring_t args[MAX_OPT_ARGS]; | 489 | substring_t args[MAX_OPT_ARGS]; |
| 472 | 490 | ||
| @@ -554,15 +572,34 @@ out_dput: | |||
| 554 | goto out_unlock; | 572 | goto out_unlock; |
| 555 | } | 573 | } |
| 556 | 574 | ||
| 575 | static void ovl_unescape(char *s) | ||
| 576 | { | ||
| 577 | char *d = s; | ||
| 578 | |||
| 579 | for (;; s++, d++) { | ||
| 580 | if (*s == '\\') | ||
| 581 | s++; | ||
| 582 | *d = *s; | ||
| 583 | if (!*s) | ||
| 584 | break; | ||
| 585 | } | ||
| 586 | } | ||
| 587 | |||
| 557 | static int ovl_mount_dir(const char *name, struct path *path) | 588 | static int ovl_mount_dir(const char *name, struct path *path) |
| 558 | { | 589 | { |
| 559 | int err; | 590 | int err; |
| 591 | char *tmp = kstrdup(name, GFP_KERNEL); | ||
| 592 | |||
| 593 | if (!tmp) | ||
| 594 | return -ENOMEM; | ||
| 560 | 595 | ||
| 561 | err = kern_path(name, LOOKUP_FOLLOW, path); | 596 | ovl_unescape(tmp); |
| 597 | err = kern_path(tmp, LOOKUP_FOLLOW, path); | ||
| 562 | if (err) { | 598 | if (err) { |
| 563 | pr_err("overlayfs: failed to resolve '%s': %i\n", name, err); | 599 | pr_err("overlayfs: failed to resolve '%s': %i\n", tmp, err); |
| 564 | err = -EINVAL; | 600 | err = -EINVAL; |
| 565 | } | 601 | } |
| 602 | kfree(tmp); | ||
| 566 | return err; | 603 | return err; |
| 567 | } | 604 | } |
| 568 | 605 | ||
| @@ -776,11 +813,11 @@ static struct dentry *ovl_mount(struct file_system_type *fs_type, int flags, | |||
| 776 | 813 | ||
| 777 | static struct file_system_type ovl_fs_type = { | 814 | static struct file_system_type ovl_fs_type = { |
| 778 | .owner = THIS_MODULE, | 815 | .owner = THIS_MODULE, |
| 779 | .name = "overlayfs", | 816 | .name = "overlay", |
| 780 | .mount = ovl_mount, | 817 | .mount = ovl_mount, |
| 781 | .kill_sb = kill_anon_super, | 818 | .kill_sb = kill_anon_super, |
| 782 | }; | 819 | }; |
| 783 | MODULE_ALIAS_FS("overlayfs"); | 820 | MODULE_ALIAS_FS("overlay"); |
| 784 | 821 | ||
| 785 | static int __init ovl_init(void) | 822 | static int __init ovl_init(void) |
| 786 | { | 823 | { |
