/* * Flush out all the files in a filesystem. */ int ffs_flushfiles(struct mount *mp, int flags, struct proc *p) { struct ufsmount *ump; int error; ump = VFSTOUFS(mp); if (mp->mnt_flag & MNT_QUOTA) { int i; if ((error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) != 0) return (error); for (i = 0; i < MAXQUOTAS; i++) { if (ump->um_quotas[i] == NULLVP) continue; quotaoff(p, mp, i); } /* * Here we fall through to vflush again to ensure * that we have gotten rid of all the system vnodes. */ } /* * Flush all the files. */ if ((error = vflush(mp, NULL, flags)) != 0) return (error); /* * Flush filesystem metadata. */ vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, p); error = VOP_FSYNC(ump->um_devvp, p->p_ucred, MNT_WAIT, p); VOP_UNLOCK(ump->um_devvp, 0, p); return (error); }
static int off_f( int argc, char **argv) { int c, flags = 0, qflags = 0, type = 0; while ((c = getopt(argc, argv, "gpuv")) != EOF) { switch (c) { case 'g': type |= XFS_GROUP_QUOTA; qflags |= XFS_QUOTA_GDQ_ACCT | XFS_QUOTA_GDQ_ENFD; break; case 'p': type |= XFS_PROJ_QUOTA; qflags |= XFS_QUOTA_PDQ_ACCT | XFS_QUOTA_PDQ_ENFD; break; case 'u': type |= XFS_USER_QUOTA; qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD; break; case 'v': flags |= VERBOSE_FLAG; break; default: return command_usage(&off_cmd); } } if (argc != optind) return command_usage(&off_cmd); if (!type) { type |= XFS_USER_QUOTA; qflags |= XFS_QUOTA_UDQ_ACCT | XFS_QUOTA_UDQ_ENFD; } if (fs_path->fs_flags & FS_MOUNT_POINT) quotaoff(fs_path->fs_dir, type, qflags, flags); return 0; }
/* * Q_QUOTAON - set up a quota file for a particular file system. */ int quotaon(struct lwp *l, struct mount *mp, int type, void *fname) { struct ufsmount *ump = VFSTOUFS(mp); struct vnode *vp, **vpp, *mvp; struct dquot *dq; int error; struct nameidata nd; /* XXX XXX XXX */ if (mp->mnt_wapbl != NULL) { printf("%s: quotas cannot yet be used with -o log\n", mp->mnt_stat.f_mntonname); return (EOPNOTSUPP); } vpp = &ump->um_quotas[type]; NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, fname); if ((error = vn_open(&nd, FREAD|FWRITE, 0)) != 0) return (error); vp = nd.ni_vp; VOP_UNLOCK(vp, 0); if (vp->v_type != VREG) { (void) vn_close(vp, FREAD|FWRITE, l->l_cred); return (EACCES); } if (*vpp != vp) quotaoff(l, mp, type); mutex_enter(&dqlock); while ((ump->um_qflags[type] & (QTF_CLOSING | QTF_OPENING)) != 0) cv_wait(&dqcv, &dqlock); ump->um_qflags[type] |= QTF_OPENING; mutex_exit(&dqlock); mp->mnt_flag |= MNT_QUOTA; vp->v_vflag |= VV_SYSTEM; /* XXXSMP */ *vpp = vp; /* * Save the credential of the process that turned on quotas. * Set up the time limits for this quota. */ kauth_cred_hold(l->l_cred); ump->um_cred[type] = l->l_cred; ump->um_btime[type] = MAX_DQ_TIME; ump->um_itime[type] = MAX_IQ_TIME; if (dqget(NULLVP, 0, ump, type, &dq) == 0) { if (dq->dq_btime > 0) ump->um_btime[type] = dq->dq_btime; if (dq->dq_itime > 0) ump->um_itime[type] = dq->dq_itime; dqrele(NULLVP, dq); } /* Allocate a marker vnode. */ if ((mvp = vnalloc(mp)) == NULL) { error = ENOMEM; goto out; } /* * Search vnodes associated with this mount point, * adding references to quota file being opened. * NB: only need to add dquot's for inodes being modified. */ mutex_enter(&mntvnode_lock); again: for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) { vmark(mvp, vp); mutex_enter(&vp->v_interlock); if (VTOI(vp) == NULL || vp->v_mount != mp || vismarker(vp) || vp->v_type == VNON || vp->v_writecount == 0 || (vp->v_iflag & (VI_XLOCK | VI_CLEAN)) != 0) { mutex_exit(&vp->v_interlock); continue; } mutex_exit(&mntvnode_lock); if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK)) { mutex_enter(&mntvnode_lock); (void)vunmark(mvp); goto again; } if ((error = getinoquota(VTOI(vp))) != 0) { vput(vp); mutex_enter(&mntvnode_lock); (void)vunmark(mvp); break; } vput(vp); mutex_enter(&mntvnode_lock); } mutex_exit(&mntvnode_lock); vnfree(mvp); out: mutex_enter(&dqlock); ump->um_qflags[type] &= ~QTF_OPENING; cv_broadcast(&dqcv); mutex_exit(&dqlock); if (error) quotaoff(l, mp, type); return (error); }
/* * Do operations associated with quotas */ int ufs_quotactl(struct mount *mp, int cmds, uid_t uid, void *arg) { struct lwp *l = curlwp; #ifndef QUOTA (void) mp; (void) cmds; (void) uid; (void) arg; (void) l; return (EOPNOTSUPP); #else int cmd, type, error; if (uid == -1) uid = kauth_cred_getuid(l->l_cred); cmd = cmds >> SUBCMDSHIFT; switch (cmd) { case Q_SYNC: break; case Q_GETQUOTA: if (uid == kauth_cred_getuid(l->l_cred)) break; /* fall through */ default: if ((error = kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL)) != 0) return (error); } type = cmds & SUBCMDMASK; if ((u_int)type >= MAXQUOTAS) return (EINVAL); error = vfs_busy(mp, NULL); if (error != 0) return (error); mutex_enter(&mp->mnt_updating); switch (cmd) { case Q_QUOTAON: error = quotaon(l, mp, type, arg); break; case Q_QUOTAOFF: error = quotaoff(l, mp, type); break; case Q_SETQUOTA: error = setquota(mp, uid, type, arg); break; case Q_SETUSE: error = setuse(mp, uid, type, arg); break; case Q_GETQUOTA: error = getquota(mp, uid, type, arg); break; case Q_SYNC: error = qsync(mp); break; default: error = EINVAL; } mutex_exit(&mp->mnt_updating); vfs_unbusy(mp, false, NULL); return (error); #endif }