Esempio n. 1
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.
 */
STATIC int
xfs_parseargs(
	struct xfs_mount	*mp,
	char			*options,
	char			**mtpt)
{
	struct super_block	*sb = mp->m_super;
	char			*this_char, *value, *eov;
	int			dsunit = 0;
	int			dswidth = 0;
	int			iosize = 0;
	int			dmapi_implies_ikeep = 1;
	__uint8_t		iosizelog = 0;

	/*
	 * 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;
	mp->m_flags |= XFS_MOUNT_SMALL_INUMS;

	/*
	 * 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) {
				cmn_err(CE_WARN,
					"XFS: %s option requires an argument",
					this_char);
				return EINVAL;
			}
			mp->m_logbufs = simple_strtoul(value, &eov, 10);
		} else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) {
			if (!value || !*value) {
				cmn_err(CE_WARN,
					"XFS: %s option requires an argument",
					this_char);
				return EINVAL;
			}
			mp->m_logbsize = suffix_strtoul(value, &eov, 10);
		} else if (!strcmp(this_char, MNTOPT_LOGDEV)) {
			if (!value || !*value) {
				cmn_err(CE_WARN,
					"XFS: %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)) {
			if (!value || !*value) {
				cmn_err(CE_WARN,
					"XFS: %s option requires an argument",
					this_char);
				return EINVAL;
			}
			*mtpt = kstrndup(value, MAXNAMELEN, GFP_KERNEL);
			if (!*mtpt)
				return ENOMEM;
		} else if (!strcmp(this_char, MNTOPT_RTDEV)) {
			if (!value || !*value) {
				cmn_err(CE_WARN,
					"XFS: %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) {
				cmn_err(CE_WARN,
					"XFS: %s option requires an argument",
					this_char);
				return EINVAL;
			}
			iosize = simple_strtoul(value, &eov, 10);
			iosizelog = ffs(iosize) - 1;
		} else if (!strcmp(this_char, MNTOPT_ALLOCSIZE)) {
			if (!value || !*value) {
				cmn_err(CE_WARN,
					"XFS: %s option requires an argument",
					this_char);
				return EINVAL;
			}
			iosize = suffix_strtoul(value, &eov, 10);
			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_OSYNCISOSYNC)) {
			mp->m_flags |= XFS_MOUNT_OSYNCISOSYNC;
		} 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) {
				cmn_err(CE_WARN,
					"XFS: %s option requires an argument",
					this_char);
				return EINVAL;
			}
			dsunit = simple_strtoul(value, &eov, 10);
		} else if (!strcmp(this_char, MNTOPT_SWIDTH)) {
			if (!value || !*value) {
				cmn_err(CE_WARN,
					"XFS: %s option requires an argument",
					this_char);
				return EINVAL;
			}
			dswidth = simple_strtoul(value, &eov, 10);
		} else if (!strcmp(this_char, MNTOPT_64BITINODE)) {
			mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS;
#if !XFS_BIG_INUMS
			cmn_err(CE_WARN,
				"XFS: %s option not allowed on this system",
				this_char);
			return EINVAL;
#endif
		} 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)) {
			dmapi_implies_ikeep = 0;
			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_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE |
					  XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE |
					  XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE |
					  XFS_UQUOTA_ENFD | XFS_OQUOTA_ENFD);
		} 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_OQUOTA_ENFD);
		} else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) {
			mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE);
			mp->m_qflags &= ~XFS_OQUOTA_ENFD;
		} else if (!strcmp(this_char, MNTOPT_GQUOTA) ||
			   !strcmp(this_char, MNTOPT_GRPQUOTA)) {
			mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE |
					 XFS_OQUOTA_ENFD);
		} else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
			mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
			mp->m_qflags &= ~XFS_OQUOTA_ENFD;
		} else if (!strcmp(this_char, MNTOPT_DMAPI)) {
			mp->m_flags |= XFS_MOUNT_DMAPI;
		} else if (!strcmp(this_char, MNTOPT_XDSM)) {
			mp->m_flags |= XFS_MOUNT_DMAPI;
		} else if (!strcmp(this_char, MNTOPT_DMI)) {
			mp->m_flags |= XFS_MOUNT_DMAPI;
		} else if (!strcmp(this_char, "ihashsize")) {
			cmn_err(CE_WARN,
	"XFS: ihashsize no longer used, option is deprecated.");
		} else if (!strcmp(this_char, "osyncisdsync")) {
			/* no-op, this is now the default */
			cmn_err(CE_WARN,
	"XFS: osyncisdsync is now the default, option is deprecated.");
		} else if (!strcmp(this_char, "irixsgid")) {
			cmn_err(CE_WARN,
	"XFS: irixsgid is now a sysctl(2) variable, option is deprecated.");
		} else {
			cmn_err(CE_WARN,
				"XFS: 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)) {
		cmn_err(CE_WARN, "XFS: no-recovery mounts must be read-only.");
		return EINVAL;
	}

	if ((mp->m_flags & XFS_MOUNT_NOALIGN) && (dsunit || dswidth)) {
		cmn_err(CE_WARN,
	"XFS: sunit and swidth options incompatible with the noalign option");
		return EINVAL;
	}

#ifndef CONFIG_XFS_QUOTA
	if (XFS_IS_QUOTA_RUNNING(mp)) {
		cmn_err(CE_WARN,
			"XFS: quota support not available in this kernel.");
		return EINVAL;
	}
#endif

	if ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
	    (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE))) {
		cmn_err(CE_WARN,
			"XFS: cannot mount with both project and group quota");
		return EINVAL;
	}

	if ((mp->m_flags & XFS_MOUNT_DMAPI) && (!*mtpt || *mtpt[0] == '\0')) {
		printk("XFS: %s option needs the mount point option as well\n",
			MNTOPT_DMAPI);
		return EINVAL;
	}

	if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
		cmn_err(CE_WARN,
			"XFS: sunit and swidth must be specified together");
		return EINVAL;
	}

	if (dsunit && (dswidth % dsunit != 0)) {
		cmn_err(CE_WARN,
	"XFS: stripe width (%d) must be a multiple of the stripe unit (%d)",
			dswidth, dsunit);
		return EINVAL;
	}

	/*
	 * Applications using DMI filesystems often expect the
	 * inode generation number to be monotonically increasing.
	 * If we delete inode chunks we break this assumption, so
	 * keep unused inode chunks on disk for DMI filesystems
	 * until we come up with a better solution.
	 * Note that if "ikeep" or "noikeep" mount options are
	 * supplied, then they are honored.
	 */
	if ((mp->m_flags & XFS_MOUNT_DMAPI) && dmapi_implies_ikeep)
		mp->m_flags |= XFS_MOUNT_IKEEP;

