3 * Generic IO operations on quotafiles
5 * Jan Kara <jack@suse.cz> - sponsored by SuSE CR
15 #include <sys/types.h>
18 #include <asm/byteorder.h>
28 #include "dqblk_rpc.h"
29 #include "dqblk_xfs.h"
31 /* Header in all newer quotafiles */
32 struct disk_dqheader {
34 u_int32_t dqh_version;
35 } __attribute__ ((packed));
38 * Detect quota format and initialize quota IO
40 struct quota_handle *init_io(struct mount_entry *mnt, int type, int fmt, int flags)
44 struct quota_handle *h = smalloc(sizeof(struct quota_handle));
47 if (!me_hasquota(mnt, type))
49 if (stat(mnt->me_devname, &h->qh_stat) < 0)
50 memset(&h->qh_stat, 0, sizeof(struct stat));
52 if (flags & IOI_READONLY)
53 h->qh_io_flags |= IOFL_RO;
54 if (flags & IOI_NFS_MIXED_PATHS)
55 h->qh_io_flags |= IOFL_NFS_MIXED_PATHS;
57 sstrncpy(h->qh_quotadev, mnt->me_devname, sizeof(h->qh_quotadev));
58 sstrncpy(h->qh_fstype, mnt->me_type, MAX_FSTYPE_LEN);
59 sstrncpy(h->qh_dir, mnt->me_dir, PATH_MAX);
60 if (nfs_fstype(mnt->me_type)) { /* NFS filesystem? */
61 if (fmt != -1 && fmt != QF_RPC) { /* User wanted some other format? */
62 errstr(_("Only RPC quota format is allowed on NFS filesystem.\n"));
68 h->qh_ops = "afile_ops_rpc;
69 memset(&h->qh_info, 0, sizeof(h->qh_info));
70 h->qh_ops->init_io(h);
73 errstr(_("RPC quota format not compiled.\n"));
76 } else if (fmt == QF_RPC) {
77 errstr(_("RPC quota format specified for non-NFS filesystem.\n"));
81 if (!strcmp(mnt->me_type, MNTTYPE_XFS) || /* XFS filesystem? */
82 !strcmp(mnt->me_type, MNTTYPE_GFS2)) { /* XFS filesystem? */
83 if (fmt != -1 && fmt != QF_XFS) { /* User wanted some other format? */
84 errstr(_("Only XFS quota format is allowed on XFS filesystem.\n"));
89 h->qh_ops = "afile_ops_xfs;
90 memset(&h->qh_info, 0, sizeof(h->qh_info));
91 h->qh_ops->init_io(h);
94 else if (fmt == QF_XFS) {
95 errstr(_("XFS quota allowed only on XFS filesystem.\n"));
98 if (kern_qfmt_supp(fmt)) { /* Quota compiled and desired format available? */
99 /* Quota turned on? */
100 kernfmt = kern_quota_on(mnt, type, fmt);
102 h->qh_io_flags |= IOFL_QUOTAON;
103 fmt = kernfmt; /* Default is kernel used format */
107 if (meta_qf_fstype(mnt->me_type) || mnt->me_qfmt[type] == QF_META) {
108 if (!QIO_ENABLED(h)) {
109 errstr(_("Quota not supported by the filesystem.\n"));
117 nameflag = (!QIO_ENABLED(h) || flags & IOI_INITSCAN) ? NF_FORMAT : 0;
119 /* Let's try any VFSv0 quota format... */
120 if (get_qf_name(mnt, type, QF_VFSV0, nameflag, &qfname) >= 0)
122 /* And then VFSv1 quota format... */
123 else if (get_qf_name(mnt, type, QF_VFSV1, nameflag, &qfname) >= 0)
125 /* And then old quota format... */
126 else if (get_qf_name(mnt, type, QF_VFSOLD, nameflag, &qfname) >= 0)
128 else { /* Don't know... */
129 errstr(_("Cannot find any quota file to work on.\n"));
133 if (get_qf_name(mnt, type, fmt, nameflag, &qfname) < 0) {
134 errstr(_("Quota file not found or has wrong format.\n"));
138 if (!QIO_ENABLED(h) || flags & IOI_INITSCAN) { /* Need to open file? */
139 if (QIO_ENABLED(h)) { /* Kernel uses same file? */
141 (kernel_iface == IFACE_GENERIC) ? Q_SYNC : Q_6_5_SYNC;
142 if (quotactl(QCMD(cmd, h->qh_type), h->qh_quotadev,
144 die(4, _("Cannot sync quotas on device %s: %s\n"),
145 h->qh_quotadev, strerror(errno));
148 /* We still need to open file for operations like 'repquota' */
149 if ((fd = open(qfname, QIO_RO(h) ? O_RDONLY : O_RDWR)) < 0) {
150 errstr(_("Cannot open quotafile %s: %s\n"),
151 qfname, strerror(errno));
154 flock(fd, QIO_RO(h) ? LOCK_SH : LOCK_EX);
162 free(qfname); /* We don't need it anymore */
166 if (fmt == QF_VFSOLD)
167 h->qh_ops = "afile_ops_1;
168 else if (is_tree_qfmt(fmt))
169 h->qh_ops = "afile_ops_2;
170 else if (fmt == QF_META)
171 h->qh_ops = "afile_ops_meta;
172 memset(&h->qh_info, 0, sizeof(h->qh_info));
174 if (h->qh_ops->init_io && h->qh_ops->init_io(h) < 0) {
175 errstr(_("Cannot initialize quota on %s: %s\n"), h->qh_quotadev, strerror(errno));
190 * Create new quotafile of specified format on given filesystem
192 struct quota_handle *new_io(struct mount_entry *mnt, int type, int fmt)
196 struct quota_handle *h;
197 char namebuf[PATH_MAX];
201 else if (fmt == QF_RPC || fmt == QF_XFS) {
202 errstr(_("Creation of %s quota format is not supported.\n"),
207 * For filesystems which never have quotas in quota files or for
208 * filesystems which have quotas already stored in system files we
209 * refuse to create anything.
211 if (meta_qf_fstype(mnt->me_type) || mnt->me_qfmt[type] == QF_META) {
212 errstr(_("Quota on %s is stored in system files and must"
213 " be manipulated by fs tools.\n"), mnt->me_dir);
216 if (get_qf_name(mnt, type, fmt, 0, &qfname) < 0)
218 sstrncpy(namebuf, qfname, PATH_MAX);
219 sstrncat(namebuf, ".new", PATH_MAX);
221 if ((fd = open(namebuf, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR)) < 0) {
222 errstr(_("Cannot create new quotafile %s: %s\n"),
223 namebuf, strerror(errno));
226 h = smalloc(sizeof(struct quota_handle));
230 sstrncpy(h->qh_quotadev, mnt->me_devname, sizeof(h->qh_quotadev));
231 sstrncpy(h->qh_fstype, mnt->me_type, MAX_FSTYPE_LEN);
232 sstrncpy(h->qh_dir, mnt->me_dir, PATH_MAX);
235 memset(&h->qh_info, 0, sizeof(h->qh_info));
236 if (fmt == QF_VFSOLD)
237 h->qh_ops = "afile_ops_1;
239 h->qh_ops = "afile_ops_2;
242 if (h->qh_ops->new_io && h->qh_ops->new_io(h) < 0) {
254 * Close quotafile and release handle
256 int end_io(struct quota_handle *h)
258 if (h->qh_io_flags & IOFL_INFODIRTY) {
259 if (h->qh_ops->write_info && h->qh_ops->write_info(h) < 0)
261 h->qh_io_flags &= ~IOFL_INFODIRTY;
263 if (h->qh_ops->end_io && h->qh_ops->end_io(h) < 0)
265 if (h->qh_fd != -1) {
266 flock(h->qh_fd, LOCK_UN);
274 * Create empty quota structure
276 struct dquot *get_empty_dquot(void)
278 struct dquot *dquot = smalloc(sizeof(struct dquot));
280 memset(dquot, 0, sizeof(*dquot));
286 * Check whether values in current dquot can be stored on disk
288 int check_dquot_range(struct dquot *dquot)
290 struct util_dqinfo *info = &dquot->dq_h->qh_info;
292 if (dquot->dq_dqb.dqb_bhardlimit > info->dqi_max_b_limit ||
293 dquot->dq_dqb.dqb_bsoftlimit > info->dqi_max_b_limit ||
294 dquot->dq_dqb.dqb_ihardlimit > info->dqi_max_i_limit ||
295 dquot->dq_dqb.dqb_isoftlimit > info->dqi_max_i_limit) {
296 errstr(_("Trying to set quota limits out of range "
297 "supported by quota format on %s.\n"), dquot->dq_h->qh_quotadev);
300 if (dquot->dq_dqb.dqb_curinodes > info->dqi_max_i_usage ||
301 dquot->dq_dqb.dqb_curspace > info->dqi_max_b_usage) {
302 errstr(_("Trying to set quota usage out of range "
303 "supported by quota format on %s.\n"), dquot->dq_h->qh_quotadev);