@@ -157,14 +157,43 @@ const struct fs_parameter_spec ovl_parameter_spec[] = {
157157 {}
158158};
159159
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+
160188static ssize_t ovl_parse_param_split_lowerdirs (char * str )
161189{
162190 ssize_t nr_layers = 1 , nr_colons = 0 ;
163191 char * s , * d ;
164192
165193 for (s = d = str ;; s ++ , d ++ ) {
166194 if (* s == '\\' ) {
167- s ++ ;
195+ /* keep esc chars in split lowerdir */
196+ * d ++ = * s ++ ;
168197 } else if (* s == ':' ) {
169198 bool next_colon = (* (s + 1 ) == ':' );
170199
@@ -239,7 +268,7 @@ static void ovl_unescape(char *s)
239268 }
240269}
241270
242- static int ovl_mount_dir (const char * name , struct path * path )
271+ static int ovl_mount_dir (const char * name , struct path * path , bool upper )
243272{
244273 int err = - ENOMEM ;
245274 char * tmp = kstrdup (name , GFP_KERNEL );
@@ -248,7 +277,7 @@ static int ovl_mount_dir(const char *name, struct path *path)
248277 ovl_unescape (tmp );
249278 err = ovl_mount_dir_noesc (tmp , path );
250279
251- if (!err && path -> dentry -> d_flags & DCACHE_OP_REAL ) {
280+ if (!err && upper && path -> dentry -> d_flags & DCACHE_OP_REAL ) {
252281 pr_err ("filesystem on '%s' not supported as upperdir\n" ,
253282 tmp );
254283 path_put_init (path );
@@ -269,7 +298,7 @@ static int ovl_parse_param_upperdir(const char *name, struct fs_context *fc,
269298 struct path path ;
270299 char * dup ;
271300
272- err = ovl_mount_dir (name , & path );
301+ err = ovl_mount_dir (name , & path , true );
273302 if (err )
274303 return err ;
275304
@@ -321,12 +350,6 @@ static void ovl_parse_param_drop_lowerdir(struct ovl_fs_context *ctx)
321350 * Set "/lower1", "/lower2", and "/lower3" as lower layers and
322351 * "/data1" and "/data2" as data lower layers. Any existing lower
323352 * layers are replaced.
324- * (2) lowerdir=:/lower4
325- * Append "/lower4" to current stack of lower layers. This requires
326- * that there already is at least one lower layer configured.
327- * (3) lowerdir=::/lower5
328- * Append data "/lower5" as data lower layer. This requires that
329- * there's at least one regular lower layer present.
330353 */
331354static int ovl_parse_param_lowerdir (const char * name , struct fs_context * fc )
332355{
@@ -348,49 +371,9 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc)
348371 return 0 ;
349372 }
350373
351- if (strncmp (name , "::" , 2 ) == 0 ) {
352- /*
353- * This is a data layer.
354- * There must be at least one regular lower layer
355- * specified.
356- */
357- if (ctx -> nr == 0 ) {
358- pr_err ("data lower layers without regular lower layers not allowed" );
359- return - EINVAL ;
360- }
361-
362- /* Skip the leading "::". */
363- name += 2 ;
364- data_layer = true;
365- /*
366- * A data layer is automatically an append as there
367- * must've been at least one regular lower layer.
368- */
369- append = true;
370- } else if (* name == ':' ) {
371- /*
372- * This is a regular lower layer.
373- * If users want to append a layer enforce that they
374- * have already specified a first layer before. It's
375- * better to be strict.
376- */
377- if (ctx -> nr == 0 ) {
378- pr_err ("cannot append layer if no previous layer has been specified" );
379- return - EINVAL ;
380- }
381-
382- /*
383- * Once a sequence of data layers has started regular
384- * lower layers are forbidden.
385- */
386- if (ctx -> nr_data > 0 ) {
387- pr_err ("regular lower layers cannot follow data lower layers" );
388- return - EINVAL ;
389- }
390-
391- /* Skip the leading ":". */
392- name ++ ;
393- append = true;
374+ if (* name == ':' ) {
375+ pr_err ("cannot append lower layer" );
376+ return - EINVAL ;
394377 }
395378
396379 dup = kstrdup (name , GFP_KERNEL );
@@ -472,7 +455,7 @@ static int ovl_parse_param_lowerdir(const char *name, struct fs_context *fc)
472455 l = & ctx -> lower [nr ];
473456 memset (l , 0 , sizeof (* l ));
474457
475- err = ovl_mount_dir_noesc (dup_iter , & l -> path );
458+ err = ovl_mount_dir (dup_iter , & l -> path , false );
476459 if (err )
477460 goto out_put ;
478461
@@ -682,6 +665,7 @@ static int ovl_reconfigure(struct fs_context *fc)
682665}
683666
684667static const struct fs_context_operations ovl_context_ops = {
668+ .parse_monolithic = ovl_parse_monolithic ,
685669 .parse_param = ovl_parse_param ,
686670 .get_tree = ovl_get_tree ,
687671 .reconfigure = ovl_reconfigure ,
@@ -950,16 +934,23 @@ int ovl_show_options(struct seq_file *m, struct dentry *dentry)
950934 struct super_block * sb = dentry -> d_sb ;
951935 struct ovl_fs * ofs = OVL_FS (sb );
952936 size_t nr , nr_merged_lower = ofs -> numlayer - ofs -> numdatalayer ;
953- char * * lowerdatadirs = & ofs -> config .lowerdirs [nr_merged_lower ];
954-
955- /* lowerdirs[] starts from offset 1 */
956- seq_printf (m , ",lowerdir=%s" , ofs -> config .lowerdirs [1 ]);
957- /* dump regular lower layers */
958- for (nr = 2 ; nr < nr_merged_lower ; nr ++ )
959- seq_printf (m , ":%s" , ofs -> config .lowerdirs [nr ]);
960- /* dump data lower layers */
961- for (nr = 0 ; nr < ofs -> numdatalayer ; nr ++ )
962- seq_printf (m , "::%s" , lowerdatadirs [nr ]);
937+
938+ /*
939+ * lowerdirs[] starts from offset 1, then
940+ * >= 0 regular lower layers prefixed with : and
941+ * >= 0 data-only lower layers prefixed with ::
942+ *
943+ * we need to escase comma and space like seq_show_option() does and
944+ * we also need to escape the colon separator from lowerdir paths.
945+ */
946+ seq_puts (m , ",lowerdir=" );
947+ for (nr = 1 ; nr < ofs -> numlayer ; nr ++ ) {
948+ if (nr > 1 )
949+ seq_putc (m , ':' );
950+ if (nr >= nr_merged_lower )
951+ seq_putc (m , ':' );
952+ seq_escape (m , ofs -> config .lowerdirs [nr ], ":, \t\n\\" );
953+ }
963954 if (ofs -> config .upperdir ) {
964955 seq_show_option (m , "upperdir" , ofs -> config .upperdir );
965956 seq_show_option (m , "workdir" , ofs -> config .workdir );
0 commit comments