STATIC int xfs_ioc_bulkstat( xfs_mount_t *mp, unsigned int cmd, void __user *arg) { xfs_fsop_bulkreq_t bulkreq; int count; /* # of records returned */ xfs_ino_t inlast; /* last inode number */ int done; int error; /* done = 1 if there are more stats to get and if bulkstat */ /* should be called again (unused here, but used in dmapi) */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (XFS_FORCED_SHUTDOWN(mp)) return -XFS_ERROR(EIO); if (copy_from_user(&bulkreq, arg, sizeof(xfs_fsop_bulkreq_t))) return -XFS_ERROR(EFAULT); if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) return -XFS_ERROR(EFAULT); if ((count = bulkreq.icount) <= 0) return -XFS_ERROR(EINVAL); if (bulkreq.ubuffer == NULL) return -XFS_ERROR(EINVAL); if (cmd == XFS_IOC_FSINUMBERS) error = xfs_inumbers(mp, &inlast, &count, bulkreq.ubuffer, xfs_inumbers_fmt); else if (cmd == XFS_IOC_FSBULKSTAT_SINGLE) error = xfs_bulkstat_single(mp, &inlast, bulkreq.ubuffer, &done); else /* XFS_IOC_FSBULKSTAT */ error = xfs_bulkstat(mp, &inlast, &count, (bulkstat_one_pf)xfs_bulkstat_one, NULL, sizeof(xfs_bstat_t), bulkreq.ubuffer, BULKSTAT_FG_QUICK, &done); if (error) return -error; if (bulkreq.ocount != NULL) { if (copy_to_user(bulkreq.lastip, &inlast, sizeof(xfs_ino_t))) return -XFS_ERROR(EFAULT); if (copy_to_user(bulkreq.ocount, &count, sizeof(count))) return -XFS_ERROR(EFAULT); } return 0; }
/* PRIVATE, debugging */ int xfs_qm_internalqcheck( xfs_mount_t *mp) { xfs_ino_t lastino; int done, count; int i; xfs_dqtest_t *d, *e; xfs_dqhash_t *h1; int error; lastino = 0; qmtest_hashmask = 32; count = 5; done = 0; qmtest_nfails = 0; if (! XFS_IS_QUOTA_ON(mp)) return XFS_ERROR(ESRCH); xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); XFS_bflush(mp->m_ddev_targp); xfs_log_force(mp, (xfs_lsn_t)0, XFS_LOG_FORCE | XFS_LOG_SYNC); XFS_bflush(mp->m_ddev_targp); mutex_lock(&qcheck_lock); /* There should be absolutely no quota activity while this is going on. */ qmtest_udqtab = kmem_zalloc(qmtest_hashmask * sizeof(xfs_dqhash_t), KM_SLEEP); qmtest_gdqtab = kmem_zalloc(qmtest_hashmask * sizeof(xfs_dqhash_t), KM_SLEEP); do { /* * Iterate thru all the inodes in the file system, * adjusting the corresponding dquot counters */ if ((error = xfs_bulkstat(mp, &lastino, &count, xfs_qm_internalqcheck_adjust, NULL, 0, NULL, BULKSTAT_FG_IGET, &done))) { break; } } while (! done); if (error) { cmn_err(CE_DEBUG, "Bulkstat returned error 0x%x", error); } cmn_err(CE_DEBUG, "Checking results against system dquots"); for (i = 0; i < qmtest_hashmask; i++) { h1 = &qmtest_udqtab[i]; for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) { xfs_dqtest_cmp(d); e = (xfs_dqtest_t *) d->HL_NEXT; kmem_free(d, sizeof(xfs_dqtest_t)); d = e; } h1 = &qmtest_gdqtab[i]; for (d = (xfs_dqtest_t *) h1->qh_next; d != NULL; ) { xfs_dqtest_cmp(d); e = (xfs_dqtest_t *) d->HL_NEXT; kmem_free(d, sizeof(xfs_dqtest_t)); d = e; } } if (qmtest_nfails) { cmn_err(CE_DEBUG, "******** quotacheck failed ********"); cmn_err(CE_DEBUG, "failures = %d", qmtest_nfails); } else { cmn_err(CE_DEBUG, "******** quotacheck successful! ********"); } kmem_free(qmtest_udqtab, qmtest_hashmask * sizeof(xfs_dqhash_t)); kmem_free(qmtest_gdqtab, qmtest_hashmask * sizeof(xfs_dqhash_t)); mutex_unlock(&qcheck_lock); return (qmtest_nfails); }
/* * Walk thru all the filesystem inodes and construct a consistent view * of the disk quota world. If the quotacheck fails, disable quotas. */ int xfs_qm_quotacheck( xfs_mount_t *mp) { int done, count, error, error2; xfs_ino_t lastino; size_t structsz; xfs_inode_t *uip, *gip; uint flags; LIST_HEAD (buffer_list); count = INT_MAX; structsz = 1; lastino = 0; flags = 0; ASSERT(mp->m_quotainfo->qi_uquotaip || mp->m_quotainfo->qi_gquotaip); ASSERT(XFS_IS_QUOTA_RUNNING(mp)); xfs_notice(mp, "Quotacheck needed: Please wait."); /* * First we go thru all the dquots on disk, USR and GRP/PRJ, and reset * their counters to zero. We need a clean slate. * We don't log our changes till later. */ uip = mp->m_quotainfo->qi_uquotaip; if (uip) { error = xfs_qm_dqiterate(mp, uip, XFS_QMOPT_UQUOTA, &buffer_list); if (error) goto error_return; flags |= XFS_UQUOTA_CHKD; } gip = mp->m_quotainfo->qi_gquotaip; if (gip) { error = xfs_qm_dqiterate(mp, gip, XFS_IS_GQUOTA_ON(mp) ? XFS_QMOPT_GQUOTA : XFS_QMOPT_PQUOTA, &buffer_list); if (error) goto error_return; flags |= XFS_OQUOTA_CHKD; } do { /* * Iterate thru all the inodes in the file system, * adjusting the corresponding dquot counters in core. */ error = xfs_bulkstat(mp, &lastino, &count, xfs_qm_dqusage_adjust, structsz, NULL, &done); if (error) break; } while (!done); /* * We've made all the changes that we need to make incore. Flush them * down to disk buffers if everything was updated successfully. */ if (XFS_IS_UQUOTA_ON(mp)) { error = xfs_qm_dquot_walk(mp, XFS_DQ_USER, xfs_qm_flush_one, &buffer_list); } if (XFS_IS_GQUOTA_ON(mp)) { error2 = xfs_qm_dquot_walk(mp, XFS_DQ_GROUP, xfs_qm_flush_one, &buffer_list); if (!error) error = error2; } if (XFS_IS_PQUOTA_ON(mp)) { error2 = xfs_qm_dquot_walk(mp, XFS_DQ_PROJ, xfs_qm_flush_one, &buffer_list); if (!error) error = error2; } error2 = xfs_buf_delwri_submit(&buffer_list); if (!error) error = error2; /* * We can get this error if we couldn't do a dquot allocation inside * xfs_qm_dqusage_adjust (via bulkstat). We don't care about the * dirty dquots that might be cached, we just want to get rid of them * and turn quotaoff. The dquots won't be attached to any of the inodes * at this point (because we intentionally didn't in dqget_noattach). */ if (error) { xfs_qm_dqpurge_all(mp, XFS_QMOPT_QUOTALL); goto error_return; } /* * If one type of quotas is off, then it will lose its * quotachecked status, since we won't be doing accounting for * that type anymore. */ mp->m_qflags &= ~XFS_ALL_QUOTA_CHKD; mp->m_qflags |= flags; error_return: while (!list_empty(&buffer_list)) { struct xfs_buf *bp = list_first_entry(&buffer_list, struct xfs_buf, b_list); list_del_init(&bp->b_list); xfs_buf_relse(bp); } if (error) { xfs_warn(mp, "Quotacheck: Unsuccessful (Error %d): Disabling quotas.", error); /* * We must turn off quotas. */ ASSERT(mp->m_quotainfo != NULL); xfs_qm_destroy_quotainfo(mp); if (xfs_mount_reset_sbqflags(mp)) { xfs_warn(mp, "Quotacheck: Failed to reset quota flags."); } } else xfs_notice(mp, "Quotacheck: Done."); return (error); }
/* copied from xfs_ioctl.c */ STATIC int xfs_ioc_bulkstat_compat( xfs_mount_t *mp, unsigned int cmd, void __user *arg) { compat_xfs_fsop_bulkreq_t __user *p32 = (void __user *)arg; u32 addr; xfs_fsop_bulkreq_t bulkreq; int count; /* # of records returned */ xfs_ino_t inlast; /* last inode number */ int done; int error; /* done = 1 if there are more stats to get and if bulkstat */ /* should be called again (unused here, but used in dmapi) */ if (!capable(CAP_SYS_ADMIN)) return -EPERM; if (XFS_FORCED_SHUTDOWN(mp)) return -XFS_ERROR(EIO); if (get_user(addr, &p32->lastip)) return -EFAULT; bulkreq.lastip = compat_ptr(addr); if (get_user(bulkreq.icount, &p32->icount) || get_user(addr, &p32->ubuffer)) return -EFAULT; bulkreq.ubuffer = compat_ptr(addr); if (get_user(addr, &p32->ocount)) return -EFAULT; bulkreq.ocount = compat_ptr(addr); if (copy_from_user(&inlast, bulkreq.lastip, sizeof(__s64))) return -XFS_ERROR(EFAULT); if ((count = bulkreq.icount) <= 0) return -XFS_ERROR(EINVAL); if (cmd == XFS_IOC_FSINUMBERS) error = xfs_inumbers(mp, &inlast, &count, bulkreq.ubuffer, xfs_inumbers_fmt_compat); else { /* declare a var to get a warning in case the type changes */ bulkstat_one_fmt_pf formatter = xfs_bulkstat_one_fmt_compat; error = xfs_bulkstat(mp, &inlast, &count, xfs_bulkstat_one, formatter, sizeof(compat_xfs_bstat_t), bulkreq.ubuffer, BULKSTAT_FG_QUICK, &done); } if (error) return -error; if (bulkreq.ocount != NULL) { if (copy_to_user(bulkreq.lastip, &inlast, sizeof(xfs_ino_t))) return -XFS_ERROR(EFAULT); if (copy_to_user(bulkreq.ocount, &count, sizeof(count))) return -XFS_ERROR(EFAULT); } return 0; }
/* * fsrfs -- reorganize a file system */ static int fsrfs(char *mntdir, xfs_ino_t startino, int targetrange) { int fsfd, fd; int count = 0; int ret; size_t buflenout; xfs_bstat_t buf[GRABSZ]; char fname[64]; char *tname; jdm_fshandle_t *fshandlep; xfs_ino_t lastino = startino; fsrprintf("%s startino=%llu\n", mntdir, (unsigned long long)startino); fshandlep = jdm_getfshandle( mntdir ); if ( ! fshandlep ) { fsrprintf("unable to get handle: %s: %s\n", mntdir, strerror( errno )); return -1; } if ((fsfd = open(mntdir, O_RDONLY)) < 0) { fsrprintf("unable to open: %s: %s\n", mntdir, strerror( errno )); return -1; } if (xfs_getgeom(fsfd, &fsgeom) < 0 ) { fsrprintf("Skipping %s: could not get XFS geom\n", mntdir); return -1; } tmp_init(mntdir); sync(); while (! xfs_bulkstat(fsfd, &lastino, GRABSZ, &buf[0], &buflenout)) { xfs_bstat_t *p; xfs_bstat_t *endp; if (buflenout == 0 ) goto out0; /* Each loop through, defrag targetrange percent of the files */ count = (buflenout * targetrange) / 100; qsort((char *)buf, buflenout, sizeof(struct xfs_bstat), cmp); for ( p = buf, endp = (buf + buflenout); p < endp ; p++ ) { /* Do some obvious checks now */ if (((p->bs_mode & S_IFMT) != S_IFREG) || (p->bs_extents < 2)) continue; if((fd = jdm_open(fshandlep, p, O_RDWR)) < 0) { /* This probably means the file was * removed while in progress of handling * it. Just quietly ignore this file. */ if (dflag) fsrprintf("could not open: ino %llu\n", p->bs_ino); continue; } /* Don't know the pathname, so make up something */ sprintf(fname, "ino=%llu", (unsigned long long)p->bs_ino); /* Get a tmp file name */ tname = tmp_next(mntdir); ret = fsrfile_common(fname, tname, mntdir, fd, p); leftoffino = p->bs_ino; close(fd); if (ret == 0) { if (--count <= 0) break; } } if (endtime && endtime < time(0)) { tmp_close(mntdir); close(fsfd); fsrall_cleanup(1); exit(1); } } out0: tmp_close(mntdir); close(fsfd); return 0; }