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 tag 'ovl-fixes-6.6-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs

Pull overlayfs fixes from Amir Goldstein:

- Various fixes for regressions due to conversion to new mount
api in v6.5

- Disable a new mount option syntax (append lowerdir) that was
added in v6.5 because we plan to add a different lowerdir
append syntax in v6.7

* tag 'ovl-fixes-6.6-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/overlayfs/vfs:
ovl: temporarily disable appending lowedirs
ovl: fix regression in showing lowerdir mount option
ovl: fix regression in parsing of mount options with escaped comma
fs: factor out vfs_parse_monolithic_sep() helper

+97 -68
+12
Documentation/filesystems/overlayfs.rst
··· 339 339 rightmost one and going left. In the above example lower1 will be the 340 340 top, lower2 the middle and lower3 the bottom layer. 341 341 342 + Note: directory names containing colons can be provided as lower layer by 343 + escaping the colons with a single backslash. For example: 344 + 345 + mount -t overlay overlay -olowerdir=/a\:lower\:\:dir /merged 346 + 347 + Since kernel version v6.5, directory names containing colons can also 348 + be provided as lower layer using the fsconfig syscall from new mount api: 349 + 350 + fsconfig(fs_fd, FSCONFIG_SET_STRING, "lowerdir", "/a:lower::dir", 0); 351 + 352 + In the latter case, colons in lower layer directory names will be escaped 353 + as an octal characters (\072) when displayed in /proc/self/mountinfo. 342 354 343 355 Metadata only copy up 344 356 ---------------------
+29 -5
fs/fs_context.c
··· 192 192 EXPORT_SYMBOL(vfs_parse_fs_string); 193 193 194 194 /** 195 - * generic_parse_monolithic - Parse key[=val][,key[=val]]* mount data 195 + * vfs_parse_monolithic_sep - Parse key[=val][,key[=val]]* mount data 196 196 * @fc: The superblock configuration to fill in. 197 197 * @data: The data to parse 198 + * @sep: callback for separating next option 198 199 * 199 - * Parse a blob of data that's in key[=val][,key[=val]]* form. This can be 200 - * called from the ->monolithic_mount_data() fs_context operation. 200 + * Parse a blob of data that's in key[=val][,key[=val]]* form with a custom 201 + * option separator callback. 201 202 * 202 203 * Returns 0 on success or the error returned by the ->parse_option() fs_context 203 204 * operation on failure. 204 205 */ 205 - int generic_parse_monolithic(struct fs_context *fc, void *data) 206 + int vfs_parse_monolithic_sep(struct fs_context *fc, void *data, 207 + char *(*sep)(char **)) 206 208 { 207 209 char *options = data, *key; 208 210 int ret = 0; ··· 216 214 if (ret) 217 215 return ret; 218 216 219 - while ((key = strsep(&options, ",")) != NULL) { 217 + while ((key = sep(&options)) != NULL) { 220 218 if (*key) { 221 219 size_t v_len = 0; 222 220 char *value = strchr(key, '='); ··· 234 232 } 235 233 236 234 return ret; 235 + } 236 + EXPORT_SYMBOL(vfs_parse_monolithic_sep); 237 + 238 + static char *vfs_parse_comma_sep(char **s) 239 + { 240 + return strsep(s, ","); 241 + } 242 + 243 + /** 244 + * generic_parse_monolithic - Parse key[=val][,key[=val]]* mount data 245 + * @fc: The superblock configuration to fill in. 246 + * @data: The data to parse 247 + * 248 + * Parse a blob of data that's in key[=val][,key[=val]]* form. This can be 249 + * called from the ->monolithic_mount_data() fs_context operation. 250 + * 251 + * Returns 0 on success or the error returned by the ->parse_option() fs_context 252 + * operation on failure. 253 + */ 254 + int generic_parse_monolithic(struct fs_context *fc, void *data) 255 + { 256 + return vfs_parse_monolithic_sep(fc, data, vfs_parse_comma_sep); 237 257 } 238 258 EXPORT_SYMBOL(generic_parse_monolithic); 239 259
+54 -63
fs/overlayfs/params.c
··· 157 157 {} 158 158 }; 159 159 160 + static char *ovl_next_opt(char **s) 161 + { 162 + char *sbegin = *s; 163 + char *p; 164 + 165 + if (sbegin == NULL) 166 + return NULL; 167 + 168 + for (p = sbegin; *p; p++) { 169 + if (*p == '\\') { 170 + p++; 171 + if (!*p) 172 + break; 173 + } else if (*p == ',') { 174 + *p = '\0'; 175 + *s = p + 1; 176 + return sbegin; 177 + } 178 + } 179 + *s = NULL; 180 + return sbegin; 181 + } 182 + 183 + static int ovl_parse_monolithic(struct fs_context *fc, void *data) 184 + { 185 + return vfs_parse_monolithic_sep(fc, data, ovl_next_opt); 186 + } 187 + 160 188 static ssize_t ovl_parse_param_split_lowerdirs(char *str) 161 189 { 162 190 ssize_t nr_layers = 1, nr_colons = 0; ··· 192 164 193 165 for (s = d = str;; s++, d++) { 194 166 if (*s == '\\') { 195 - s++; 167 + /* keep esc chars in split lowerdir */ 168 + *d++ = *s++; 196 169 } else if (*s == ':') { 197 170 bool next_colon = (*(s + 1) == ':'); 198 171 ··· 268 239 } 269 240 } 270 241 271 - static int ovl_mount_dir(const char *name, struct path *path) 242 + static int ovl_mount_dir(const char *name, struct path *path, bool upper) 272 243 { 273 244 int err = -ENOMEM; 274 245 char *tmp = kstrdup(name, GFP_KERNEL); ··· 277 248 ovl_unescape(tmp); 278 249 err = ovl_mount_dir_noesc(tmp, path); 279 250 280 - if (!err && path->dentry->d_flags & DCACHE_OP_REAL) { 251 + if (!err && upper && path->dentry->d_flags & DCACHE_OP_REAL) { 281 252 pr_err("filesystem on '%s' not supported as upperdir\n", 282 253 tmp); 283 254 path_put_init(path); ··· 298 269 struct path path; 299 270 char *dup; 300 271 301 - err = ovl_mount_dir(name, &path); 272 + err = ovl_mount_dir(name, &path, true); 302 273 if (err) 303 274 return err; 304 275 ··· 350 321 * Set "/lower1", "/lower2", and "/lower3" as lower layers and 351 322 * "/data1" and "/data2" as data lower layers. Any existing lower 352 323 * layers are replaced. 353 - * (2) lowerdir=:/lower4 354 - * Append "/lower4" to current stack of lower layers. This requires 355 - * that there already is at least one lower layer configured. 356 - * (3) lowerdir=::/lower5 357 - * Append data "/lower5" as data lower layer. This requires that 358 - * there's at least one regular lower layer present. 359 324 */ 360 325 static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc) 361 326 { ··· 371 348 return 0; 372 349 } 373 350 374 - if (strncmp(name, "::", 2) == 0) { 375 - /* 376 - * This is a data layer. 377 - * There must be at least one regular lower layer 378 - * specified. 379 - */ 380 - if (ctx->nr == 0) { 381 - pr_err("data lower layers without regular lower layers not allowed"); 382 - return -EINVAL; 383 - } 384 - 385 - /* Skip the leading "::". */ 386 - name += 2; 387 - data_layer = true; 388 - /* 389 - * A data layer is automatically an append as there 390 - * must've been at least one regular lower layer. 391 - */ 392 - append = true; 393 - } else if (*name == ':') { 394 - /* 395 - * This is a regular lower layer. 396 - * If users want to append a layer enforce that they 397 - * have already specified a first layer before. It's 398 - * better to be strict. 399 - */ 400 - if (ctx->nr == 0) { 401 - pr_err("cannot append layer if no previous layer has been specified"); 402 - return -EINVAL; 403 - } 404 - 405 - /* 406 - * Once a sequence of data layers has started regular 407 - * lower layers are forbidden. 408 - */ 409 - if (ctx->nr_data > 0) { 410 - pr_err("regular lower layers cannot follow data lower layers"); 411 - return -EINVAL; 412 - } 413 - 414 - /* Skip the leading ":". */ 415 - name++; 416 - append = true; 351 + if (*name == ':') { 352 + pr_err("cannot append lower layer"); 353 + return -EINVAL; 417 354 } 418 355 419 356 dup = kstrdup(name, GFP_KERNEL); ··· 455 472 l = &ctx->lower[nr]; 456 473 memset(l, 0, sizeof(*l)); 457 474 458 - err = ovl_mount_dir_noesc(dup_iter, &l->path); 475 + err = ovl_mount_dir(dup_iter, &l->path, false); 459 476 if (err) 460 477 goto out_put; 461 478 ··· 665 682 } 666 683 667 684 static const struct fs_context_operations ovl_context_ops = { 685 + .parse_monolithic = ovl_parse_monolithic, 668 686 .parse_param = ovl_parse_param, 669 687 .get_tree = ovl_get_tree, 670 688 .reconfigure = ovl_reconfigure, ··· 934 950 struct super_block *sb = dentry->d_sb; 935 951 struct ovl_fs *ofs = OVL_FS(sb); 936 952 size_t nr, nr_merged_lower = ofs->numlayer - ofs->numdatalayer; 937 - char **lowerdatadirs = &ofs->config.lowerdirs[nr_merged_lower]; 938 953 939 - /* lowerdirs[] starts from offset 1 */ 940 - seq_printf(m, ",lowerdir=%s", ofs->config.lowerdirs[1]); 941 - /* dump regular lower layers */ 942 - for (nr = 2; nr < nr_merged_lower; nr++) 943 - seq_printf(m, ":%s", ofs->config.lowerdirs[nr]); 944 - /* dump data lower layers */ 945 - for (nr = 0; nr < ofs->numdatalayer; nr++) 946 - seq_printf(m, "::%s", lowerdatadirs[nr]); 954 + /* 955 + * lowerdirs[] starts from offset 1, then 956 + * >= 0 regular lower layers prefixed with : and 957 + * >= 0 data-only lower layers prefixed with :: 958 + * 959 + * we need to escase comma and space like seq_show_option() does and 960 + * we also need to escape the colon separator from lowerdir paths. 961 + */ 962 + seq_puts(m, ",lowerdir="); 963 + for (nr = 1; nr < ofs->numlayer; nr++) { 964 + if (nr > 1) 965 + seq_putc(m, ':'); 966 + if (nr >= nr_merged_lower) 967 + seq_putc(m, ':'); 968 + seq_escape(m, ofs->config.lowerdirs[nr], ":, \t\n\\"); 969 + } 947 970 if (ofs->config.upperdir) { 948 971 seq_show_option(m, "upperdir", ofs->config.upperdir); 949 972 seq_show_option(m, "workdir", ofs->config.workdir);
+2
include/linux/fs_context.h
··· 136 136 extern int vfs_parse_fs_param(struct fs_context *fc, struct fs_parameter *param); 137 137 extern int vfs_parse_fs_string(struct fs_context *fc, const char *key, 138 138 const char *value, size_t v_size); 139 + int vfs_parse_monolithic_sep(struct fs_context *fc, void *data, 140 + char *(*sep)(char **)); 139 141 extern int generic_parse_monolithic(struct fs_context *fc, void *data); 140 142 extern int vfs_get_tree(struct fs_context *fc); 141 143 extern void put_fs_context(struct fs_context *fc);