done:
	if (!(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.
		 */
		if (dsunit) {
			mp->m_dalign = dsunit;
			mp->m_flags |= XFS_MOUNT_RETERR;
		}

		if (dswidth)
			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)) {
		cmn_err(CE_WARN,
			"XFS: invalid logbufs value: %d [not %d-%d]",
			mp->m_logbufs, XLOG_MIN_ICLOGS, XLOG_MAX_ICLOGS);
		return XFS_ERROR(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))) {
		cmn_err(CE_WARN,
	"XFS: invalid logbufsize: %d [not 16k,32k,64k,128k or 256k]",
			mp->m_logbsize);
		return XFS_ERROR(EINVAL);
	}

	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;

	if (iosizelog) {
		if (iosizelog > XFS_MAX_IO_LOG ||
		    iosizelog < XFS_MIN_IO_LOG) {
			cmn_err(CE_WARN,
		"XFS: invalid log iosize: %d [not %d-%d]",
				iosizelog, XFS_MIN_IO_LOG,
				XFS_MAX_IO_LOG);
			return XFS_ERROR(EINVAL);
		}

		mp->m_flags |= XFS_MOUNT_DFLT_IOSIZE;
		mp->m_readio_log = iosizelog;
		mp->m_writeio_log = iosizelog;
	}

	return 0;
}
Esempio n. 2
0
STATIC int
xfs_parseargs(
    struct xfs_mount	*mp,
    char			*options,
    struct xfs_mount_args	*args,
    int			update)
{
    char			*this_char, *value, *eov;
    int			dsunit, dswidth, vol_dsunit, vol_dswidth;
    int			iosize;
    int			dmapi_implies_ikeep = 1;

    args->flags |= XFSMNT_BARRIER;
    args->flags2 |= XFSMNT2_COMPAT_IOSIZE;

    if (!options)
        goto done;

    iosize = dsunit = dswidth = vol_dsunit = vol_dswidth = 0;

    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) {
                cmn_err(CE_WARN,
                        "XFS: %s option requires an argument",
                        this_char);
                return EINVAL;
            }
            args->logbufs = simple_strtoul(value, &eov, 10);
        } else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) {
            if (!value || !*value) {
                cmn_err(CE_WARN,
                        "XFS: %s option requires an argument",
                        this_char);
                return EINVAL;
            }
            args->logbufsize = suffix_strtoul(value, &eov, 10);
        } else if (!strcmp(this_char, MNTOPT_LOGDEV)) {
            if (!value || !*value) {
                cmn_err(CE_WARN,
                        "XFS: %s option requires an argument",
                        this_char);
                return EINVAL;
            }
            strncpy(args->logname, value, MAXNAMELEN);
        } else if (!strcmp(this_char, MNTOPT_MTPT)) {
            if (!value || !*value) {
                cmn_err(CE_WARN,
                        "XFS: %s option requires an argument",
                        this_char);
                return EINVAL;
            }
            strncpy(args->mtpt, value, MAXNAMELEN);
        } else if (!strcmp(this_char, MNTOPT_RTDEV)) {
            if (!value || !*value) {
                cmn_err(CE_WARN,
                        "XFS: %s option requires an argument",
                        this_char);
                return EINVAL;
            }
            strncpy(args->rtname, value, MAXNAMELEN);
        } else if (!strcmp(this_char, MNTOPT_BIOSIZE)) {
            if (!value || !*value) {
                cmn_err(CE_WARN,
                        "XFS: %s option requires an argument",
                        this_char);
                return EINVAL;
            }
            iosize = simple_strtoul(value, &eov, 10);
            args->flags |= XFSMNT_IOSIZE;
            args->iosizelog = (uint8_t) iosize;
        } else if (!strcmp(this_char, MNTOPT_ALLOCSIZE)) {
            if (!value || !*value) {
                cmn_err(CE_WARN,
                        "XFS: %s option requires an argument",
                        this_char);
                return EINVAL;
            }
            iosize = suffix_strtoul(value, &eov, 10);
            args->flags |= XFSMNT_IOSIZE;
            args->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)) {
            args->flags |= XFSMNT_WSYNC;
        } else if (!strcmp(this_char, MNTOPT_OSYNCISOSYNC)) {
            args->flags |= XFSMNT_OSYNCISOSYNC;
        } else if (!strcmp(this_char, MNTOPT_NORECOVERY)) {
            args->flags |= XFSMNT_NORECOVERY;
        } else if (!strcmp(this_char, MNTOPT_INO64)) {
            args->flags |= XFSMNT_INO64;
#if !XFS_BIG_INUMS
            cmn_err(CE_WARN,
                    "XFS: %s option not allowed on this system",
                    this_char);
            return EINVAL;
#endif
        } else if (!strcmp(this_char, MNTOPT_NOALIGN)) {
            args->flags |= XFSMNT_NOALIGN;
        } else if (!strcmp(this_char, MNTOPT_SWALLOC)) {
            args->flags |= XFSMNT_SWALLOC;
        } else if (!strcmp(this_char, MNTOPT_SUNIT)) {
            if (!value || !*value) {
                cmn_err(CE_WARN,
                        "XFS: %s option requires an argument",
                        this_char);
                return EINVAL;
            }
            dsunit = simple_strtoul(value, &eov, 10);
        } else if (!strcmp(this_char, MNTOPT_SWIDTH)) {
            if (!value || !*value) {
                cmn_err(CE_WARN,
                        "XFS: %s option requires an argument",
                        this_char);
                return EINVAL;
            }
            dswidth = simple_strtoul(value, &eov, 10);
        } else if (!strcmp(this_char, MNTOPT_64BITINODE)) {
            args->flags &= ~XFSMNT_32BITINODES;
#if !XFS_BIG_INUMS
            cmn_err(CE_WARN,
                    "XFS: %s option not allowed on this system",
                    this_char);
            return EINVAL;
#endif
        } else if (!strcmp(this_char, MNTOPT_NOUUID)) {
            args->flags |= XFSMNT_NOUUID;
        } else if (!strcmp(this_char, MNTOPT_BARRIER)) {
            args->flags |= XFSMNT_BARRIER;
        } else if (!strcmp(this_char, MNTOPT_NOBARRIER)) {
            args->flags &= ~XFSMNT_BARRIER;
        } else if (!strcmp(this_char, MNTOPT_IKEEP)) {
            args->flags |= XFSMNT_IKEEP;
        } else if (!strcmp(this_char, MNTOPT_NOIKEEP)) {
            dmapi_implies_ikeep = 0;
            args->flags &= ~XFSMNT_IKEEP;
        } else if (!strcmp(this_char, MNTOPT_LARGEIO)) {
            args->flags2 &= ~XFSMNT2_COMPAT_IOSIZE;
        } else if (!strcmp(this_char, MNTOPT_NOLARGEIO)) {
            args->flags2 |= XFSMNT2_COMPAT_IOSIZE;
        } else if (!strcmp(this_char, MNTOPT_ATTR2)) {
            args->flags |= XFSMNT_ATTR2;
        } else if (!strcmp(this_char, MNTOPT_NOATTR2)) {
            args->flags &= ~XFSMNT_ATTR2;
        } else if (!strcmp(this_char, MNTOPT_FILESTREAM)) {
            args->flags2 |= XFSMNT2_FILESTREAMS;
        } else if (!strcmp(this_char, MNTOPT_NOQUOTA)) {
            args->flags &= ~(XFSMNT_UQUOTAENF|XFSMNT_UQUOTA);
            args->flags &= ~(XFSMNT_GQUOTAENF|XFSMNT_GQUOTA);
        } else if (!strcmp(this_char, MNTOPT_QUOTA) ||
                   !strcmp(this_char, MNTOPT_UQUOTA) ||
                   !strcmp(this_char, MNTOPT_USRQUOTA)) {
            args->flags |= XFSMNT_UQUOTA | XFSMNT_UQUOTAENF;
        } else if (!strcmp(this_char, MNTOPT_QUOTANOENF) ||
                   !strcmp(this_char, MNTOPT_UQUOTANOENF)) {
            args->flags |= XFSMNT_UQUOTA;
            args->flags &= ~XFSMNT_UQUOTAENF;
        } else if (!strcmp(this_char, MNTOPT_PQUOTA) ||
                   !strcmp(this_char, MNTOPT_PRJQUOTA)) {
            args->flags |= XFSMNT_PQUOTA | XFSMNT_PQUOTAENF;
        } else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) {
            args->flags |= XFSMNT_PQUOTA;
            args->flags &= ~XFSMNT_PQUOTAENF;
        } else if (!strcmp(this_char, MNTOPT_GQUOTA) ||
                   !strcmp(this_char, MNTOPT_GRPQUOTA)) {
            args->flags |= XFSMNT_GQUOTA | XFSMNT_GQUOTAENF;
        } else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
            args->flags |= XFSMNT_GQUOTA;
            args->flags &= ~XFSMNT_GQUOTAENF;
        } else if (!strcmp(this_char, MNTOPT_DMAPI)) {
            args->flags |= XFSMNT_DMAPI;
        } else if (!strcmp(this_char, MNTOPT_XDSM)) {
            args->flags |= XFSMNT_DMAPI;
        } else if (!strcmp(this_char, MNTOPT_DMI)) {
            args->flags |= XFSMNT_DMAPI;
        } else if (!strcmp(this_char, "ihashsize")) {
            cmn_err(CE_WARN,
                    "XFS: ihashsize no longer used, option is deprecated.");
        } else if (!strcmp(this_char, "osyncisdsync")) {
            /* no-op, this is now the default */
            cmn_err(CE_WARN,
                    "XFS: osyncisdsync is now the default, option is deprecated.");
        } else if (!strcmp(this_char, "irixsgid")) {
            cmn_err(CE_WARN,
                    "XFS: irixsgid is now a sysctl(2) variable, option is deprecated.");
        } else {
            cmn_err(CE_WARN,
                    "XFS: unknown mount option [%s].", this_char);
            return EINVAL;
        }
    }

    if (args->flags & XFSMNT_NORECOVERY) {
        if ((mp->m_flags & XFS_MOUNT_RDONLY) == 0) {
            cmn_err(CE_WARN,
                    "XFS: no-recovery mounts must be read-only.");
            return EINVAL;
        }
    }

    if ((args->flags & XFSMNT_NOALIGN) && (dsunit || dswidth)) {
        cmn_err(CE_WARN,
                "XFS: sunit and swidth options incompatible with the noalign option");
        return EINVAL;
    }

    if ((args->flags & XFSMNT_GQUOTA) && (args->flags & XFSMNT_PQUOTA)) {
        cmn_err(CE_WARN,
                "XFS: cannot mount with both project and group quota");
        return EINVAL;
    }

    if ((args->flags & XFSMNT_DMAPI) && *args->mtpt == '\0') {
        printk("XFS: %s option needs the mount point option as well\n",
               MNTOPT_DMAPI);
        return EINVAL;
    }

    if ((dsunit && !dswidth) || (!dsunit && dswidth)) {
        cmn_err(CE_WARN,
                "XFS: sunit and swidth must be specified together");
        return EINVAL;
    }

    if (dsunit && (dswidth % dsunit != 0)) {
        cmn_err(CE_WARN,
                "XFS: stripe width (%d) must be a multiple of the stripe unit (%d)",
                dswidth, dsunit);
        return EINVAL;
    }

    /*
     * Applications using DMI filesystems often expect the
     * inode generation number to be monotonically increasing.
     * If we delete inode chunks we break this assumption, so
     * keep unused inode chunks on disk for DMI filesystems
     * until we come up with a better solution.
     * Note that if "ikeep" or "noikeep" mount options are
     * supplied, then they are honored.
     */
    if ((args->flags & XFSMNT_DMAPI) && dmapi_implies_ikeep)
        args->flags |= XFSMNT_IKEEP;

    if ((args->flags & XFSMNT_NOALIGN) != XFSMNT_NOALIGN) {
        if (dsunit) {
            args->sunit = dsunit;
            args->flags |= XFSMNT_RETERR;
        } else {
            args->sunit = vol_dsunit;
        }
        dswidth ? (args->swidth = dswidth) :
        (args->swidth = vol_dswidth);
    } else {
        args->sunit = args->swidth = 0;
    }

