|
|
| version 1.402, 2007/10/15 03:59:33 | version 1.403, 2007/11/05 05:10:46 |
|---|---|
| Line 50 | Line 50 |
| #include "xfs_vnodeops.h" | #include "xfs_vnodeops.h" |
| #include "xfs_vfsops.h" | #include "xfs_vfsops.h" |
| #include "xfs_version.h" | #include "xfs_version.h" |
| #include "xfs_log_priv.h" | |
| #include <linux/namei.h> | #include <linux/namei.h> |
| #include <linux/init.h> | #include <linux/init.h> |
| Line 88 xfs_args_allocate( | Line 89 xfs_args_allocate( |
| return args; | return args; |
| } | } |
| #define MNTOPT_LOGBUFS "logbufs" /* number of XFS log buffers */ | |
| #define MNTOPT_LOGBSIZE "logbsize" /* size of XFS log buffers */ | |
| #define MNTOPT_LOGDEV "logdev" /* log device */ | |
| #define MNTOPT_RTDEV "rtdev" /* realtime I/O device */ | |
| #define MNTOPT_BIOSIZE "biosize" /* log2 of preferred buffered io size */ | |
| #define MNTOPT_WSYNC "wsync" /* safe-mode nfs compatible mount */ | |
| #define MNTOPT_INO64 "ino64" /* force inodes into 64-bit range */ | |
| #define MNTOPT_NOALIGN "noalign" /* turn off stripe alignment */ | |
| #define MNTOPT_SWALLOC "swalloc" /* turn on stripe width allocation */ | |
| #define MNTOPT_SUNIT "sunit" /* data volume stripe unit */ | |
| #define MNTOPT_SWIDTH "swidth" /* data volume stripe width */ | |
| #define MNTOPT_NOUUID "nouuid" /* ignore filesystem UUID */ | |
| #define MNTOPT_MTPT "mtpt" /* filesystem mount point */ | |
| #define MNTOPT_GRPID "grpid" /* group-ID from parent directory */ | |
| #define MNTOPT_NOGRPID "nogrpid" /* group-ID from current process */ | |
| #define MNTOPT_BSDGROUPS "bsdgroups" /* group-ID from parent directory */ | |
| #define MNTOPT_SYSVGROUPS "sysvgroups" /* group-ID from current process */ | |
| #define MNTOPT_ALLOCSIZE "allocsize" /* preferred allocation size */ | |
| #define MNTOPT_NORECOVERY "norecovery" /* don't run XFS recovery */ | |
| #define MNTOPT_BARRIER "barrier" /* use writer barriers for log write and | |
| * unwritten extent conversion */ | |
| #define MNTOPT_NOBARRIER "nobarrier" /* .. disable */ | |
| #define MNTOPT_OSYNCISOSYNC "osyncisosync" /* o_sync is REALLY o_sync */ | |
| #define MNTOPT_64BITINODE "inode64" /* inodes can be allocated anywhere */ | |
| #define MNTOPT_IKEEP "ikeep" /* do not free empty inode clusters */ | |
| #define MNTOPT_NOIKEEP "noikeep" /* free empty inode clusters */ | |
| #define MNTOPT_LARGEIO "largeio" /* report large I/O sizes in stat() */ | |
| #define MNTOPT_NOLARGEIO "nolargeio" /* do not report large I/O sizes | |
| * in stat(). */ | |
| #define MNTOPT_ATTR2 "attr2" /* do use attr2 attribute format */ | |
| #define MNTOPT_NOATTR2 "noattr2" /* do not use attr2 attribute format */ | |
| #define MNTOPT_FILESTREAM "filestreams" /* use filestreams allocator */ | |
| #define MNTOPT_QUOTA "quota" /* disk quotas (user) */ | |
| #define MNTOPT_NOQUOTA "noquota" /* no quotas */ | |
| #define MNTOPT_USRQUOTA "usrquota" /* user quota enabled */ | |
| #define MNTOPT_GRPQUOTA "grpquota" /* group quota enabled */ | |
| #define MNTOPT_PRJQUOTA "prjquota" /* project quota enabled */ | |
| #define MNTOPT_UQUOTA "uquota" /* user quota (IRIX variant) */ | |
| #define MNTOPT_GQUOTA "gquota" /* group quota (IRIX variant) */ | |
| #define MNTOPT_PQUOTA "pquota" /* project quota (IRIX variant) */ | |
| #define MNTOPT_UQUOTANOENF "uqnoenforce"/* user quota limit enforcement */ | |
| #define MNTOPT_GQUOTANOENF "gqnoenforce"/* group quota limit enforcement */ | |
| #define MNTOPT_PQUOTANOENF "pqnoenforce"/* project quota limit enforcement */ | |
| #define MNTOPT_QUOTANOENF "qnoenforce" /* same as uqnoenforce */ | |
| #define MNTOPT_DMAPI "dmapi" /* DMI enabled (DMAPI / XDSM) */ | |
| #define MNTOPT_XDSM "xdsm" /* DMI enabled (DMAPI / XDSM) */ | |
| #define MNTOPT_DMI "dmi" /* DMI enabled (DMAPI / XDSM) */ | |
| STATIC unsigned long | |
| suffix_strtoul(char *s, char **endp, unsigned int base) | |
| { | |
| int last, shift_left_factor = 0; | |
| char *value = s; | |
| last = strlen(value) - 1; | |
| if (value[last] == 'K' || value[last] == 'k') { | |
| shift_left_factor = 10; | |
| value[last] = '\0'; | |
| } | |
| if (value[last] == 'M' || value[last] == 'm') { | |
| shift_left_factor = 20; | |
| value[last] = '\0'; | |
| } | |
| if (value[last] == 'G' || value[last] == 'g') { | |
| shift_left_factor = 30; | |
| value[last] = '\0'; | |
| } | |
| return simple_strtoul((const char *)s, endp, base) << shift_left_factor; | |
| } | |
| 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 ikeep = 0; | |
| 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)) { | |
| ikeep = 1; | |
| args->flags &= ~XFSMNT_IDELETE; | |
| } else if (!strcmp(this_char, MNTOPT_NOIKEEP)) { | |
| args->flags |= XFSMNT_IDELETE; | |
| } 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) && !ikeep) | |
| args->flags |= XFSMNT_IDELETE; | |
| 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; | |
| } | |
| struct proc_xfs_info { | |
| int flag; | |
| char *str; | |
| }; | |
| STATIC int | |
| xfs_showargs( | |
| struct xfs_mount *mp, | |
| struct seq_file *m) | |
| { | |
| static struct proc_xfs_info xfs_info_set[] = { | |
| /* the few simple ones we can get from the mount struct */ | |
| { XFS_MOUNT_WSYNC, "," MNTOPT_WSYNC }, | |
| { XFS_MOUNT_INO64, "," MNTOPT_INO64 }, | |
| { XFS_MOUNT_NOALIGN, "," MNTOPT_NOALIGN }, | |
| { XFS_MOUNT_SWALLOC, "," MNTOPT_SWALLOC }, | |
| { XFS_MOUNT_NOUUID, "," MNTOPT_NOUUID }, | |
| { XFS_MOUNT_NORECOVERY, "," MNTOPT_NORECOVERY }, | |
| { XFS_MOUNT_OSYNCISOSYNC, "," MNTOPT_OSYNCISOSYNC }, | |
| { XFS_MOUNT_ATTR2, "," MNTOPT_ATTR2 }, | |
| { XFS_MOUNT_FILESTREAMS, "," MNTOPT_FILESTREAM }, | |
| { XFS_MOUNT_DMAPI, "," MNTOPT_DMAPI }, | |
| { XFS_MOUNT_GRPID, "," MNTOPT_GRPID }, | |
| { 0, NULL } | |
| }; | |
| static struct proc_xfs_info xfs_info_unset[] = { | |
| /* the few simple ones we can get from the mount struct */ | |
| { XFS_MOUNT_IDELETE, "," MNTOPT_IKEEP }, | |
| { XFS_MOUNT_COMPAT_IOSIZE, "," MNTOPT_LARGEIO }, | |
| { XFS_MOUNT_BARRIER, "," MNTOPT_NOBARRIER }, | |
| { XFS_MOUNT_SMALL_INUMS, "," MNTOPT_64BITINODE }, | |
| { 0, NULL } | |
| }; | |
| struct proc_xfs_info *xfs_infop; | |
| for (xfs_infop = xfs_info_set; xfs_infop->flag; xfs_infop++) { | |
| if (mp->m_flags & xfs_infop->flag) | |
| seq_puts(m, xfs_infop->str); | |
| } | |
| for (xfs_infop = xfs_info_unset; xfs_infop->flag; xfs_infop++) { | |
| if (!(mp->m_flags & xfs_infop->flag)) | |
| seq_puts(m, xfs_infop->str); | |
| } | |
| if (mp->m_flags & XFS_MOUNT_DFLT_IOSIZE) | |
| seq_printf(m, "," MNTOPT_ALLOCSIZE "=%dk", | |
| (int)(1 << mp->m_writeio_log) >> 10); | |
| if (mp->m_logbufs > 0) | |
| seq_printf(m, "," MNTOPT_LOGBUFS "=%d", mp->m_logbufs); | |
| if (mp->m_logbsize > 0) | |
| seq_printf(m, "," MNTOPT_LOGBSIZE "=%dk", mp->m_logbsize >> 10); | |
| if (mp->m_logname) | |
| seq_printf(m, "," MNTOPT_LOGDEV "=%s", mp->m_logname); | |
| if (mp->m_rtname) | |
| seq_printf(m, "," MNTOPT_RTDEV "=%s", mp->m_rtname); | |
| if (mp->m_dalign > 0) | |
| seq_printf(m, "," MNTOPT_SUNIT "=%d", | |
| (int)XFS_FSB_TO_BB(mp, mp->m_dalign)); | |
| if (mp->m_swidth > 0) | |
| seq_printf(m, "," MNTOPT_SWIDTH "=%d", | |
| (int)XFS_FSB_TO_BB(mp, mp->m_swidth)); | |
| if (mp->m_qflags & (XFS_UQUOTA_ACCT|XFS_UQUOTA_ENFD)) | |
| seq_puts(m, "," MNTOPT_USRQUOTA); | |
| else if (mp->m_qflags & XFS_UQUOTA_ACCT) | |
| seq_puts(m, "," MNTOPT_UQUOTANOENF); | |
| if (mp->m_qflags & (XFS_PQUOTA_ACCT|XFS_OQUOTA_ENFD)) | |
| seq_puts(m, "," MNTOPT_PRJQUOTA); | |
| else if (mp->m_qflags & XFS_PQUOTA_ACCT) | |
| seq_puts(m, "," MNTOPT_PQUOTANOENF); | |
| if (mp->m_qflags & (XFS_GQUOTA_ACCT|XFS_OQUOTA_ENFD)) | |
| seq_puts(m, "," MNTOPT_GRPQUOTA); | |
| else if (mp->m_qflags & XFS_GQUOTA_ACCT) | |
| seq_puts(m, "," MNTOPT_GQUOTANOENF); | |
| if (!(mp->m_qflags & XFS_ALL_QUOTA_ACCT)) | |
| seq_puts(m, "," MNTOPT_NOQUOTA); | |
| return 0; | |
| } | |
| __uint64_t | __uint64_t |
| xfs_max_file_offset( | xfs_max_file_offset( |
| unsigned int blockshift) | unsigned int blockshift) |