4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 021110-1307, USA
24 * Copyright (c) 2012, 2014, Intel Corporation.
25 * Use is subject to license terms.
27 * Lustre administrative quota format.
28 * from linux/fs/quota_v2.c
31 #include "osd_internal.h"
32 #include "osd_quota_fmt.h"
34 typedef char *dqbuf_t;
38 struct lustre_disk_dqblk_v2 r1;
39 } emptydquot = { .r1 = { 0 } };
41 static inline dqbuf_t getdqbuf(void)
43 dqbuf_t buf = kmalloc(LUSTRE_DQBLKSIZE, GFP_NOFS);
45 CWARN("Not enough memory for quota buffers.\n");
49 static inline void freedqbuf(dqbuf_t buf)
55 * Read the \a blk into \a buf.
57 static ssize_t quota_read_blk(const struct lu_env *env,
58 struct osd_object *obj,
59 int type, uint blk, dqbuf_t buf)
62 struct super_block *sb = obj->oo_inode->i_sb;
66 memset(buf, 0, LUSTRE_DQBLKSIZE);
68 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 7, 53, 0)
69 /* type is set as -1 when reading old admin quota file */
70 if (type != USRQUOTA && type != GRPQUOTA) {
71 struct lu_buf lu_buffer;
74 lu_buffer.lb_buf = buf;
75 lu_buffer.lb_len = LUSTRE_DQBLKSIZE;
76 pos = blk << LUSTRE_DQBLKSIZE_BITS;
78 ret = dt_record_read(env, &obj->oo_dt, &lu_buffer, &pos);
81 ret = LUSTRE_DQBLKSIZE;
82 else if (ret == -EBADR || ret == -EFAULT)
87 #warning "remove old quota compatibility code"
90 ret = sb->s_op->quota_read(sb, type, buf, LUSTRE_DQBLKSIZE,
91 blk << LUSTRE_DQBLKSIZE_BITS);
93 /* Reading past EOF just returns a block of zeros */
101 * Find entry in block by given \a dqid in the leaf block \a blk
103 * \retval +ve, the offset of the entry in file
104 * \retval 0, entry not found
105 * \retval -ve, unexpected failure
107 static loff_t find_block_dqentry(const struct lu_env *env,
108 struct osd_object *obj, int type,
109 qid_t dqid, uint blk,
110 struct osd_it_quota *it)
112 dqbuf_t buf = getdqbuf();
115 struct lustre_disk_dqblk_v2 *ddquot;
120 ddquot = (struct lustre_disk_dqblk_v2 *)GETENTRIES(buf);
121 dqblk_sz = sizeof(struct lustre_disk_dqblk_v2);
124 ret = quota_read_blk(env, obj, type, blk, buf);
126 CERROR("Can't read quota tree block %u.\n", blk);
131 for (i = 0; i < LUSTRE_DQSTRINBLK &&
132 le32_to_cpu(ddquot[i].dqb_id) != dqid; i++)
134 } else { /* ID 0 as a bit more complicated searching... */
135 for (i = 0; i < LUSTRE_DQSTRINBLK; i++)
136 if (!le32_to_cpu(ddquot[i].dqb_id) &&
137 memcmp((char *)&emptydquot, (char *)&ddquot[i],
141 if (i == LUSTRE_DQSTRINBLK) {
142 CDEBUG(D_QUOTA, "Quota for id %u not found.\n", dqid);
146 ret = (blk << LUSTRE_DQBLKSIZE_BITS) +
147 sizeof(struct lustre_disk_dqdbheader) + i * dqblk_sz;
150 it->oiq_blk[LUSTRE_DQTREEDEPTH] = blk;
151 it->oiq_offset = ret;
153 it->oiq_index[LUSTRE_DQTREEDEPTH] = i;
164 * Find entry for given \a dqid in the tree block \a blk
166 * \retval +ve, the offset of the entry in file
167 * \retval 0, entry not found
168 * \retval -ve, unexpected failure
170 loff_t find_tree_dqentry(const struct lu_env *env,
171 struct osd_object *obj, int type,
172 qid_t dqid, uint blk, int depth,
173 struct osd_it_quota *it)
175 dqbuf_t buf = getdqbuf();
177 u32 *ref = (u32 *) buf;
183 ret = quota_read_blk(env, obj, type, blk, buf);
185 CERROR("Can't read quota tree block %u.\n", blk);
189 blk = le32_to_cpu(ref[GETIDINDEX(dqid, depth)]);
190 if (!blk) /* No reference? */
193 if (depth < LUSTRE_DQTREEDEPTH - 1)
194 ret = find_tree_dqentry(env, obj, type, dqid, blk,
197 ret = find_block_dqentry(env, obj, type, dqid, blk, it);
200 it->oiq_blk[depth + 1] = blk;
201 it->oiq_index[depth] = GETIDINDEX(dqid, depth);
210 * Search from \a index within the leaf block \a blk, and fill the \a it with
211 * the first valid entry.
213 * \retval +ve, no valid entry found
214 * \retval 0, entry found
215 * \retval -ve, unexpected failure
217 int walk_block_dqentry(const struct lu_env *env, struct osd_object *obj,
218 int type, uint blk, uint index,
219 struct osd_it_quota *it)
223 struct lustre_disk_dqdbheader *dqhead;
225 struct lustre_disk_dqblk_v2 *ddquot;
226 struct osd_quota_leaf *leaf;
229 /* check if the leaf block has been processed before */
230 list_for_each_entry(leaf, &it->oiq_list, oql_link) {
231 if (leaf->oql_blk == blk)
236 dqhead = (struct lustre_disk_dqdbheader *)buf;
237 dqblk_sz = sizeof(struct lustre_disk_dqblk_v2);
240 ret = quota_read_blk(env, obj, type, blk, buf);
242 CERROR("Can't read quota tree block %u.\n", blk);
247 if (!le16_to_cpu(dqhead->dqdh_entries))
250 ddquot = (struct lustre_disk_dqblk_v2 *)GETENTRIES(buf);
251 LASSERT(index < LUSTRE_DQSTRINBLK);
252 for (i = index; i < LUSTRE_DQSTRINBLK; i++) {
253 /* skip empty entry */
254 if (!memcmp((char *)&emptydquot,
255 (char *)&ddquot[i], dqblk_sz))
258 it->oiq_blk[LUSTRE_DQTREEDEPTH] = blk;
259 it->oiq_id = le32_to_cpu(ddquot[i].dqb_id);
260 it->oiq_offset = (blk << LUSTRE_DQBLKSIZE_BITS) +
261 sizeof(struct lustre_disk_dqdbheader) +
263 it->oiq_index[LUSTRE_DQTREEDEPTH] = i;
274 * Search from \a index within the tree block \a blk, and fill the \a it
275 * with the first valid entry.
277 * \retval +ve, no valid entry found
278 * \retval 0, entry found
279 * \retval -ve, unexpected failure
281 int walk_tree_dqentry(const struct lu_env *env, struct osd_object *obj,
282 int type, uint blk, int depth, uint index,
283 struct osd_it_quota *it)
285 dqbuf_t buf = getdqbuf();
287 u32 *ref = (u32 *) buf;
293 ret = quota_read_blk(env, obj, type, blk, buf);
295 CERROR("Can't read quota tree block %u.\n", blk);
300 for (; index <= 0xff && ret > 0; index++) {
301 blk = le32_to_cpu(ref[index]);
302 if (!blk) /* No reference */
305 if (depth < LUSTRE_DQTREEDEPTH - 1)
306 ret = walk_tree_dqentry(env, obj, type, blk,
309 ret = walk_block_dqentry(env, obj, type, blk, 0, it);
312 if (ret == 0) { /* Entry found */
313 it->oiq_blk[depth + 1] = blk;
314 it->oiq_index[depth] = index;