done:
    if (args->flags & XFSMNT_32BITINODES)
        mp->m_flags |= XFS_MOUNT_SMALL_INUMS;
    if (args->flags2)
        args->flags |= XFSMNT_FLAGS2;
    return 0;
}
Esempio n. 3
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.
 */
STATIC int
xfs_parseargs(
	struct xfs_mount	*mp,
	char			*options)
{
	struct super_block	*sb = mp->m_super;
	char			*this_char, *value, *eov;
	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;
	mp->m_flags |= XFS_MOUNT_SMALL_INUMS;
	mp->m_flags |= XFS_MOUNT_DELAYLOG;

	/*
	 * 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;
			}
			mp->m_logbufs = simple_strtoul(value, &eov, 10);
		} else if (!strcmp(this_char, MNTOPT_LOGBSIZE)) {
			if (!value || !*value) {
				xfs_warn(mp, "%s option requires an argument",
					this_char);
				return EINVAL;
			}
			mp->m_logbsize = suffix_strtoul(value, &eov, 10);
		} 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;
			}
			iosize = simple_strtoul(value, &eov, 10);
			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;
			}
			iosize = suffix_strtoul(value, &eov, 10);
			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;
			}
			dsunit = simple_strtoul(value, &eov, 10);
		} else if (!strcmp(this_char, MNTOPT_SWIDTH)) {
			if (!value || !*value) {
				xfs_warn(mp, "%s option requires an argument",
					this_char);
				return EINVAL;
			}
			dswidth = simple_strtoul(value, &eov, 10);
		} else if (!strcmp(this_char, MNTOPT_64BITINODE)) {
			mp->m_flags &= ~XFS_MOUNT_SMALL_INUMS;
#if !XFS_BIG_INUMS
			xfs_warn(mp, "%s option not allowed on this system",
				this_char);
			return EINVAL;
#endif
		} 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_UQUOTA_ACCT | XFS_UQUOTA_ACTIVE |
					  XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE |
					  XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE |
					  XFS_UQUOTA_ENFD | XFS_OQUOTA_ENFD);
		} 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_OQUOTA_ENFD);
		} else if (!strcmp(this_char, MNTOPT_PQUOTANOENF)) {
			mp->m_qflags |= (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE);
			mp->m_qflags &= ~XFS_OQUOTA_ENFD;
		} else if (!strcmp(this_char, MNTOPT_GQUOTA) ||
			   !strcmp(this_char, MNTOPT_GRPQUOTA)) {
			mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE |
					 XFS_OQUOTA_ENFD);
		} else if (!strcmp(this_char, MNTOPT_GQUOTANOENF)) {
			mp->m_qflags |= (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE);
			mp->m_qflags &= ~XFS_OQUOTA_ENFD;
		} else if (!strcmp(this_char, MNTOPT_DELAYLOG)) {
			xfs_warn(mp,
	"delaylog is the default now, option is deprecated.");
		} else if (!strcmp(this_char, MNTOPT_NODELAYLOG)) {
			xfs_warn(mp,
	"nodelaylog support has been removed, option is deprecated.");
		} 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 if (!strcmp(this_char, "ihashsize")) {
			xfs_warn(mp,
	"ihashsize no longer used, option is deprecated.");
		} else if (!strcmp(this_char, "osyncisdsync")) {
			xfs_warn(mp,
	"osyncisdsync has no effect, option is deprecated.");
		} else if (!strcmp(this_char, "osyncisosync")) {
			xfs_warn(mp,
	"osyncisosync has no effect, option is deprecated.");
		} else if (!strcmp(this_char, "irixsgid")) {
			xfs_warn(mp,
	"irixsgid is now a sysctl(2) variable, option is deprecated.");
		} 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;
	}

	if ((mp->m_flags & XFS_MOUNT_DISCARD) &&
	    !(mp->m_flags & XFS_MOUNT_DELAYLOG)) {
		xfs_warn(mp,
	"the discard option is incompatible with the nodelaylog 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 ((mp->m_qflags & (XFS_GQUOTA_ACCT | XFS_GQUOTA_ACTIVE)) &&
	    (mp->m_qflags & (XFS_PQUOTA_ACCT | XFS_PQUOTA_ACTIVE))) {
		xfs_warn(mp, "cannot mount with both project and group quota");
		return EINVAL;
	}

	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 (!(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.
		 */
		if (dsunit) {
			mp->m_dalign = dsunit;
			mp->m_flags |= XFS_MOUNT_RETERR;
		}

		if (dswidth)
			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 XFS_ERROR(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 XFS_ERROR(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 XFS_ERROR(EINVAL);
		}

		mp->m_flags |= XFS_MOUNT_DFLT_IOSIZE;
		mp->m_readio_log = iosizelog;
		mp->m_writeio_log = iosizelog;
	}

	return 0;
}