/* * This function fills in xfs_mount_t fields based on mount args. * Note: the superblock has _not_ yet been read in. * * Note that this function leaks the various device name allocations on * failure. The caller takes care of them. */ STATIC int xfs_parseargs( struct xfs_mount *mp, char *options) { struct super_block *sb = mp->m_super; char *this_char, *value; int dsunit = 0; int dswidth = 0; int iosize = 0; __uint8_t iosizelog = 0; /* * set up the mount name first so all the errors will refer to the * correct device. */ mp->m_fsname = kstrndup(sb->s_id, MAXNAMELEN, GFP_KERNEL); if (!mp->m_fsname) return -ENOMEM; mp->m_fsname_len = strlen(mp->m_fsname) + 1; /* * Copy binary VFS mount flags we are interested in. */ if (sb->s_flags & MS_RDONLY) mp->m_flags |= XFS_MOUNT_RDONLY; if (sb->s_flags & MS_DIRSYNC) mp->m_flags |= XFS_MOUNT_DIRSYNC; if (sb->s_flags & MS_SYNCHRONOUS) mp->m_flags |= XFS_MOUNT_WSYNC; /* * Set some default flags that could be cleared by the mount option * parsing. */ mp->m_flags |= XFS_MOUNT_BARRIER; mp->m_flags |= XFS_MOUNT_COMPAT_IOSIZE; /* * These can be overridden by the mount option parsing. */ mp->m_logbufs = -1; mp->m_logbsize = -1; if (!options) goto done; while ((this_char = strsep(&options, ",")) != NULL) { if (!*this_char) continue; if ((value = strchr(this_char, '=')) != NULL) *value++ = 0; if (!strcmp(this_char, MNTOPT_LOGBUFS)) { if (!value || !*value) { xfs_warn(mp, "%s option requires an argument", this_char); return -EINVAL; } if (kstrtoint(value, 10, &mp->m_logbufs)) return -EINVAL; } else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) { if (!value || !*value) { xfs_warn(mp, "%s option requires an argument", this_char); return -EINVAL; } if (suffix_kstrtoint(value, 10, &mp->m_logbsize)) return -EINVAL; } else if (!strcmp(this_char, MNTOPT_LOGDEV)) { if (!value || !*value) { xfs_warn(mp, "%s option requires an argument", this_char); return -EINVAL; } mp->m_logname = kstrndup(value, MAXNAMELEN, GFP_KERNEL); if (!mp->m_logname) return -ENOMEM; } else if (!strcmp(this_char, MNTOPT_MTPT)) { xfs_warn(mp, "%s option not allowed on this system", this_char); return -EINVAL; } else if (!strcmp(this_char, MNTOPT_RTDEV)) { if (!value || !*value) { xfs_warn(mp, "%s option requires an argument", this_char); return -EINVAL; } mp->m_rtname = kstrndup(value, MAXNAMELEN, GFP_KERNEL); if (!mp->m_rtname) return -ENOMEM; } else if (!strcmp(this_char, MNTOPT_BIOSIZE)) { if (!value || !*value) { xfs_warn(mp, "%s option requires an argument", this_char); return -EINVAL; } if (kstrtoint(value, 10, &iosize)) return -EINVAL; iosizelog = ffs(iosize) - 1; } else if (!strcmp(this_char, MNTOPT_ALLOCSIZE)) { if (!value || !*value) { xfs_warn(mp, "%s option requires an argument", this_char); return -EINVAL; } if (suffix_kstrtoint(value, 10, &iosize)) return -EINVAL; iosizelog = ffs(iosize) - 1; } else if (!strcmp(this_char, MNTOPT_GRPID) || !strcmp(this_char, MNTOPT_BSDGROUPS)) { mp->m_flags |= XFS_MOUNT_GRPID; } else if (!strcmp(this_char, MNTOPT_NOGRPID) || !strcmp(this_char, MNTOPT_SYSVGROUPS)) { mp->m_flags &= ~XFS_MOUNT_GRPID; } else if (!strcmp(this_char, MNTOPT_WSYNC)) { mp->m_flags |= XFS_MOUNT_WSYNC; } else if (!strcmp(this_char, MNTOPT_NORECOVERY)) { mp->m_flags |= XFS_MOUNT_NORECOVERY; } else if (!strcmp(this_char, MNTOPT_NOALIGN)) { mp->m_flags |= XFS_MOUNT_NOALIGN; } else if (!strcmp(this_char, MNTOPT_SWALLOC)) { mp->m_flags |= XFS_MOUNT_SWALLOC; } else if (!strcmp(this_char, MNTOPT_SUNIT)) { if (!value || !*value) { xfs_warn(mp, "%s option requires an argument", this_char); return -EINVAL; } if (kstrtoint(value, 10, &dsunit)) return -EINVAL; } else if (!strcmp(this_char, MNTOPT_SWIDTH)) { if (!value || !*value) { xfs_warn(mp, "%s option requires an argument", this_char); return -EINVAL; } if (kstrtoint(value, 10, &dswidth)) return -EINVAL; } else if (!strcmp(this_char, MNTOPT_32BITINODE)) { mp->m_flags |= XFS_MOUNT_SMALL_INUMS; } else if (!strcmp(this_char, MNTOPT_64BITINODE)) { mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS; } else if (!strcmp(this_char, MNTOPT_NOUUID)) { mp->m_flags |= XFS_MOUNT_NOUUID; } else if (!strcmp(this_char, MNTOPT_BARRIER)) { mp->m_flags |= XFS_MOUNT_BARRIER; } else if (!strcmp(this_char, MNTOPT_NOBARRIER)) { mp->m_flags &= ~XFS_MOUNT_BARRIER; } else if (!strcmp(this_char, MNTOPT_IKEEP)) { mp->m_flags |= XFS_MOUNT_IKEEP; } else if (!strcmp(this_char, MNTOPT_NOIKEEP)) { mp->m_flags &= ~XFS_MOUNT_IKEEP; } else if (!strcmp(this_char, MNTOPT_LARGEIO)) { mp->m_flags &= ~XFS_MOUNT_COMPAT_IOSIZE; } else if (!strcmp(this_char, MNTOPT_NOLARGEIO)) { mp->m_flags |= XFS_MOUNT_COMPAT_IOSIZE; } else if (!strcmp(this_char, MNTOPT_ATTR2)) { mp->m_flags |= XFS_MOUNT_ATTR2; } else if (!strcmp(this_char, MNTOPT_NOATTR2)) { mp->m_flags &= ~XFS_MOUNT_ATTR2; mp->m_flags |= XFS_MOUNT_NOATTR2; } else if (!strcmp(this_char, MNTOPT_FILESTREAM)) { mp->m_flags |= XFS_MOUNT_FILESTREAMS; } else if (!strcmp(this_char, MNTOPT_NOQUOTA)) { mp->m_qflags &= ~XFS_ALL_QUOTA_ACCT; mp->m_qflags &= ~XFS_ALL_QUOTA_ENFD; mp->m_qflags &= ~XFS_ALL_QUOTA_ACTIVE; } else if (!strcmp(this_char, MNTOPT_QUOTA) || !strcmp(this_char, MNTOPT_UQUOTA) || !strcmp(this_char, MNTOPT_USRQUOTA)) { mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE | XFS_UQUOTA_ENFD); } else if (!strcmp(this_char, MNTOPT_QUOTANOENF) || !strcmp(this_char, MNTOPT_UQUOTANOENF)) { mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE); mp->m_qflags &= ~XFS_UQUOTA_ENFD; } else if (!strcmp(this_char, MNTOPT_PQUOTA) || !strcmp(this_char, MNTOPT_PRJQUOTA)) { mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE | XFS_PQUOTA_ENFD); } else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) { mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE); mp->m_qflags &= ~XFS_PQUOTA_ENFD; } else if (!strcmp(this_char, MNTOPT_GQUOTA) || !strcmp(this_char, MNTOPT_GRPQUOTA)) { mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE | XFS_GQUOTA_ENFD); } else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) { mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE); mp->m_qflags &= ~XFS_GQUOTA_ENFD; } else if (!strcmp(this_char, MNTOPT_DISCARD)) { mp->m_flags |= XFS_MOUNT_DISCARD; } else if (!strcmp(this_char, MNTOPT_NODISCARD)) { mp->m_flags &= ~XFS_MOUNT_DISCARD; } else { xfs_warn(mp, "unknown mount option [%s].", this_char); return -EINVAL; } } /* * no recovery flag requires a read-only mount */ if ((mp->m_flags & XFS_MOUNT_NORECOVERY) && !(mp->m_flags & XFS_MOUNT_RDONLY)) { xfs_warn(mp, "no-recovery mounts must be read-only."); return -EINVAL; } if ((mp->m_flags & XFS_MOUNT_NOALIGN) && (dsunit || dswidth)) { xfs_warn(mp, "sunit and swidth options incompatible with the noalign option"); return -EINVAL; } #ifndef CONFIG_XFS_QUOTA if (XFS_IS_QUOTA_RUNNING(mp)) { xfs_warn(mp, "quota support not available in this kernel."); return -EINVAL; } #endif if ((dsunit && !dswidth) || (!dsunit && dswidth)) { xfs_warn(mp, "sunit and swidth must be specified together"); return -EINVAL; } if (dsunit && (dswidth % dsunit != 0)) { xfs_warn(mp, "stripe width (%d) must be a multiple of the stripe unit (%d)", dswidth, dsunit); return -EINVAL; } done: if (dsunit && !(mp->m_flags & XFS_MOUNT_NOALIGN)) { /* * At this point the superblock has not been read * in, therefore we do not know the block size. * Before the mount call ends we will convert * these to FSBs. */ mp->m_dalign = dsunit; mp->m_swidth = dswidth; } if (mp->m_logbufs != -1 && mp->m_logbufs != 0 && (mp->m_logbufs < XLOG_MIN_ICLOGS || mp->m_logbufs > XLOG_MAX_ICLOGS)) { xfs_warn(mp, "invalid logbufs value: %d [not %d-%d]", mp->m_logbufs, XLOG_MIN_ICLOGS, XLOG_MAX_ICLOGS); return -EINVAL; } if (mp->m_logbsize != -1 && mp->m_logbsize != 0 && (mp->m_logbsize < XLOG_MIN_RECORD_BSIZE || mp->m_logbsize > XLOG_MAX_RECORD_BSIZE || !is_power_of_2(mp->m_logbsize))) { xfs_warn(mp, "invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]", mp->m_logbsize); return -EINVAL; } if (iosizelog) { if (iosizelog > XFS_MAX_IO_LOG || iosizelog < XFS_MIN_IO_LOG) { xfs_warn(mp, "invalid log iosize: %d [not %d-%d]", iosizelog, XFS_MIN_IO_LOG, XFS_MAX_IO_LOG); return -EINVAL; } mp->m_flags |= XFS_MOUNT_DFLT_IOSIZE; mp->m_readio_log = iosizelog; mp->m_writeio_log = iosizelog; } return 0; }
/* * This function fills in xfs_mount_t fields based on mount args. * Note: the superblock has _not_ yet been read in. * * Note that this function leaks the various device name allocations on * failure. The caller takes care of them. * * *sb is const because this is also used to test options on the remount * path, and we don't want this to have any side effects at remount time. * Today this function does not change *sb, but just to future-proof... */ STATIC int xfs_parseargs( struct xfs_mount *mp, char *options) { const struct super_block *sb = mp->m_super; char *p; substring_t args[MAX_OPT_ARGS]; int dsunit = 0; int dswidth = 0; int iosize = 0; __uint8_t iosizelog = 0; /* * set up the mount name first so all the errors will refer to the * correct device. */ mp->m_fsname = kstrndup(sb->s_id, MAXNAMELEN, GFP_KERNEL); if (!mp->m_fsname) return -ENOMEM; mp->m_fsname_len = strlen(mp->m_fsname) + 1; /* * Copy binary VFS mount flags we are interested in. */ if (sb->s_flags & MS_RDONLY) mp->m_flags |= XFS_MOUNT_RDONLY; if (sb->s_flags & MS_DIRSYNC) mp->m_flags |= XFS_MOUNT_DIRSYNC; if (sb->s_flags & MS_SYNCHRONOUS) mp->m_flags |= XFS_MOUNT_WSYNC; /* * Set some default flags that could be cleared by the mount option * parsing. */ mp->m_flags |= XFS_MOUNT_BARRIER; mp->m_flags |= XFS_MOUNT_COMPAT_IOSIZE; /* * These can be overridden by the mount option parsing. */ mp->m_logbufs = -1; mp->m_logbsize = -1; if (!options) goto done; while ((p = strsep(&options, ",")) != NULL) { int token; if (!*p) continue; token = match_token(p, tokens, args); switch (token) { case Opt_logbufs: if (match_int(args, &mp->m_logbufs)) return -EINVAL; break; case Opt_logbsize: if (suffix_kstrtoint(args, 10, &mp->m_logbsize)) return -EINVAL; break; case Opt_logdev: mp->m_logname = match_strdup(args); if (!mp->m_logname) return -ENOMEM; break; case Opt_mtpt: xfs_warn(mp, "%s option not allowed on this system", p); return -EINVAL; case Opt_rtdev: mp->m_rtname = match_strdup(args); if (!mp->m_rtname) return -ENOMEM; break; case Opt_allocsize: case Opt_biosize: if (suffix_kstrtoint(args, 10, &iosize)) return -EINVAL; iosizelog = ffs(iosize) - 1; break; case Opt_grpid: case Opt_bsdgroups: mp->m_flags |= XFS_MOUNT_GRPID; break; case Opt_nogrpid: case Opt_sysvgroups: mp->m_flags &= ~XFS_MOUNT_GRPID; break; case Opt_wsync: mp->m_flags |= XFS_MOUNT_WSYNC; break; case Opt_norecovery: mp->m_flags |= XFS_MOUNT_NORECOVERY; break; case Opt_noalign: mp->m_flags |= XFS_MOUNT_NOALIGN; break; case Opt_swalloc: mp->m_flags |= XFS_MOUNT_SWALLOC; break; case Opt_sunit: if (match_int(args, &dsunit)) return -EINVAL; break; case Opt_swidth: if (match_int(args, &dswidth)) return -EINVAL; break; case Opt_inode32: mp->m_flags |= XFS_MOUNT_SMALL_INUMS; break; case Opt_inode64: mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS; break; case Opt_nouuid: mp->m_flags |= XFS_MOUNT_NOUUID; break; case Opt_barrier: mp->m_flags |= XFS_MOUNT_BARRIER; break; case Opt_nobarrier: mp->m_flags &= ~XFS_MOUNT_BARRIER; break; case Opt_ikeep: mp->m_flags |= XFS_MOUNT_IKEEP; break; case Opt_noikeep: mp->m_flags &= ~XFS_MOUNT_IKEEP; break; case Opt_largeio: mp->m_flags &= ~XFS_MOUNT_COMPAT_IOSIZE; break; case Opt_nolargeio: mp->m_flags |= XFS_MOUNT_COMPAT_IOSIZE; break; case Opt_attr2: mp->m_flags |= XFS_MOUNT_ATTR2; break; case Opt_noattr2: mp->m_flags &= ~XFS_MOUNT_ATTR2; mp->m_flags |= XFS_MOUNT_NOATTR2; break; case Opt_filestreams: mp->m_flags |= XFS_MOUNT_FILESTREAMS; break; case Opt_noquota: mp->m_qflags &= ~XFS_ALL_QUOTA_ACCT; mp->m_qflags &= ~XFS_ALL_QUOTA_ENFD; mp->m_qflags &= ~XFS_ALL_QUOTA_ACTIVE; break; case Opt_quota: case Opt_uquota: case Opt_usrquota: mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE | XFS_UQUOTA_ENFD); break; case Opt_qnoenforce: case Opt_uqnoenforce: mp->m_qflags |= (XFS_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE); mp->m_qflags &= ~XFS_UQUOTA_ENFD; break; case Opt_pquota: case Opt_prjquota: mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE | XFS_PQUOTA_ENFD); break; case Opt_pqnoenforce: mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE); mp->m_qflags &= ~XFS_PQUOTA_ENFD; break; case Opt_gquota: case Opt_grpquota: mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE | XFS_GQUOTA_ENFD); break; case Opt_gqnoenforce: mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE); mp->m_qflags &= ~XFS_GQUOTA_ENFD; break; case Opt_discard: mp->m_flags |= XFS_MOUNT_DISCARD; break; case Opt_nodiscard: mp->m_flags &= ~XFS_MOUNT_DISCARD; break; #ifdef CONFIG_FS_DAX case Opt_dax: mp->m_flags |= XFS_MOUNT_DAX; break; #endif default: xfs_warn(mp, "unknown mount option [%s].", p); return -EINVAL; } } /* * no recovery flag requires a read-only mount */ if ((mp->m_flags & XFS_MOUNT_NORECOVERY) && !(mp->m_flags & XFS_MOUNT_RDONLY)) { xfs_warn(mp, "no-recovery mounts must be read-only."); return -EINVAL; } if ((mp->m_flags & XFS_MOUNT_NOALIGN) && (dsunit || dswidth)) { xfs_warn(mp, "sunit and swidth options incompatible with the noalign option"); return -EINVAL; } #ifndef CONFIG_XFS_QUOTA if (XFS_IS_QUOTA_RUNNING(mp)) { xfs_warn(mp, "quota support not available in this kernel."); return -EINVAL; } #endif if ((dsunit && !dswidth) || (!dsunit && dswidth)) { xfs_warn(mp, "sunit and swidth must be specified together"); return -EINVAL; } if (dsunit && (dswidth % dsunit != 0)) { xfs_warn(mp, "stripe width (%d) must be a multiple of the stripe unit (%d)", dswidth, dsunit); return -EINVAL; } done: if (dsunit && !(mp->m_flags & XFS_MOUNT_NOALIGN)) { /* * At this point the superblock has not been read * in, therefore we do not know the block size. * Before the mount call ends we will convert * these to FSBs. */ mp->m_dalign = dsunit; mp->m_swidth = dswidth; } if (mp->m_logbufs != -1 && mp->m_logbufs != 0 && (mp->m_logbufs < XLOG_MIN_ICLOGS || mp->m_logbufs > XLOG_MAX_ICLOGS)) { xfs_warn(mp, "invalid logbufs value: %d [not %d-%d]", mp->m_logbufs, XLOG_MIN_ICLOGS, XLOG_MAX_ICLOGS); return -EINVAL; } if (mp->m_logbsize != -1 && mp->m_logbsize != 0 && (mp->m_logbsize < XLOG_MIN_RECORD_BSIZE || mp->m_logbsize > XLOG_MAX_RECORD_BSIZE || !is_power_of_2(mp->m_logbsize))) { xfs_warn(mp, "invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]", mp->m_logbsize); return -EINVAL; } if (iosizelog) { if (iosizelog > XFS_MAX_IO_LOG || iosizelog < XFS_MIN_IO_LOG) { xfs_warn(mp, "invalid log iosize: %d [not %d-%d]", iosizelog, XFS_MIN_IO_LOG, XFS_MAX_IO_LOG); return -EINVAL; } mp->m_flags |= XFS_MOUNT_DFLT_IOSIZE; mp->m_readio_log = iosizelog; mp->m_writeio_log = iosizelog; } return 0; }