/* * Parse mount options. See the manual page for usage instructions. * * Returns the dentry object of the lower-level (lower) directory; * We want to mount our stackable file system on top of that lower directory. */ static struct unionfs_dentry_info *unionfs_parse_options( struct super_block *sb, char *options) { struct unionfs_dentry_info *lower_root_info; char *optname; int err = 0; int bindex; int dirsfound = 0; /* allocate private data area */ err = -ENOMEM; lower_root_info = kzalloc(sizeof(struct unionfs_dentry_info), GFP_KERNEL); if (unlikely(!lower_root_info)) goto out_error; lower_root_info->bstart = -1; lower_root_info->bend = -1; lower_root_info->bopaque = -1; while ((optname = strsep(&options, ",")) != NULL) { char *optarg; if (!optname || !*optname) continue; optarg = strchr(optname, '='); if (optarg) *optarg++ = '\0'; /* * All of our options take an argument now. Insert ones that * don't, above this check. */ if (!optarg) { printk(KERN_ERR "unionfs: %s requires an argument\n", optname); err = -EINVAL; goto out_error; } if (!strcmp("dirs", optname)) { if (++dirsfound > 1) { printk(KERN_ERR "unionfs: multiple dirs specified\n"); err = -EINVAL; goto out_error; } err = parse_dirs_option(sb, lower_root_info, optarg); if (err) goto out_error; continue; } err = -EINVAL; printk(KERN_ERR "unionfs: unrecognized option '%s'\n", optname); goto out_error; } if (dirsfound != 1) { printk(KERN_ERR "unionfs: dirs option required\n"); err = -EINVAL; goto out_error; } goto out; out_error: if (lower_root_info && lower_root_info->lower_paths) { for (bindex = lower_root_info->bstart; bindex >= 0 && bindex <= lower_root_info->bend; bindex++) { struct dentry *d; struct vfsmount *m; d = lower_root_info->lower_paths[bindex].dentry; m = lower_root_info->lower_paths[bindex].mnt; dput(d); /* initializing: can't use unionfs_mntput here */ mntput(m); } } kfree(lower_root_info->lower_paths); kfree(lower_root_info); kfree(UNIONFS_SB(sb)->data); UNIONFS_SB(sb)->data = NULL; lower_root_info = ERR_PTR(err); out: return lower_root_info; }
/* * Parse mount options. See the manual page for usage instructions. * * Returns the dentry object of the lower-level (hidden) directory; * We want to mount our stackable file system on top of that hidden directory. * * Sets default debugging level to N, if any. */ static struct unionfs_dentry_info *unionfs_parse_options(struct super_block *sb, char *options) { struct unionfs_dentry_info *hidden_root_info; char *optname; int err = 0; int bindex; int dirsfound = 0; #ifdef UNIONFS_IMAP int imapfound = 0; #endif print_entry_location(); /* allocate private data area */ err = -ENOMEM; hidden_root_info = KZALLOC(sizeof(struct unionfs_dentry_info), GFP_KERNEL); if (!hidden_root_info) goto out_error; hidden_root_info->udi_bstart = -1; hidden_root_info->udi_bend = -1; hidden_root_info->udi_bopaque = -1; while ((optname = strsep(&options, ",")) != NULL) { char *optarg; char *endptr; int intval; if (!*optname) { continue; } optarg = strchr(optname, '='); if (optarg) { *optarg++ = '\0'; } /* All of our options take an argument now. Insert ones that * don't, above this check. */ if (!optarg) { printk("unionfs: %s requires an argument.\n", optname); err = -EINVAL; goto out_error; } if (!strcmp("dirs", optname)) { if (++dirsfound > 1) { printk(KERN_WARNING "unionfs: multiple dirs specified\n"); err = -EINVAL; goto out_error; } err = parse_dirs_option(sb, hidden_root_info, optarg); if (err) goto out_error; continue; } #ifdef UNIONFS_IMAP if (!strcmp("imap", optname)) { if (++imapfound > 1) { printk(KERN_WARNING "unionfs: multiple imap specified\n"); err = -EINVAL; goto out_error; } err = parse_imap_option(sb, hidden_root_info, optarg); if (err) goto out_error; continue; } #endif if (!strcmp("delete", optname)) { if (!strcmp("whiteout", optarg)) { /* default */ #ifdef UNIONFS_DELETE_ALL } else if (!strcmp("all", optarg)) { MOUNT_FLAG(sb) |= DELETE_ALL; #endif } else { printk(KERN_WARNING "unionfs: invalid delete option '%s'\n", optarg); err = -EINVAL; goto out_error; } continue; } if (!strcmp("copyup", optname)) { if (!strcmp("preserve", optarg)) { /* default */ } else if (!strcmp("currentuser", optarg)) { MOUNT_FLAG(sb) |= COPYUP_CURRENT_USER; } else { printk(KERN_WARNING "unionfs: could not parse copyup option value '%s'\n", optarg); err = -EINVAL; goto out_error; } continue; } /* All of these options require an integer argument. */ intval = simple_strtoul(optarg, &endptr, 0); if (*endptr) { printk(KERN_WARNING "unionfs: invalid %s option '%s'\n", optname, optarg); err = -EINVAL; goto out_error; } if (!strcmp("debug", optname)) { fist_set_debug_value(intval); continue; } err = -EINVAL; printk(KERN_WARNING "unionfs: unrecognized option '%s'\n", optname); goto out_error; } if (dirsfound != 1) { printk(KERN_WARNING "unionfs: dirs option required\n"); err = -EINVAL; goto out_error; } goto out; out_error: if (hidden_root_info && hidden_root_info->udi_dentry) { for (bindex = hidden_root_info->udi_bstart; bindex >= 0 && bindex <= hidden_root_info->udi_bend; bindex++) { struct dentry *d; d = hidden_root_info->udi_dentry[bindex]; DPUT(d); if (stohiddenmnt_index(sb, bindex)) mntput(stohiddenmnt_index(sb, bindex)); } } KFREE(hidden_root_info->udi_dentry); KFREE(hidden_root_info); KFREE(stopd(sb)->usi_data); stopd(sb)->usi_data = NULL; hidden_root_info = ERR_PTR(err); out: print_exit_location(); return hidden_root_info; }