Blame view
fs/gfs2/quota.c
38 KB
b3b94faa5 [GFS2] The core o... |
1 2 |
/* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
0d0868bde [GFS2] Get rid of... |
3 |
* Copyright (C) 2004-2007 Red Hat, Inc. All rights reserved. |
b3b94faa5 [GFS2] The core o... |
4 5 6 |
* * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions |
e9fc2aa09 [GFS2] Update cop... |
7 |
* of the GNU General Public License version 2. |
b3b94faa5 [GFS2] The core o... |
8 9 10 11 12 13 14 15 16 17 |
*/ /* * Quota change tags are associated with each transaction that allocates or * deallocates space. Those changes are accumulated locally to each node (in a * per-node file) and then are periodically synced to the quota file. This * avoids the bottleneck of constantly touching the quota file, but introduces * fuzziness in the current usage value of IDs that are being used on different * nodes in the cluster simultaneously. So, it is possible for a user on * multiple nodes to overrun their quota, but that overrun is controlable. |
1e72c0f7c GFS2: Clean up gf... |
18 |
* Since quota tags are part of transactions, there is no need for a quota check |
b3b94faa5 [GFS2] The core o... |
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
* program to be run on node crashes or anything like that. * * There are couple of knobs that let the administrator manage the quota * fuzziness. "quota_quantum" sets the maximum time a quota change can be * sitting on one node before being synced to the quota file. (The default is * 60 seconds.) Another knob, "quota_scale" controls how quickly the frequency * of quota file syncs increases as the user moves closer to their limit. The * more frequent the syncs, the more accurate the quota enforcement, but that * means that there is more contention between the nodes for the quota file. * The default value is one. This sets the maximum theoretical quota overrun * (with infinite node with infinite bandwidth) to twice the user's limit. (In * practice, the maximum overrun you see should be much less.) A "quota_scale" * number greater than one makes quota syncs more frequent and reduces the * maximum overrun. Numbers less than one (but greater than zero) make quota * syncs less frequent. * * GFS quotas also use per-ID Lock Value Blocks (LVBs) to cache the contents of * the quota file, so it is not being constantly read. */ #include <linux/sched.h> #include <linux/slab.h> |
1495f230f vmscan: change sh... |
41 |
#include <linux/mm.h> |
b3b94faa5 [GFS2] The core o... |
42 43 44 |
#include <linux/spinlock.h> #include <linux/completion.h> #include <linux/buffer_head.h> |
b3b94faa5 [GFS2] The core o... |
45 |
#include <linux/sort.h> |
18ec7d5c3 [GFS2] Make journ... |
46 |
#include <linux/fs.h> |
2e565bb69 [GFS2] Mark metad... |
47 |
#include <linux/bio.h> |
5c676f6d3 [GFS2] Macros rem... |
48 |
#include <linux/gfs2_ondisk.h> |
37b2c8377 GFS2: Clean up & ... |
49 50 |
#include <linux/kthread.h> #include <linux/freezer.h> |
2ec465052 GFS2: Use dquot_s... |
51 |
#include <linux/quota.h> |
1d371b5e1 GFS2: Add get_xst... |
52 |
#include <linux/dqblk_xfs.h> |
b3b94faa5 [GFS2] The core o... |
53 54 |
#include "gfs2.h" |
5c676f6d3 [GFS2] Macros rem... |
55 |
#include "incore.h" |
b3b94faa5 [GFS2] The core o... |
56 57 58 |
#include "bmap.h" #include "glock.h" #include "glops.h" |
b3b94faa5 [GFS2] The core o... |
59 60 61 62 63 64 |
#include "log.h" #include "meta_io.h" #include "quota.h" #include "rgrp.h" #include "super.h" #include "trans.h" |
18ec7d5c3 [GFS2] Make journ... |
65 |
#include "inode.h" |
5c676f6d3 [GFS2] Macros rem... |
66 |
#include "util.h" |
b3b94faa5 [GFS2] The core o... |
67 68 69 |
#define QUOTA_USER 1 #define QUOTA_GROUP 0 |
bb8d8a6f5 [GFS2] Fix sign p... |
70 71 72 73 74 |
struct gfs2_quota_change_host { u64 qc_change; u32 qc_flags; /* GFS2_QCF_... */ u32 qc_id; }; |
0a7ab79c5 GFS2: change gfs2... |
75 76 |
static LIST_HEAD(qd_lru_list); static atomic_t qd_lru_count = ATOMIC_INIT(0); |
1328df725 GFS2: Use DEFINE_... |
77 |
static DEFINE_SPINLOCK(qd_lru_lock); |
0a7ab79c5 GFS2: change gfs2... |
78 |
|
1495f230f vmscan: change sh... |
79 |
int gfs2_shrink_qd_memory(struct shrinker *shrink, struct shrink_control *sc) |
0a7ab79c5 GFS2: change gfs2... |
80 81 82 |
{ struct gfs2_quota_data *qd; struct gfs2_sbd *sdp; |
1495f230f vmscan: change sh... |
83 |
int nr_to_scan = sc->nr_to_scan; |
0a7ab79c5 GFS2: change gfs2... |
84 |
|
1495f230f vmscan: change sh... |
85 |
if (nr_to_scan == 0) |
0a7ab79c5 GFS2: change gfs2... |
86 |
goto out; |
1495f230f vmscan: change sh... |
87 |
if (!(sc->gfp_mask & __GFP_FS)) |
0a7ab79c5 GFS2: change gfs2... |
88 89 90 |
return -1; spin_lock(&qd_lru_lock); |
1495f230f vmscan: change sh... |
91 |
while (nr_to_scan && !list_empty(&qd_lru_list)) { |
0a7ab79c5 GFS2: change gfs2... |
92 93 94 95 96 97 |
qd = list_entry(qd_lru_list.next, struct gfs2_quota_data, qd_reclaim); sdp = qd->qd_gl->gl_sbd; /* Free from the filesystem-specific list */ list_del(&qd->qd_list); |
0a7ab79c5 GFS2: change gfs2... |
98 99 100 |
gfs2_assert_warn(sdp, !qd->qd_change); gfs2_assert_warn(sdp, !qd->qd_slot_count); gfs2_assert_warn(sdp, !qd->qd_bh_count); |
f057f6cdf GFS2: Merge lock_... |
101 |
gfs2_glock_put(qd->qd_gl); |
0a7ab79c5 GFS2: change gfs2... |
102 103 104 105 106 107 108 109 |
atomic_dec(&sdp->sd_quota_count); /* Delete it from the common reclaim list */ list_del_init(&qd->qd_reclaim); atomic_dec(&qd_lru_count); spin_unlock(&qd_lru_lock); kmem_cache_free(gfs2_quotad_cachep, qd); spin_lock(&qd_lru_lock); |
1495f230f vmscan: change sh... |
110 |
nr_to_scan--; |
0a7ab79c5 GFS2: change gfs2... |
111 112 113 114 115 116 |
} spin_unlock(&qd_lru_lock); out: return (atomic_read(&qd_lru_count) * sysctl_vfs_cache_pressure) / 100; } |
cd915493f [GFS2] Change all... |
117 |
static u64 qd2offset(struct gfs2_quota_data *qd) |
b3b94faa5 [GFS2] The core o... |
118 |
{ |
cd915493f [GFS2] Change all... |
119 |
u64 offset; |
b3b94faa5 [GFS2] The core o... |
120 |
|
cd915493f [GFS2] Change all... |
121 |
offset = 2 * (u64)qd->qd_id + !test_bit(QDF_USER, &qd->qd_flags); |
b3b94faa5 [GFS2] The core o... |
122 123 124 125 |
offset *= sizeof(struct gfs2_quota); return offset; } |
cd915493f [GFS2] Change all... |
126 |
static int qd_alloc(struct gfs2_sbd *sdp, int user, u32 id, |
b3b94faa5 [GFS2] The core o... |
127 128 129 130 |
struct gfs2_quota_data **qdp) { struct gfs2_quota_data *qd; int error; |
37b2c8377 GFS2: Clean up & ... |
131 |
qd = kmem_cache_zalloc(gfs2_quotad_cachep, GFP_NOFS); |
b3b94faa5 [GFS2] The core o... |
132 133 |
if (!qd) return -ENOMEM; |
0a7ab79c5 GFS2: change gfs2... |
134 |
atomic_set(&qd->qd_count, 1); |
b3b94faa5 [GFS2] The core o... |
135 136 137 138 |
qd->qd_id = id; if (user) set_bit(QDF_USER, &qd->qd_flags); qd->qd_slot = -1; |
0a7ab79c5 GFS2: change gfs2... |
139 |
INIT_LIST_HEAD(&qd->qd_reclaim); |
b3b94faa5 [GFS2] The core o... |
140 |
|
cd915493f [GFS2] Change all... |
141 |
error = gfs2_glock_get(sdp, 2 * (u64)id + !user, |
b3b94faa5 [GFS2] The core o... |
142 143 144 |
&gfs2_quota_glops, CREATE, &qd->qd_gl); if (error) goto fail; |
b3b94faa5 [GFS2] The core o... |
145 146 147 |
*qdp = qd; return 0; |
a91ea69ff [GFS2] Align all ... |
148 |
fail: |
37b2c8377 GFS2: Clean up & ... |
149 |
kmem_cache_free(gfs2_quotad_cachep, qd); |
b3b94faa5 [GFS2] The core o... |
150 151 |
return error; } |
6a6ada81e GFS2: Remove cons... |
152 |
static int qd_get(struct gfs2_sbd *sdp, int user, u32 id, |
b3b94faa5 [GFS2] The core o... |
153 154 155 156 157 158 159 160 161 |
struct gfs2_quota_data **qdp) { struct gfs2_quota_data *qd = NULL, *new_qd = NULL; int error, found; *qdp = NULL; for (;;) { found = 0; |
0a7ab79c5 GFS2: change gfs2... |
162 |
spin_lock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
163 164 165 |
list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) { if (qd->qd_id == id && !test_bit(QDF_USER, &qd->qd_flags) == !user) { |
0a7ab79c5 GFS2: change gfs2... |
166 167 168 169 170 171 172 |
if (!atomic_read(&qd->qd_count) && !list_empty(&qd->qd_reclaim)) { /* Remove it from reclaim list */ list_del_init(&qd->qd_reclaim); atomic_dec(&qd_lru_count); } atomic_inc(&qd->qd_count); |
b3b94faa5 [GFS2] The core o... |
173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
found = 1; break; } } if (!found) qd = NULL; if (!qd && new_qd) { qd = new_qd; list_add(&qd->qd_list, &sdp->sd_quota_list); atomic_inc(&sdp->sd_quota_count); new_qd = NULL; } |
0a7ab79c5 GFS2: change gfs2... |
187 |
spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
188 |
|
6a6ada81e GFS2: Remove cons... |
189 |
if (qd) { |
b3b94faa5 [GFS2] The core o... |
190 |
if (new_qd) { |
f057f6cdf GFS2: Merge lock_... |
191 |
gfs2_glock_put(new_qd->qd_gl); |
37b2c8377 GFS2: Clean up & ... |
192 |
kmem_cache_free(gfs2_quotad_cachep, new_qd); |
b3b94faa5 [GFS2] The core o... |
193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
} *qdp = qd; return 0; } error = qd_alloc(sdp, user, id, &new_qd); if (error) return error; } } static void qd_hold(struct gfs2_quota_data *qd) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; |
0a7ab79c5 GFS2: change gfs2... |
207 208 |
gfs2_assert(sdp, atomic_read(&qd->qd_count)); atomic_inc(&qd->qd_count); |
b3b94faa5 [GFS2] The core o... |
209 210 211 212 |
} static void qd_put(struct gfs2_quota_data *qd) { |
0a7ab79c5 GFS2: change gfs2... |
213 214 215 216 217 218 |
if (atomic_dec_and_lock(&qd->qd_count, &qd_lru_lock)) { /* Add to the reclaim list */ list_add_tail(&qd->qd_reclaim, &qd_lru_list); atomic_inc(&qd_lru_count); spin_unlock(&qd_lru_lock); } |
b3b94faa5 [GFS2] The core o... |
219 220 221 222 223 224 225 |
} static int slot_get(struct gfs2_quota_data *qd) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; unsigned int c, o = 0, b; unsigned char byte = 0; |
22077f57d GFS2: Remove "dou... |
226 |
spin_lock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
227 228 |
if (qd->qd_slot_count++) { |
22077f57d GFS2: Remove "dou... |
229 |
spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
230 231 232 233 234 235 236 237 238 239 240 |
return 0; } for (c = 0; c < sdp->sd_quota_chunks; c++) for (o = 0; o < PAGE_SIZE; o++) { byte = sdp->sd_quota_bitmap[c][o]; if (byte != 0xFF) goto found; } goto fail; |
a91ea69ff [GFS2] Align all ... |
241 |
found: |
b3b94faa5 [GFS2] The core o... |
242 243 244 245 246 247 248 249 250 |
for (b = 0; b < 8; b++) if (!(byte & (1 << b))) break; qd->qd_slot = c * (8 * PAGE_SIZE) + o * 8 + b; if (qd->qd_slot >= sdp->sd_quota_slots) goto fail; sdp->sd_quota_bitmap[c][o] |= 1 << b; |
22077f57d GFS2: Remove "dou... |
251 |
spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
252 253 |
return 0; |
a91ea69ff [GFS2] Align all ... |
254 |
fail: |
b3b94faa5 [GFS2] The core o... |
255 |
qd->qd_slot_count--; |
22077f57d GFS2: Remove "dou... |
256 |
spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
257 258 259 260 261 262 |
return -ENOSPC; } static void slot_hold(struct gfs2_quota_data *qd) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; |
22077f57d GFS2: Remove "dou... |
263 |
spin_lock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
264 265 |
gfs2_assert(sdp, qd->qd_slot_count); qd->qd_slot_count++; |
22077f57d GFS2: Remove "dou... |
266 |
spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
267 268 269 270 271 |
} static void slot_put(struct gfs2_quota_data *qd) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; |
22077f57d GFS2: Remove "dou... |
272 |
spin_lock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
273 274 275 276 277 |
gfs2_assert(sdp, qd->qd_slot_count); if (!--qd->qd_slot_count) { gfs2_icbit_munge(sdp, sdp->sd_quota_bitmap, qd->qd_slot, 0); qd->qd_slot = -1; } |
22077f57d GFS2: Remove "dou... |
278 |
spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
279 280 281 282 283 |
} static int bh_get(struct gfs2_quota_data *qd) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; |
feaa7bba0 [GFS2] Fix unlink... |
284 |
struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode); |
b3b94faa5 [GFS2] The core o... |
285 |
unsigned int block, offset; |
b3b94faa5 [GFS2] The core o... |
286 287 |
struct buffer_head *bh; int error; |
23591256d [GFS2] Fix bmap t... |
288 |
struct buffer_head bh_map = { .b_state = 0, .b_blocknr = 0 }; |
b3b94faa5 [GFS2] The core o... |
289 |
|
f55ab26a8 [GFS2] Use mutice... |
290 |
mutex_lock(&sdp->sd_quota_mutex); |
b3b94faa5 [GFS2] The core o... |
291 292 |
if (qd->qd_bh_count++) { |
f55ab26a8 [GFS2] Use mutice... |
293 |
mutex_unlock(&sdp->sd_quota_mutex); |
b3b94faa5 [GFS2] The core o... |
294 295 296 297 |
return 0; } block = qd->qd_slot / sdp->sd_qc_per_block; |
0d0868bde [GFS2] Get rid of... |
298 |
offset = qd->qd_slot % sdp->sd_qc_per_block; |
b3b94faa5 [GFS2] The core o... |
299 |
|
23591256d [GFS2] Fix bmap t... |
300 |
bh_map.b_size = 1 << ip->i_inode.i_blkbits; |
e9e1ef2b6 [GFS2] Remove fun... |
301 |
error = gfs2_block_map(&ip->i_inode, block, &bh_map, 0); |
b3b94faa5 [GFS2] The core o... |
302 303 |
if (error) goto fail; |
7276b3b0c [GFS2] Tidy up me... |
304 |
error = gfs2_meta_read(ip->i_gl, bh_map.b_blocknr, DIO_WAIT, &bh); |
b3b94faa5 [GFS2] The core o... |
305 306 307 308 309 310 311 312 313 314 |
if (error) goto fail; error = -EIO; if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_QC)) goto fail_brelse; qd->qd_bh = bh; qd->qd_bh_qc = (struct gfs2_quota_change *) (bh->b_data + sizeof(struct gfs2_meta_header) + offset * sizeof(struct gfs2_quota_change)); |
2e95b6653 [GFS2] fix lockin... |
315 |
mutex_unlock(&sdp->sd_quota_mutex); |
b3b94faa5 [GFS2] The core o... |
316 317 |
return 0; |
a91ea69ff [GFS2] Align all ... |
318 |
fail_brelse: |
b3b94faa5 [GFS2] The core o... |
319 |
brelse(bh); |
a91ea69ff [GFS2] Align all ... |
320 |
fail: |
b3b94faa5 [GFS2] The core o... |
321 |
qd->qd_bh_count--; |
f55ab26a8 [GFS2] Use mutice... |
322 |
mutex_unlock(&sdp->sd_quota_mutex); |
b3b94faa5 [GFS2] The core o... |
323 324 325 326 327 328 |
return error; } static void bh_put(struct gfs2_quota_data *qd) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; |
f55ab26a8 [GFS2] Use mutice... |
329 |
mutex_lock(&sdp->sd_quota_mutex); |
b3b94faa5 [GFS2] The core o... |
330 331 332 333 334 335 |
gfs2_assert(sdp, qd->qd_bh_count); if (!--qd->qd_bh_count) { brelse(qd->qd_bh); qd->qd_bh = NULL; qd->qd_bh_qc = NULL; } |
f55ab26a8 [GFS2] Use mutice... |
336 |
mutex_unlock(&sdp->sd_quota_mutex); |
b3b94faa5 [GFS2] The core o... |
337 338 339 340 341 342 343 344 345 346 347 348 |
} static int qd_fish(struct gfs2_sbd *sdp, struct gfs2_quota_data **qdp) { struct gfs2_quota_data *qd = NULL; int error; int found = 0; *qdp = NULL; if (sdp->sd_vfs->s_flags & MS_RDONLY) return 0; |
0a7ab79c5 GFS2: change gfs2... |
349 |
spin_lock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
350 351 352 353 354 355 356 357 358 359 |
list_for_each_entry(qd, &sdp->sd_quota_list, qd_list) { if (test_bit(QDF_LOCKED, &qd->qd_flags) || !test_bit(QDF_CHANGE, &qd->qd_flags) || qd->qd_sync_gen >= sdp->sd_quota_sync_gen) continue; list_move_tail(&qd->qd_list, &sdp->sd_quota_list); set_bit(QDF_LOCKED, &qd->qd_flags); |
0a7ab79c5 GFS2: change gfs2... |
360 361 |
gfs2_assert_warn(sdp, atomic_read(&qd->qd_count)); atomic_inc(&qd->qd_count); |
b3b94faa5 [GFS2] The core o... |
362 363 364 365 366 367 368 369 370 371 |
qd->qd_change_sync = qd->qd_change; gfs2_assert_warn(sdp, qd->qd_slot_count); qd->qd_slot_count++; found = 1; break; } if (!found) qd = NULL; |
0a7ab79c5 GFS2: change gfs2... |
372 |
spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 |
if (qd) { gfs2_assert_warn(sdp, qd->qd_change_sync); error = bh_get(qd); if (error) { clear_bit(QDF_LOCKED, &qd->qd_flags); slot_put(qd); qd_put(qd); return error; } } *qdp = qd; return 0; } static int qd_trylock(struct gfs2_quota_data *qd) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; if (sdp->sd_vfs->s_flags & MS_RDONLY) return 0; |
0a7ab79c5 GFS2: change gfs2... |
396 |
spin_lock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
397 398 399 |
if (test_bit(QDF_LOCKED, &qd->qd_flags) || !test_bit(QDF_CHANGE, &qd->qd_flags)) { |
0a7ab79c5 GFS2: change gfs2... |
400 |
spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
401 402 403 404 405 406 |
return 0; } list_move_tail(&qd->qd_list, &sdp->sd_quota_list); set_bit(QDF_LOCKED, &qd->qd_flags); |
0a7ab79c5 GFS2: change gfs2... |
407 408 |
gfs2_assert_warn(sdp, atomic_read(&qd->qd_count)); atomic_inc(&qd->qd_count); |
b3b94faa5 [GFS2] The core o... |
409 410 411 |
qd->qd_change_sync = qd->qd_change; gfs2_assert_warn(sdp, qd->qd_slot_count); qd->qd_slot_count++; |
0a7ab79c5 GFS2: change gfs2... |
412 |
spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
413 414 415 416 417 418 419 420 421 422 423 424 425 426 |
gfs2_assert_warn(sdp, qd->qd_change_sync); if (bh_get(qd)) { clear_bit(QDF_LOCKED, &qd->qd_flags); slot_put(qd); qd_put(qd); return 0; } return 1; } static void qd_unlock(struct gfs2_quota_data *qd) { |
568f4c965 [GFS2] 80 Column ... |
427 428 |
gfs2_assert_warn(qd->qd_gl->gl_sbd, test_bit(QDF_LOCKED, &qd->qd_flags)); |
b3b94faa5 [GFS2] The core o... |
429 430 431 432 433 |
clear_bit(QDF_LOCKED, &qd->qd_flags); bh_put(qd); slot_put(qd); qd_put(qd); } |
33a82529e GFS2: Remove cons... |
434 |
static int qdsb_get(struct gfs2_sbd *sdp, int user, u32 id, |
b3b94faa5 [GFS2] The core o... |
435 436 437 |
struct gfs2_quota_data **qdp) { int error; |
6a6ada81e GFS2: Remove cons... |
438 |
error = qd_get(sdp, user, id, qdp); |
b3b94faa5 [GFS2] The core o... |
439 440 441 442 443 444 445 446 447 448 449 450 |
if (error) return error; error = slot_get(*qdp); if (error) goto fail; error = bh_get(*qdp); if (error) goto fail_slot; return 0; |
a91ea69ff [GFS2] Align all ... |
451 |
fail_slot: |
b3b94faa5 [GFS2] The core o... |
452 |
slot_put(*qdp); |
a91ea69ff [GFS2] Align all ... |
453 |
fail: |
b3b94faa5 [GFS2] The core o... |
454 455 456 457 458 459 460 461 462 463 |
qd_put(*qdp); return error; } static void qdsb_put(struct gfs2_quota_data *qd) { bh_put(qd); slot_put(qd); qd_put(qd); } |
cd915493f [GFS2] Change all... |
464 |
int gfs2_quota_hold(struct gfs2_inode *ip, u32 uid, u32 gid) |
b3b94faa5 [GFS2] The core o... |
465 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
466 |
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
564e12b11 GFS2: decouple qu... |
467 468 |
struct gfs2_qadata *qa = ip->i_qadata; struct gfs2_quota_data **qd = qa->qa_qd; |
b3b94faa5 [GFS2] The core o... |
469 |
int error; |
564e12b11 GFS2: decouple qu... |
470 |
if (gfs2_assert_warn(sdp, !qa->qa_qd_num) || |
b3b94faa5 [GFS2] The core o... |
471 472 473 474 475 |
gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags))) return -EIO; if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) return 0; |
33a82529e GFS2: Remove cons... |
476 |
error = qdsb_get(sdp, QUOTA_USER, ip->i_inode.i_uid, qd); |
b3b94faa5 [GFS2] The core o... |
477 478 |
if (error) goto out; |
564e12b11 GFS2: decouple qu... |
479 |
qa->qa_qd_num++; |
b3b94faa5 [GFS2] The core o... |
480 |
qd++; |
33a82529e GFS2: Remove cons... |
481 |
error = qdsb_get(sdp, QUOTA_GROUP, ip->i_inode.i_gid, qd); |
b3b94faa5 [GFS2] The core o... |
482 483 |
if (error) goto out; |
564e12b11 GFS2: decouple qu... |
484 |
qa->qa_qd_num++; |
b3b94faa5 [GFS2] The core o... |
485 |
qd++; |
2933f9254 [GFS2] Shrink gfs... |
486 |
if (uid != NO_QUOTA_CHANGE && uid != ip->i_inode.i_uid) { |
33a82529e GFS2: Remove cons... |
487 |
error = qdsb_get(sdp, QUOTA_USER, uid, qd); |
b3b94faa5 [GFS2] The core o... |
488 489 |
if (error) goto out; |
564e12b11 GFS2: decouple qu... |
490 |
qa->qa_qd_num++; |
b3b94faa5 [GFS2] The core o... |
491 492 |
qd++; } |
2933f9254 [GFS2] Shrink gfs... |
493 |
if (gid != NO_QUOTA_CHANGE && gid != ip->i_inode.i_gid) { |
33a82529e GFS2: Remove cons... |
494 |
error = qdsb_get(sdp, QUOTA_GROUP, gid, qd); |
b3b94faa5 [GFS2] The core o... |
495 496 |
if (error) goto out; |
564e12b11 GFS2: decouple qu... |
497 |
qa->qa_qd_num++; |
b3b94faa5 [GFS2] The core o... |
498 499 |
qd++; } |
a91ea69ff [GFS2] Align all ... |
500 |
out: |
b3b94faa5 [GFS2] The core o... |
501 502 |
if (error) gfs2_quota_unhold(ip); |
b3b94faa5 [GFS2] The core o... |
503 504 505 506 507 |
return error; } void gfs2_quota_unhold(struct gfs2_inode *ip) { |
feaa7bba0 [GFS2] Fix unlink... |
508 |
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
564e12b11 GFS2: decouple qu... |
509 |
struct gfs2_qadata *qa = ip->i_qadata; |
b3b94faa5 [GFS2] The core o... |
510 511 512 |
unsigned int x; gfs2_assert_warn(sdp, !test_bit(GIF_QD_LOCKED, &ip->i_flags)); |
564e12b11 GFS2: decouple qu... |
513 514 515 |
for (x = 0; x < qa->qa_qd_num; x++) { qdsb_put(qa->qa_qd[x]); qa->qa_qd[x] = NULL; |
b3b94faa5 [GFS2] The core o... |
516 |
} |
564e12b11 GFS2: decouple qu... |
517 |
qa->qa_qd_num = 0; |
b3b94faa5 [GFS2] The core o... |
518 519 520 521 |
} static int sort_qd(const void *a, const void *b) { |
48fac1790 [GFS2] Remove unu... |
522 523 |
const struct gfs2_quota_data *qd_a = *(const struct gfs2_quota_data **)a; const struct gfs2_quota_data *qd_b = *(const struct gfs2_quota_data **)b; |
b3b94faa5 [GFS2] The core o... |
524 525 526 527 |
if (!test_bit(QDF_USER, &qd_a->qd_flags) != !test_bit(QDF_USER, &qd_b->qd_flags)) { if (test_bit(QDF_USER, &qd_a->qd_flags)) |
48fac1790 [GFS2] Remove unu... |
528 |
return -1; |
b3b94faa5 [GFS2] The core o... |
529 |
else |
48fac1790 [GFS2] Remove unu... |
530 |
return 1; |
b3b94faa5 [GFS2] The core o... |
531 |
} |
48fac1790 [GFS2] Remove unu... |
532 533 534 535 |
if (qd_a->qd_id < qd_b->qd_id) return -1; if (qd_a->qd_id > qd_b->qd_id) return 1; |
b3b94faa5 [GFS2] The core o... |
536 |
|
48fac1790 [GFS2] Remove unu... |
537 |
return 0; |
b3b94faa5 [GFS2] The core o... |
538 |
} |
cd915493f [GFS2] Change all... |
539 |
static void do_qc(struct gfs2_quota_data *qd, s64 change) |
b3b94faa5 [GFS2] The core o... |
540 541 |
{ struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; |
feaa7bba0 [GFS2] Fix unlink... |
542 |
struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode); |
b3b94faa5 [GFS2] The core o... |
543 |
struct gfs2_quota_change *qc = qd->qd_bh_qc; |
cd915493f [GFS2] Change all... |
544 |
s64 x; |
b3b94faa5 [GFS2] The core o... |
545 |
|
f55ab26a8 [GFS2] Use mutice... |
546 |
mutex_lock(&sdp->sd_quota_mutex); |
d4e9c4c3b [GFS2] Add an add... |
547 |
gfs2_trans_add_bh(ip->i_gl, qd->qd_bh, 1); |
b3b94faa5 [GFS2] The core o... |
548 549 550 551 552 553 554 555 |
if (!test_bit(QDF_CHANGE, &qd->qd_flags)) { qc->qc_change = 0; qc->qc_flags = 0; if (test_bit(QDF_USER, &qd->qd_flags)) qc->qc_flags = cpu_to_be32(GFS2_QCF_USER); qc->qc_id = cpu_to_be32(qd->qd_id); } |
b44b84d76 [GFS2] gfs2 misc ... |
556 |
x = be64_to_cpu(qc->qc_change) + change; |
b3b94faa5 [GFS2] The core o... |
557 |
qc->qc_change = cpu_to_be64(x); |
22077f57d GFS2: Remove "dou... |
558 |
spin_lock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
559 |
qd->qd_change = x; |
22077f57d GFS2: Remove "dou... |
560 |
spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
561 562 563 564 565 566 567 568 569 570 571 572 |
if (!x) { gfs2_assert_warn(sdp, test_bit(QDF_CHANGE, &qd->qd_flags)); clear_bit(QDF_CHANGE, &qd->qd_flags); qc->qc_flags = 0; qc->qc_id = 0; slot_put(qd); qd_put(qd); } else if (!test_and_set_bit(QDF_CHANGE, &qd->qd_flags)) { qd_hold(qd); slot_hold(qd); } |
907b9bceb [GFS2/DLM] Fix tr... |
573 |
|
f55ab26a8 [GFS2] Use mutice... |
574 |
mutex_unlock(&sdp->sd_quota_mutex); |
b3b94faa5 [GFS2] The core o... |
575 |
} |
18ec7d5c3 [GFS2] Make journ... |
576 |
/** |
1e72c0f7c GFS2: Clean up gf... |
577 578 579 |
* gfs2_adjust_quota - adjust record of current block usage * @ip: The quota inode * @loc: Offset of the entry in the quota file |
e285c1003 GFS2: Add set_xqu... |
580 |
* @change: The amount of usage change to record |
1e72c0f7c GFS2: Clean up gf... |
581 |
* @qd: The quota data |
e285c1003 GFS2: Add set_xqu... |
582 |
* @fdq: The updated limits to record |
18ec7d5c3 [GFS2] Make journ... |
583 584 585 |
* * This function was mostly borrowed from gfs2_block_truncate_page which was * in turn mostly borrowed from ext3 |
1e72c0f7c GFS2: Clean up gf... |
586 587 |
* * Returns: 0 or -ve on error |
18ec7d5c3 [GFS2] Make journ... |
588 |
*/ |
1e72c0f7c GFS2: Clean up gf... |
589 |
|
18ec7d5c3 [GFS2] Make journ... |
590 |
static int gfs2_adjust_quota(struct gfs2_inode *ip, loff_t loc, |
e285c1003 GFS2: Add set_xqu... |
591 592 |
s64 change, struct gfs2_quota_data *qd, struct fs_disk_quota *fdq) |
18ec7d5c3 [GFS2] Make journ... |
593 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
594 |
struct inode *inode = &ip->i_inode; |
14870b457 GFS2: Userland ex... |
595 |
struct gfs2_sbd *sdp = GFS2_SB(inode); |
18ec7d5c3 [GFS2] Make journ... |
596 597 |
struct address_space *mapping = inode->i_mapping; unsigned long index = loc >> PAGE_CACHE_SHIFT; |
1990e9176 [GFS2] Quotas non... |
598 |
unsigned offset = loc & (PAGE_CACHE_SIZE - 1); |
18ec7d5c3 [GFS2] Make journ... |
599 |
unsigned blocksize, iblock, pos; |
ab9bbda02 GFS2: Use ->dirty... |
600 |
struct buffer_head *bh; |
18ec7d5c3 [GFS2] Make journ... |
601 |
struct page *page; |
7e619bc3e GFS2: Fix writing... |
602 603 604 |
void *kaddr, *ptr; struct gfs2_quota q, *qp; int err, nbytes; |
e285c1003 GFS2: Add set_xqu... |
605 |
u64 size; |
18ec7d5c3 [GFS2] Make journ... |
606 |
|
891a8e933 GFS2: Misc fixes |
607 608 609 610 611 |
if (gfs2_is_stuffed(ip)) { err = gfs2_unstuff_dinode(ip, NULL); if (err) return err; } |
7e619bc3e GFS2: Fix writing... |
612 613 614 615 616 617 618 619 620 621 622 623 624 625 |
memset(&q, 0, sizeof(struct gfs2_quota)); err = gfs2_internal_read(ip, NULL, (char *)&q, &loc, sizeof(q)); if (err < 0) return err; err = -EIO; qp = &q; qp->qu_value = be64_to_cpu(qp->qu_value); qp->qu_value += change; qp->qu_value = cpu_to_be64(qp->qu_value); qd->qd_qb.qb_value = qp->qu_value; if (fdq) { if (fdq->d_fieldmask & FS_DQ_BSOFT) { |
14870b457 GFS2: Userland ex... |
626 |
qp->qu_warn = cpu_to_be64(fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift); |
7e619bc3e GFS2: Fix writing... |
627 628 629 |
qd->qd_qb.qb_warn = qp->qu_warn; } if (fdq->d_fieldmask & FS_DQ_BHARD) { |
14870b457 GFS2: Userland ex... |
630 |
qp->qu_limit = cpu_to_be64(fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift); |
7e619bc3e GFS2: Fix writing... |
631 632 |
qd->qd_qb.qb_limit = qp->qu_limit; } |
802ec9b66 GFS2: Allow gfs2 ... |
633 634 635 636 |
if (fdq->d_fieldmask & FS_DQ_BCOUNT) { qp->qu_value = cpu_to_be64(fdq->d_bcount >> sdp->sd_fsb2bb_shift); qd->qd_qb.qb_value = qp->qu_value; } |
7e619bc3e GFS2: Fix writing... |
637 638 639 640 641 642 |
} /* Write the quota into the quota file on disk */ ptr = qp; nbytes = sizeof(struct gfs2_quota); get_a_page: |
18ec7d5c3 [GFS2] Make journ... |
643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 |
page = grab_cache_page(mapping, index); if (!page) return -ENOMEM; blocksize = inode->i_sb->s_blocksize; iblock = index << (PAGE_CACHE_SHIFT - inode->i_sb->s_blocksize_bits); if (!page_has_buffers(page)) create_empty_buffers(page, blocksize, 0); bh = page_buffers(page); pos = blocksize; while (offset >= pos) { bh = bh->b_this_page; iblock++; pos += blocksize; } if (!buffer_mapped(bh)) { |
e9e1ef2b6 [GFS2] Remove fun... |
662 |
gfs2_block_map(inode, iblock, bh, 1); |
18ec7d5c3 [GFS2] Make journ... |
663 |
if (!buffer_mapped(bh)) |
7e619bc3e GFS2: Fix writing... |
664 665 |
goto unlock_out; /* If it's a newly allocated disk block for quota, zero it */ |
8b4216018 GFS2: BUG in gfs2... |
666 667 |
if (buffer_new(bh)) zero_user(page, pos - blocksize, bh->b_size); |
18ec7d5c3 [GFS2] Make journ... |
668 669 670 671 672 673 |
} if (PageUptodate(page)) set_buffer_uptodate(bh); if (!buffer_uptodate(bh)) { |
20ed0535d GFS2: Fix up REQ ... |
674 |
ll_rw_block(READ | REQ_META, 1, &bh); |
18ec7d5c3 [GFS2] Make journ... |
675 676 |
wait_on_buffer(bh); if (!buffer_uptodate(bh)) |
7e619bc3e GFS2: Fix writing... |
677 |
goto unlock_out; |
18ec7d5c3 [GFS2] Make journ... |
678 679 680 681 682 |
} gfs2_trans_add_bh(ip->i_gl, bh, 0); kaddr = kmap_atomic(page, KM_USER0); |
7e619bc3e GFS2: Fix writing... |
683 684 685 |
if (offset + sizeof(struct gfs2_quota) > PAGE_CACHE_SIZE) nbytes = PAGE_CACHE_SIZE - offset; memcpy(kaddr + offset, ptr, nbytes); |
18ec7d5c3 [GFS2] Make journ... |
686 687 |
flush_dcache_page(page); kunmap_atomic(kaddr, KM_USER0); |
7e619bc3e GFS2: Fix writing... |
688 689 690 691 692 |
unlock_page(page); page_cache_release(page); /* If quota straddles page boundary, we need to update the rest of the * quota at the beginning of the next page */ |
8b4216018 GFS2: BUG in gfs2... |
693 |
if ((offset + sizeof(struct gfs2_quota)) > PAGE_CACHE_SIZE) { |
7e619bc3e GFS2: Fix writing... |
694 695 696 697 698 699 |
ptr = ptr + nbytes; nbytes = sizeof(struct gfs2_quota) - nbytes; offset = 0; index++; goto get_a_page; } |
e285c1003 GFS2: Add set_xqu... |
700 |
|
e285c1003 GFS2: Add set_xqu... |
701 |
size = loc + sizeof(struct gfs2_quota); |
a2e0f7993 GFS2: Remove i_di... |
702 |
if (size > inode->i_size) |
e285c1003 GFS2: Add set_xqu... |
703 |
i_size_write(inode, size); |
e285c1003 GFS2: Add set_xqu... |
704 |
inode->i_mtime = inode->i_atime = CURRENT_TIME; |
e285c1003 GFS2: Add set_xqu... |
705 |
mark_inode_dirty(inode); |
7e619bc3e GFS2: Fix writing... |
706 |
return err; |
ab9bbda02 GFS2: Use ->dirty... |
707 |
|
7e619bc3e GFS2: Fix writing... |
708 |
unlock_out: |
18ec7d5c3 [GFS2] Make journ... |
709 710 711 712 |
unlock_page(page); page_cache_release(page); return err; } |
b3b94faa5 [GFS2] The core o... |
713 714 715 |
static int do_sync(unsigned int num_qd, struct gfs2_quota_data **qda) { struct gfs2_sbd *sdp = (*qda)->qd_gl->gl_sbd; |
feaa7bba0 [GFS2] Fix unlink... |
716 |
struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); |
b3b94faa5 [GFS2] The core o... |
717 718 719 720 |
unsigned int data_blocks, ind_blocks; struct gfs2_holder *ghs, i_gh; unsigned int qx, x; struct gfs2_quota_data *qd; |
f42faf4fa [GFS2] Add gfs2_i... |
721 |
loff_t offset; |
20b95bf2c [GFS2] gfs2_adjus... |
722 |
unsigned int nalloc = 0, blocks; |
b3b94faa5 [GFS2] The core o... |
723 724 725 726 |
int error; gfs2_write_calc_reserv(ip, sizeof(struct gfs2_quota), &data_blocks, &ind_blocks); |
16c5f06f1 [GFS2] fix GFP_KE... |
727 |
ghs = kcalloc(num_qd, sizeof(struct gfs2_holder), GFP_NOFS); |
b3b94faa5 [GFS2] The core o... |
728 729 730 731 |
if (!ghs) return -ENOMEM; sort(qda, num_qd, sizeof(struct gfs2_quota_data *), sort_qd, NULL); |
e285c1003 GFS2: Add set_xqu... |
732 |
mutex_lock_nested(&ip->i_inode.i_mutex, I_MUTEX_QUOTA); |
b3b94faa5 [GFS2] The core o... |
733 |
for (qx = 0; qx < num_qd; qx++) { |
1e72c0f7c GFS2: Clean up gf... |
734 |
error = gfs2_glock_nq_init(qda[qx]->qd_gl, LM_ST_EXCLUSIVE, |
b3b94faa5 [GFS2] The core o... |
735 736 737 738 739 740 741 742 743 744 |
GL_NOCACHE, &ghs[qx]); if (error) goto out; } error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); if (error) goto out; for (x = 0; x < num_qd; x++) { |
b3b94faa5 [GFS2] The core o... |
745 |
offset = qd2offset(qda[x]); |
461cb419f GFS2: Simplify gf... |
746 747 |
if (gfs2_write_alloc_required(ip, offset, sizeof(struct gfs2_quota))) |
b3b94faa5 [GFS2] The core o... |
748 749 |
nalloc++; } |
20b95bf2c [GFS2] gfs2_adjus... |
750 751 752 753 754 755 |
/* * 1 blk for unstuffing inode if stuffed. We add this extra * block to the reservation unconditionally. If the inode * doesn't need unstuffing, the block will be released to the * rgrp since it won't be allocated during the transaction */ |
7e619bc3e GFS2: Fix writing... |
756 757 758 759 |
/* +3 in the end for unstuffing block, inode size update block * and another block in case quota straddles page boundary and * two blocks need to be updated instead of 1 */ blocks = num_qd * data_blocks + RES_DINODE + num_qd + 3; |
b3b94faa5 [GFS2] The core o... |
760 |
|
564e12b11 GFS2: decouple qu... |
761 762 |
error = gfs2_inplace_reserve(ip, 1 + (nalloc * (data_blocks + ind_blocks))); |
20b95bf2c [GFS2] gfs2_adjus... |
763 764 |
if (error) goto out_alloc; |
b3b94faa5 [GFS2] The core o... |
765 |
|
20b95bf2c [GFS2] gfs2_adjus... |
766 |
if (nalloc) |
54335b1fc GFS2: Cache the m... |
767 |
blocks += gfs2_rg_blocks(ip) + nalloc * ind_blocks + RES_STATFS; |
20b95bf2c [GFS2] gfs2_adjus... |
768 769 770 771 |
error = gfs2_trans_begin(sdp, blocks, 0); if (error) goto out_ipres; |
b3b94faa5 [GFS2] The core o... |
772 773 |
for (x = 0; x < num_qd; x++) { |
b3b94faa5 [GFS2] The core o... |
774 775 |
qd = qda[x]; offset = qd2offset(qd); |
e285c1003 GFS2: Add set_xqu... |
776 |
error = gfs2_adjust_quota(ip, offset, qd->qd_change_sync, qd, NULL); |
18ec7d5c3 [GFS2] Make journ... |
777 |
if (error) |
b3b94faa5 [GFS2] The core o... |
778 |
goto out_end_trans; |
b3b94faa5 [GFS2] The core o... |
779 780 |
do_qc(qd, -qd->qd_change_sync); |
662e3a551 GFS2: quota allow... |
781 |
set_bit(QDF_REFRESH, &qd->qd_flags); |
b3b94faa5 [GFS2] The core o... |
782 783 784 |
} error = 0; |
a91ea69ff [GFS2] Align all ... |
785 |
out_end_trans: |
b3b94faa5 [GFS2] The core o... |
786 |
gfs2_trans_end(sdp); |
a91ea69ff [GFS2] Align all ... |
787 |
out_ipres: |
20b95bf2c [GFS2] gfs2_adjus... |
788 |
gfs2_inplace_release(ip); |
a91ea69ff [GFS2] Align all ... |
789 |
out_alloc: |
b3b94faa5 [GFS2] The core o... |
790 |
gfs2_glock_dq_uninit(&i_gh); |
a91ea69ff [GFS2] Align all ... |
791 |
out: |
b3b94faa5 [GFS2] The core o... |
792 793 |
while (qx--) gfs2_glock_dq_uninit(&ghs[qx]); |
e285c1003 GFS2: Add set_xqu... |
794 |
mutex_unlock(&ip->i_inode.i_mutex); |
b3b94faa5 [GFS2] The core o... |
795 |
kfree(ghs); |
b09e593d7 [GFS2] Fix a ref ... |
796 |
gfs2_log_flush(ip->i_gl->gl_sbd, ip->i_gl); |
b3b94faa5 [GFS2] The core o... |
797 798 |
return error; } |
e285c1003 GFS2: Add set_xqu... |
799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 |
static int update_qd(struct gfs2_sbd *sdp, struct gfs2_quota_data *qd) { struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); struct gfs2_quota q; struct gfs2_quota_lvb *qlvb; loff_t pos; int error; memset(&q, 0, sizeof(struct gfs2_quota)); pos = qd2offset(qd); error = gfs2_internal_read(ip, NULL, (char *)&q, &pos, sizeof(q)); if (error < 0) return error; qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; qlvb->qb_magic = cpu_to_be32(GFS2_MAGIC); qlvb->__pad = 0; qlvb->qb_limit = q.qu_limit; qlvb->qb_warn = q.qu_warn; qlvb->qb_value = q.qu_value; qd->qd_qb = *qlvb; return 0; } |
b3b94faa5 [GFS2] The core o... |
823 824 825 826 |
static int do_glock(struct gfs2_quota_data *qd, int force_refresh, struct gfs2_holder *q_gh) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; |
feaa7bba0 [GFS2] Fix unlink... |
827 |
struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); |
b3b94faa5 [GFS2] The core o... |
828 |
struct gfs2_holder i_gh; |
b3b94faa5 [GFS2] The core o... |
829 |
int error; |
a91ea69ff [GFS2] Align all ... |
830 |
restart: |
b3b94faa5 [GFS2] The core o... |
831 832 833 |
error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_SHARED, 0, q_gh); if (error) return error; |
e9fc2aa09 [GFS2] Update cop... |
834 |
qd->qd_qb = *(struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; |
b3b94faa5 [GFS2] The core o... |
835 |
|
e9fc2aa09 [GFS2] Update cop... |
836 |
if (force_refresh || qd->qd_qb.qb_magic != cpu_to_be32(GFS2_MAGIC)) { |
b3b94faa5 [GFS2] The core o... |
837 |
gfs2_glock_dq_uninit(q_gh); |
91094d0fb GFS2: Remove obso... |
838 839 |
error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_EXCLUSIVE, GL_NOCACHE, q_gh); |
b3b94faa5 [GFS2] The core o... |
840 841 |
if (error) return error; |
e9fc2aa09 [GFS2] Update cop... |
842 |
error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh); |
b3b94faa5 [GFS2] The core o... |
843 844 |
if (error) goto fail; |
e285c1003 GFS2: Add set_xqu... |
845 846 |
error = update_qd(sdp, qd); if (error) |
1e72c0f7c GFS2: Clean up gf... |
847 |
goto fail_gunlock; |
b3b94faa5 [GFS2] The core o... |
848 |
|
e285c1003 GFS2: Add set_xqu... |
849 |
gfs2_glock_dq_uninit(&i_gh); |
91094d0fb GFS2: Remove obso... |
850 851 852 |
gfs2_glock_dq_uninit(q_gh); force_refresh = 0; goto restart; |
b3b94faa5 [GFS2] The core o... |
853 854 855 |
} return 0; |
a91ea69ff [GFS2] Align all ... |
856 |
fail_gunlock: |
b3b94faa5 [GFS2] The core o... |
857 |
gfs2_glock_dq_uninit(&i_gh); |
a91ea69ff [GFS2] Align all ... |
858 |
fail: |
b3b94faa5 [GFS2] The core o... |
859 |
gfs2_glock_dq_uninit(q_gh); |
b3b94faa5 [GFS2] The core o... |
860 861 |
return error; } |
cd915493f [GFS2] Change all... |
862 |
int gfs2_quota_lock(struct gfs2_inode *ip, u32 uid, u32 gid) |
b3b94faa5 [GFS2] The core o... |
863 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
864 |
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
564e12b11 GFS2: decouple qu... |
865 |
struct gfs2_qadata *qa = ip->i_qadata; |
662e3a551 GFS2: quota allow... |
866 |
struct gfs2_quota_data *qd; |
b3b94faa5 [GFS2] The core o... |
867 868 |
unsigned int x; int error = 0; |
891a8e933 GFS2: Misc fixes |
869 870 871 |
error = gfs2_quota_hold(ip, uid, gid); if (error) return error; |
b3b94faa5 [GFS2] The core o... |
872 873 874 875 |
if (capable(CAP_SYS_RESOURCE) || sdp->sd_args.ar_quota != GFS2_QUOTA_ON) return 0; |
564e12b11 GFS2: decouple qu... |
876 |
sort(qa->qa_qd, qa->qa_qd_num, sizeof(struct gfs2_quota_data *), |
b3b94faa5 [GFS2] The core o... |
877 |
sort_qd, NULL); |
564e12b11 GFS2: decouple qu... |
878 |
for (x = 0; x < qa->qa_qd_num; x++) { |
662e3a551 GFS2: quota allow... |
879 |
int force = NO_FORCE; |
564e12b11 GFS2: decouple qu... |
880 |
qd = qa->qa_qd[x]; |
662e3a551 GFS2: quota allow... |
881 882 |
if (test_and_clear_bit(QDF_REFRESH, &qd->qd_flags)) force = FORCE; |
564e12b11 GFS2: decouple qu... |
883 |
error = do_glock(qd, force, &qa->qa_qd_ghs[x]); |
b3b94faa5 [GFS2] The core o... |
884 885 886 887 888 889 890 891 |
if (error) break; } if (!error) set_bit(GIF_QD_LOCKED, &ip->i_flags); else { while (x--) |
564e12b11 GFS2: decouple qu... |
892 |
gfs2_glock_dq_uninit(&qa->qa_qd_ghs[x]); |
b3b94faa5 [GFS2] The core o... |
893 894 895 896 897 898 899 900 901 902 |
gfs2_quota_unhold(ip); } return error; } static int need_sync(struct gfs2_quota_data *qd) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; struct gfs2_tune *gt = &sdp->sd_tune; |
cd915493f [GFS2] Change all... |
903 |
s64 value; |
b3b94faa5 [GFS2] The core o... |
904 905 906 907 908 |
unsigned int num, den; int do_sync = 1; if (!qd->qd_qb.qb_limit) return 0; |
22077f57d GFS2: Remove "dou... |
909 |
spin_lock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
910 |
value = qd->qd_change; |
22077f57d GFS2: Remove "dou... |
911 |
spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
912 913 914 915 916 917 918 919 |
spin_lock(>->gt_spin); num = gt->gt_quota_scale_num; den = gt->gt_quota_scale_den; spin_unlock(>->gt_spin); if (value < 0) do_sync = 0; |
e9fc2aa09 [GFS2] Update cop... |
920 921 |
else if ((s64)be64_to_cpu(qd->qd_qb.qb_value) >= (s64)be64_to_cpu(qd->qd_qb.qb_limit)) |
b3b94faa5 [GFS2] The core o... |
922 923 924 |
do_sync = 0; else { value *= gfs2_jindex_size(sdp) * num; |
4abaca17e [GFS2] Fix GFS2's... |
925 |
value = div_s64(value, den); |
e9fc2aa09 [GFS2] Update cop... |
926 |
value += (s64)be64_to_cpu(qd->qd_qb.qb_value); |
cd915493f [GFS2] Change all... |
927 |
if (value < (s64)be64_to_cpu(qd->qd_qb.qb_limit)) |
b3b94faa5 [GFS2] The core o... |
928 929 930 931 932 933 934 935 |
do_sync = 0; } return do_sync; } void gfs2_quota_unlock(struct gfs2_inode *ip) { |
564e12b11 GFS2: decouple qu... |
936 |
struct gfs2_qadata *qa = ip->i_qadata; |
b3b94faa5 [GFS2] The core o... |
937 938 939 940 941 942 |
struct gfs2_quota_data *qda[4]; unsigned int count = 0; unsigned int x; if (!test_and_clear_bit(GIF_QD_LOCKED, &ip->i_flags)) goto out; |
564e12b11 GFS2: decouple qu... |
943 |
for (x = 0; x < qa->qa_qd_num; x++) { |
b3b94faa5 [GFS2] The core o... |
944 945 |
struct gfs2_quota_data *qd; int sync; |
564e12b11 GFS2: decouple qu... |
946 |
qd = qa->qa_qd[x]; |
b3b94faa5 [GFS2] The core o... |
947 |
sync = need_sync(qd); |
564e12b11 GFS2: decouple qu... |
948 |
gfs2_glock_dq_uninit(&qa->qa_qd_ghs[x]); |
b3b94faa5 [GFS2] The core o... |
949 950 951 952 953 954 955 956 957 958 |
if (sync && qd_trylock(qd)) qda[count++] = qd; } if (count) { do_sync(count, qda); for (x = 0; x < count; x++) qd_unlock(qda[x]); } |
a91ea69ff [GFS2] Align all ... |
959 |
out: |
b3b94faa5 [GFS2] The core o... |
960 961 962 963 964 965 966 967 |
gfs2_quota_unhold(ip); } #define MAX_LINE 256 static int print_message(struct gfs2_quota_data *qd, char *type) { struct gfs2_sbd *sdp = qd->qd_gl->gl_sbd; |
b3b94faa5 [GFS2] The core o... |
968 |
|
2ec465052 GFS2: Use dquot_s... |
969 970 |
printk(KERN_INFO "GFS2: fsid=%s: quota %s for %s %u ", |
02630a12c [GFS2] Remove dep... |
971 972 973 |
sdp->sd_fsname, type, (test_bit(QDF_USER, &qd->qd_flags)) ? "user" : "group", qd->qd_id); |
b3b94faa5 [GFS2] The core o... |
974 975 976 |
return 0; } |
cd915493f [GFS2] Change all... |
977 |
int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid) |
b3b94faa5 [GFS2] The core o... |
978 |
{ |
feaa7bba0 [GFS2] Fix unlink... |
979 |
struct gfs2_sbd *sdp = GFS2_SB(&ip->i_inode); |
564e12b11 GFS2: decouple qu... |
980 |
struct gfs2_qadata *qa = ip->i_qadata; |
b3b94faa5 [GFS2] The core o... |
981 |
struct gfs2_quota_data *qd; |
cd915493f [GFS2] Change all... |
982 |
s64 value; |
b3b94faa5 [GFS2] The core o... |
983 984 985 986 987 988 989 990 |
unsigned int x; int error = 0; if (!test_bit(GIF_QD_LOCKED, &ip->i_flags)) return 0; if (sdp->sd_args.ar_quota != GFS2_QUOTA_ON) return 0; |
564e12b11 GFS2: decouple qu... |
991 992 |
for (x = 0; x < qa->qa_qd_num; x++) { qd = qa->qa_qd[x]; |
b3b94faa5 [GFS2] The core o... |
993 994 995 996 |
if (!((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) || (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags)))) continue; |
e9fc2aa09 [GFS2] Update cop... |
997 |
value = (s64)be64_to_cpu(qd->qd_qb.qb_value); |
22077f57d GFS2: Remove "dou... |
998 |
spin_lock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
999 |
value += qd->qd_change; |
22077f57d GFS2: Remove "dou... |
1000 |
spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
1001 |
|
cd915493f [GFS2] Change all... |
1002 |
if (be64_to_cpu(qd->qd_qb.qb_limit) && (s64)be64_to_cpu(qd->qd_qb.qb_limit) < value) { |
b3b94faa5 [GFS2] The core o... |
1003 |
print_message(qd, "exceeded"); |
2ec465052 GFS2: Use dquot_s... |
1004 1005 1006 |
quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ? USRQUOTA : GRPQUOTA, qd->qd_id, sdp->sd_vfs->s_dev, QUOTA_NL_BHARDWARN); |
b3b94faa5 [GFS2] The core o... |
1007 1008 |
error = -EDQUOT; break; |
e9fc2aa09 [GFS2] Update cop... |
1009 |
} else if (be64_to_cpu(qd->qd_qb.qb_warn) && |
cd915493f [GFS2] Change all... |
1010 |
(s64)be64_to_cpu(qd->qd_qb.qb_warn) < value && |
b3b94faa5 [GFS2] The core o... |
1011 |
time_after_eq(jiffies, qd->qd_last_warn + |
568f4c965 [GFS2] 80 Column ... |
1012 1013 |
gfs2_tune_get(sdp, gt_quota_warn_period) * HZ)) { |
2ec465052 GFS2: Use dquot_s... |
1014 1015 1016 |
quota_send_warning(test_bit(QDF_USER, &qd->qd_flags) ? USRQUOTA : GRPQUOTA, qd->qd_id, sdp->sd_vfs->s_dev, QUOTA_NL_BSOFTWARN); |
b3b94faa5 [GFS2] The core o... |
1017 1018 1019 1020 1021 1022 1023 |
error = print_message(qd, "warning"); qd->qd_last_warn = jiffies; } } return error; } |
cd915493f [GFS2] Change all... |
1024 1025 |
void gfs2_quota_change(struct gfs2_inode *ip, s64 change, u32 uid, u32 gid) |
b3b94faa5 [GFS2] The core o... |
1026 |
{ |
564e12b11 GFS2: decouple qu... |
1027 |
struct gfs2_qadata *qa = ip->i_qadata; |
b3b94faa5 [GFS2] The core o... |
1028 1029 |
struct gfs2_quota_data *qd; unsigned int x; |
b3b94faa5 [GFS2] The core o... |
1030 |
|
feaa7bba0 [GFS2] Fix unlink... |
1031 |
if (gfs2_assert_warn(GFS2_SB(&ip->i_inode), change)) |
b3b94faa5 [GFS2] The core o... |
1032 |
return; |
383f01fbf GFS2: Banish stru... |
1033 |
if (ip->i_diskflags & GFS2_DIF_SYSTEM) |
b3b94faa5 [GFS2] The core o... |
1034 |
return; |
564e12b11 GFS2: decouple qu... |
1035 1036 |
for (x = 0; x < qa->qa_qd_num; x++) { qd = qa->qa_qd[x]; |
b3b94faa5 [GFS2] The core o... |
1037 1038 1039 1040 |
if ((qd->qd_id == uid && test_bit(QDF_USER, &qd->qd_flags)) || (qd->qd_id == gid && !test_bit(QDF_USER, &qd->qd_flags))) { do_qc(qd, change); |
b3b94faa5 [GFS2] The core o... |
1041 1042 1043 |
} } } |
5fb324ad2 quota: move code ... |
1044 |
int gfs2_quota_sync(struct super_block *sb, int type, int wait) |
b3b94faa5 [GFS2] The core o... |
1045 |
{ |
8c42d637f GFS2: Alter argum... |
1046 |
struct gfs2_sbd *sdp = sb->s_fs_info; |
b3b94faa5 [GFS2] The core o... |
1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 |
struct gfs2_quota_data **qda; unsigned int max_qd = gfs2_tune_get(sdp, gt_quota_simul_sync); unsigned int num_qd; unsigned int x; int error = 0; sdp->sd_quota_sync_gen++; qda = kcalloc(max_qd, sizeof(struct gfs2_quota_data *), GFP_KERNEL); if (!qda) return -ENOMEM; do { num_qd = 0; for (;;) { error = qd_fish(sdp, qda + num_qd); if (error || !qda[num_qd]) break; if (++num_qd == max_qd) break; } if (num_qd) { if (!error) error = do_sync(num_qd, qda); if (!error) for (x = 0; x < num_qd; x++) qda[x]->qd_sync_gen = sdp->sd_quota_sync_gen; for (x = 0; x < num_qd; x++) qd_unlock(qda[x]); } } while (!error && num_qd == max_qd); kfree(qda); return error; } |
5fb324ad2 quota: move code ... |
1087 1088 1089 1090 |
static int gfs2_quota_sync_timeo(struct super_block *sb, int type) { return gfs2_quota_sync(sb, type, 0); } |
cd915493f [GFS2] Change all... |
1091 |
int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id) |
b3b94faa5 [GFS2] The core o... |
1092 1093 1094 1095 |
{ struct gfs2_quota_data *qd; struct gfs2_holder q_gh; int error; |
6a6ada81e GFS2: Remove cons... |
1096 |
error = qd_get(sdp, user, id, &qd); |
b3b94faa5 [GFS2] The core o... |
1097 1098 1099 1100 1101 1102 1103 1104 |
if (error) return error; error = do_glock(qd, FORCE, &q_gh); if (!error) gfs2_glock_dq_uninit(&q_gh); qd_put(qd); |
b3b94faa5 [GFS2] The core o... |
1105 1106 |
return error; } |
bb8d8a6f5 [GFS2] Fix sign p... |
1107 1108 1109 1110 1111 1112 1113 1114 |
static void gfs2_quota_change_in(struct gfs2_quota_change_host *qc, const void *buf) { const struct gfs2_quota_change *str = buf; qc->qc_change = be64_to_cpu(str->qc_change); qc->qc_flags = be32_to_cpu(str->qc_flags); qc->qc_id = be32_to_cpu(str->qc_id); } |
b3b94faa5 [GFS2] The core o... |
1115 1116 |
int gfs2_quota_init(struct gfs2_sbd *sdp) { |
feaa7bba0 [GFS2] Fix unlink... |
1117 |
struct gfs2_inode *ip = GFS2_I(sdp->sd_qc_inode); |
a2e0f7993 GFS2: Remove i_di... |
1118 1119 |
u64 size = i_size_read(sdp->sd_qc_inode); unsigned int blocks = size >> sdp->sd_sb.sb_bsize_shift; |
b3b94faa5 [GFS2] The core o... |
1120 1121 |
unsigned int x, slot = 0; unsigned int found = 0; |
cd915493f [GFS2] Change all... |
1122 1123 |
u64 dblock; u32 extlen = 0; |
b3b94faa5 [GFS2] The core o... |
1124 |
int error; |
a2e0f7993 GFS2: Remove i_di... |
1125 |
if (gfs2_check_internal_file_size(sdp->sd_qc_inode, 1, 64 << 20)) |
907b9bceb [GFS2/DLM] Fix tr... |
1126 |
return -EIO; |
a2e0f7993 GFS2: Remove i_di... |
1127 |
|
b3b94faa5 [GFS2] The core o... |
1128 |
sdp->sd_quota_slots = blocks * sdp->sd_qc_per_block; |
5c676f6d3 [GFS2] Macros rem... |
1129 |
sdp->sd_quota_chunks = DIV_ROUND_UP(sdp->sd_quota_slots, 8 * PAGE_SIZE); |
b3b94faa5 [GFS2] The core o... |
1130 1131 1132 1133 |
error = -ENOMEM; sdp->sd_quota_bitmap = kcalloc(sdp->sd_quota_chunks, |
16c5f06f1 [GFS2] fix GFP_KE... |
1134 |
sizeof(unsigned char *), GFP_NOFS); |
b3b94faa5 [GFS2] The core o... |
1135 1136 1137 1138 |
if (!sdp->sd_quota_bitmap) return error; for (x = 0; x < sdp->sd_quota_chunks; x++) { |
16c5f06f1 [GFS2] fix GFP_KE... |
1139 |
sdp->sd_quota_bitmap[x] = kzalloc(PAGE_SIZE, GFP_NOFS); |
b3b94faa5 [GFS2] The core o... |
1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 |
if (!sdp->sd_quota_bitmap[x]) goto fail; } for (x = 0; x < blocks; x++) { struct buffer_head *bh; unsigned int y; if (!extlen) { int new = 0; |
feaa7bba0 [GFS2] Fix unlink... |
1150 |
error = gfs2_extent_map(&ip->i_inode, x, &new, &dblock, &extlen); |
b3b94faa5 [GFS2] The core o... |
1151 1152 1153 |
if (error) goto fail; } |
b3b94faa5 [GFS2] The core o... |
1154 |
error = -EIO; |
7276b3b0c [GFS2] Tidy up me... |
1155 1156 1157 |
bh = gfs2_meta_ra(ip->i_gl, dblock, extlen); if (!bh) goto fail; |
b3b94faa5 [GFS2] The core o... |
1158 1159 1160 1161 |
if (gfs2_metatype_check(sdp, bh, GFS2_METATYPE_QC)) { brelse(bh); goto fail; } |
7276b3b0c [GFS2] Tidy up me... |
1162 |
for (y = 0; y < sdp->sd_qc_per_block && slot < sdp->sd_quota_slots; |
b3b94faa5 [GFS2] The core o... |
1163 |
y++, slot++) { |
b62f963e1 [GFS2] split and ... |
1164 |
struct gfs2_quota_change_host qc; |
b3b94faa5 [GFS2] The core o... |
1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 |
struct gfs2_quota_data *qd; gfs2_quota_change_in(&qc, bh->b_data + sizeof(struct gfs2_meta_header) + y * sizeof(struct gfs2_quota_change)); if (!qc.qc_change) continue; error = qd_alloc(sdp, (qc.qc_flags & GFS2_QCF_USER), qc.qc_id, &qd); if (error) { brelse(bh); goto fail; } set_bit(QDF_CHANGE, &qd->qd_flags); qd->qd_change = qc.qc_change; qd->qd_slot = slot; qd->qd_slot_count = 1; |
b3b94faa5 [GFS2] The core o... |
1184 |
|
0a7ab79c5 GFS2: change gfs2... |
1185 |
spin_lock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
1186 1187 1188 |
gfs2_icbit_munge(sdp, sdp->sd_quota_bitmap, slot, 1); list_add(&qd->qd_list, &sdp->sd_quota_list); atomic_inc(&sdp->sd_quota_count); |
0a7ab79c5 GFS2: change gfs2... |
1189 |
spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 |
found++; } brelse(bh); dblock++; extlen--; } if (found) fs_info(sdp, "found %u quota changes ", found); return 0; |
a91ea69ff [GFS2] Align all ... |
1204 |
fail: |
b3b94faa5 [GFS2] The core o... |
1205 1206 1207 |
gfs2_quota_cleanup(sdp); return error; } |
b3b94faa5 [GFS2] The core o... |
1208 1209 1210 1211 1212 |
void gfs2_quota_cleanup(struct gfs2_sbd *sdp) { struct list_head *head = &sdp->sd_quota_list; struct gfs2_quota_data *qd; unsigned int x; |
0a7ab79c5 GFS2: change gfs2... |
1213 |
spin_lock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
1214 1215 |
while (!list_empty(head)) { qd = list_entry(head->prev, struct gfs2_quota_data, qd_list); |
0a7ab79c5 GFS2: change gfs2... |
1216 1217 1218 |
if (atomic_read(&qd->qd_count) > 1 || (atomic_read(&qd->qd_count) && !test_bit(QDF_CHANGE, &qd->qd_flags))) { |
0a7ab79c5 GFS2: change gfs2... |
1219 1220 |
list_move(&qd->qd_list, head); spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
1221 |
schedule(); |
0a7ab79c5 GFS2: change gfs2... |
1222 |
spin_lock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
1223 1224 1225 1226 |
continue; } list_del(&qd->qd_list); |
0a7ab79c5 GFS2: change gfs2... |
1227 1228 1229 1230 1231 |
/* Also remove if this qd exists in the reclaim list */ if (!list_empty(&qd->qd_reclaim)) { list_del_init(&qd->qd_reclaim); atomic_dec(&qd_lru_count); } |
b3b94faa5 [GFS2] The core o... |
1232 |
atomic_dec(&sdp->sd_quota_count); |
0a7ab79c5 GFS2: change gfs2... |
1233 |
spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
1234 |
|
0a7ab79c5 GFS2: change gfs2... |
1235 |
if (!atomic_read(&qd->qd_count)) { |
b3b94faa5 [GFS2] The core o... |
1236 1237 1238 1239 1240 |
gfs2_assert_warn(sdp, !qd->qd_change); gfs2_assert_warn(sdp, !qd->qd_slot_count); } else gfs2_assert_warn(sdp, qd->qd_slot_count == 1); gfs2_assert_warn(sdp, !qd->qd_bh_count); |
f057f6cdf GFS2: Merge lock_... |
1241 |
gfs2_glock_put(qd->qd_gl); |
37b2c8377 GFS2: Clean up & ... |
1242 |
kmem_cache_free(gfs2_quotad_cachep, qd); |
b3b94faa5 [GFS2] The core o... |
1243 |
|
0a7ab79c5 GFS2: change gfs2... |
1244 |
spin_lock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
1245 |
} |
0a7ab79c5 GFS2: change gfs2... |
1246 |
spin_unlock(&qd_lru_lock); |
b3b94faa5 [GFS2] The core o... |
1247 1248 1249 1250 1251 1252 1253 1254 1255 |
gfs2_assert_warn(sdp, !atomic_read(&sdp->sd_quota_count)); if (sdp->sd_quota_bitmap) { for (x = 0; x < sdp->sd_quota_chunks; x++) kfree(sdp->sd_quota_bitmap[x]); kfree(sdp->sd_quota_bitmap); } } |
37b2c8377 GFS2: Clean up & ... |
1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 |
static void quotad_error(struct gfs2_sbd *sdp, const char *msg, int error) { if (error == 0 || error == -EROFS) return; if (!test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) fs_err(sdp, "gfs2_quotad: %s error %d ", msg, error); } static void quotad_check_timeo(struct gfs2_sbd *sdp, const char *msg, |
8c42d637f GFS2: Alter argum... |
1266 |
int (*fxn)(struct super_block *sb, int type), |
37b2c8377 GFS2: Clean up & ... |
1267 1268 1269 1270 |
unsigned long t, unsigned long *timeo, unsigned int *new_timeo) { if (t >= *timeo) { |
8c42d637f GFS2: Alter argum... |
1271 |
int error = fxn(sdp->sd_vfs, 0); |
37b2c8377 GFS2: Clean up & ... |
1272 1273 1274 1275 1276 1277 |
quotad_error(sdp, msg, error); *timeo = gfs2_tune_get_i(&sdp->sd_tune, new_timeo) * HZ; } else { *timeo -= t; } } |
813e0c46c GFS2: Fix "trunca... |
1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 |
static void quotad_check_trunc_list(struct gfs2_sbd *sdp) { struct gfs2_inode *ip; while(1) { ip = NULL; spin_lock(&sdp->sd_trunc_lock); if (!list_empty(&sdp->sd_trunc_list)) { ip = list_entry(sdp->sd_trunc_list.next, struct gfs2_inode, i_trunc_list); list_del_init(&ip->i_trunc_list); } spin_unlock(&sdp->sd_trunc_lock); if (ip == NULL) return; gfs2_glock_finish_truncate(ip); } } |
3d3c10f2c GFS2: Improve sta... |
1296 1297 1298 1299 1300 1301 |
void gfs2_wake_up_statfs(struct gfs2_sbd *sdp) { if (!sdp->sd_statfs_force_sync) { sdp->sd_statfs_force_sync = 1; wake_up(&sdp->sd_quota_wait); } } |
37b2c8377 GFS2: Clean up & ... |
1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 |
/** * gfs2_quotad - Write cached quota changes into the quota file * @sdp: Pointer to GFS2 superblock * */ int gfs2_quotad(void *data) { struct gfs2_sbd *sdp = data; struct gfs2_tune *tune = &sdp->sd_tune; unsigned long statfs_timeo = 0; unsigned long quotad_timeo = 0; unsigned long t = 0; DEFINE_WAIT(wait); |
813e0c46c GFS2: Fix "trunca... |
1316 |
int empty; |
37b2c8377 GFS2: Clean up & ... |
1317 1318 1319 1320 |
while (!kthread_should_stop()) { /* Update the master statfs file */ |
3d3c10f2c GFS2: Improve sta... |
1321 1322 1323 1324 1325 1326 1327 1328 1329 |
if (sdp->sd_statfs_force_sync) { int error = gfs2_statfs_sync(sdp->sd_vfs, 0); quotad_error(sdp, "statfs", error); statfs_timeo = gfs2_tune_get(sdp, gt_statfs_quantum) * HZ; } else quotad_check_timeo(sdp, "statfs", gfs2_statfs_sync, t, &statfs_timeo, &tune->gt_statfs_quantum); |
37b2c8377 GFS2: Clean up & ... |
1330 1331 |
/* Update quota file */ |
5fb324ad2 quota: move code ... |
1332 |
quotad_check_timeo(sdp, "sync", gfs2_quota_sync_timeo, t, |
37b2c8377 GFS2: Clean up & ... |
1333 |
"ad_timeo, &tune->gt_quota_quantum); |
813e0c46c GFS2: Fix "trunca... |
1334 1335 |
/* Check for & recover partially truncated inodes */ quotad_check_trunc_list(sdp); |
a0acae0e8 freezer: unexport... |
1336 |
try_to_freeze(); |
37b2c8377 GFS2: Clean up & ... |
1337 |
t = min(quotad_timeo, statfs_timeo); |
7fa5d20d1 GFS2: Make quotad... |
1338 |
prepare_to_wait(&sdp->sd_quota_wait, &wait, TASK_INTERRUPTIBLE); |
813e0c46c GFS2: Fix "trunca... |
1339 1340 1341 |
spin_lock(&sdp->sd_trunc_lock); empty = list_empty(&sdp->sd_trunc_list); spin_unlock(&sdp->sd_trunc_lock); |
3d3c10f2c GFS2: Improve sta... |
1342 |
if (empty && !sdp->sd_statfs_force_sync) |
813e0c46c GFS2: Fix "trunca... |
1343 1344 1345 |
t -= schedule_timeout(t); else t = 0; |
37b2c8377 GFS2: Clean up & ... |
1346 1347 1348 1349 1350 |
finish_wait(&sdp->sd_quota_wait, &wait); } return 0; } |
1d371b5e1 GFS2: Add get_xst... |
1351 1352 1353 1354 1355 1356 1357 |
static int gfs2_quota_get_xstate(struct super_block *sb, struct fs_quota_stat *fqs) { struct gfs2_sbd *sdp = sb->s_fs_info; memset(fqs, 0, sizeof(struct fs_quota_stat)); fqs->qs_version = FS_QSTAT_VERSION; |
ad6bb90f3 GFS2: fix quota s... |
1358 1359 1360 |
switch (sdp->sd_args.ar_quota) { case GFS2_QUOTA_ON: |
ade7ce31c quota: Clean up t... |
1361 |
fqs->qs_flags |= (FS_QUOTA_UDQ_ENFD | FS_QUOTA_GDQ_ENFD); |
ad6bb90f3 GFS2: fix quota s... |
1362 1363 |
/*FALLTHRU*/ case GFS2_QUOTA_ACCOUNT: |
ade7ce31c quota: Clean up t... |
1364 |
fqs->qs_flags |= (FS_QUOTA_UDQ_ACCT | FS_QUOTA_GDQ_ACCT); |
ad6bb90f3 GFS2: fix quota s... |
1365 1366 1367 1368 |
break; case GFS2_QUOTA_OFF: break; } |
1d371b5e1 GFS2: Add get_xst... |
1369 1370 1371 1372 1373 1374 1375 1376 1377 |
if (sdp->sd_quota_inode) { fqs->qs_uquota.qfs_ino = GFS2_I(sdp->sd_quota_inode)->i_no_addr; fqs->qs_uquota.qfs_nblks = sdp->sd_quota_inode->i_blocks; } fqs->qs_uquota.qfs_nextents = 1; /* unsupported */ fqs->qs_gquota = fqs->qs_uquota; /* its the same inode in both cases */ fqs->qs_incoredqs = atomic_read(&qd_lru_count); return 0; } |
b9b2dd36c quota: unify ->ge... |
1378 1379 |
static int gfs2_get_dqblk(struct super_block *sb, int type, qid_t id, struct fs_disk_quota *fdq) |
113d6b3c9 GFS2: Add get_xqu... |
1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 |
{ struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_quota_lvb *qlvb; struct gfs2_quota_data *qd; struct gfs2_holder q_gh; int error; memset(fdq, 0, sizeof(struct fs_disk_quota)); if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) return -ESRCH; /* Crazy XFS error code */ if (type == USRQUOTA) type = QUOTA_USER; else if (type == GRPQUOTA) type = QUOTA_GROUP; else return -EINVAL; error = qd_get(sdp, type, id, &qd); if (error) return error; error = do_glock(qd, FORCE, &q_gh); if (error) goto out; qlvb = (struct gfs2_quota_lvb *)qd->qd_gl->gl_lvb; fdq->d_version = FS_DQUOT_VERSION; |
ade7ce31c quota: Clean up t... |
1408 |
fdq->d_flags = (type == QUOTA_USER) ? FS_USER_QUOTA : FS_GROUP_QUOTA; |
113d6b3c9 GFS2: Add get_xqu... |
1409 |
fdq->d_id = id; |
14870b457 GFS2: Userland ex... |
1410 1411 1412 |
fdq->d_blk_hardlimit = be64_to_cpu(qlvb->qb_limit) << sdp->sd_fsb2bb_shift; fdq->d_blk_softlimit = be64_to_cpu(qlvb->qb_warn) << sdp->sd_fsb2bb_shift; fdq->d_bcount = be64_to_cpu(qlvb->qb_value) << sdp->sd_fsb2bb_shift; |
113d6b3c9 GFS2: Add get_xqu... |
1413 1414 1415 1416 1417 1418 |
gfs2_glock_dq_uninit(&q_gh); out: qd_put(qd); return error; } |
e285c1003 GFS2: Add set_xqu... |
1419 |
/* GFS2 only supports a subset of the XFS fields */ |
802ec9b66 GFS2: Allow gfs2 ... |
1420 |
#define GFS2_FIELDMASK (FS_DQ_BSOFT|FS_DQ_BHARD|FS_DQ_BCOUNT) |
e285c1003 GFS2: Add set_xqu... |
1421 |
|
c472b4327 quota: unify ->se... |
1422 1423 |
static int gfs2_set_dqblk(struct super_block *sb, int type, qid_t id, struct fs_disk_quota *fdq) |
e285c1003 GFS2: Add set_xqu... |
1424 1425 1426 1427 1428 1429 1430 1431 |
{ struct gfs2_sbd *sdp = sb->s_fs_info; struct gfs2_inode *ip = GFS2_I(sdp->sd_quota_inode); struct gfs2_quota_data *qd; struct gfs2_holder q_gh, i_gh; unsigned int data_blocks, ind_blocks; unsigned int blocks = 0; int alloc_required; |
e285c1003 GFS2: Add set_xqu... |
1432 1433 1434 1435 1436 1437 1438 1439 1440 |
loff_t offset; int error; if (sdp->sd_args.ar_quota == GFS2_QUOTA_OFF) return -ESRCH; /* Crazy XFS error code */ switch(type) { case USRQUOTA: type = QUOTA_USER; |
ade7ce31c quota: Clean up t... |
1441 |
if (fdq->d_flags != FS_USER_QUOTA) |
e285c1003 GFS2: Add set_xqu... |
1442 1443 1444 1445 |
return -EINVAL; break; case GRPQUOTA: type = QUOTA_GROUP; |
ade7ce31c quota: Clean up t... |
1446 |
if (fdq->d_flags != FS_GROUP_QUOTA) |
e285c1003 GFS2: Add set_xqu... |
1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 |
return -EINVAL; break; default: return -EINVAL; } if (fdq->d_fieldmask & ~GFS2_FIELDMASK) return -EINVAL; if (fdq->d_id != id) return -EINVAL; error = qd_get(sdp, type, id, &qd); if (error) return error; mutex_lock(&ip->i_inode.i_mutex); error = gfs2_glock_nq_init(qd->qd_gl, LM_ST_EXCLUSIVE, 0, &q_gh); if (error) goto out_put; error = gfs2_glock_nq_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &i_gh); if (error) goto out_q; /* Check for existing entry, if none then alloc new blocks */ error = update_qd(sdp, qd); if (error) goto out_i; /* If nothing has changed, this is a no-op */ if ((fdq->d_fieldmask & FS_DQ_BSOFT) && |
14870b457 GFS2: Userland ex... |
1477 |
((fdq->d_blk_softlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_warn))) |
e285c1003 GFS2: Add set_xqu... |
1478 |
fdq->d_fieldmask ^= FS_DQ_BSOFT; |
802ec9b66 GFS2: Allow gfs2 ... |
1479 |
|
e285c1003 GFS2: Add set_xqu... |
1480 |
if ((fdq->d_fieldmask & FS_DQ_BHARD) && |
14870b457 GFS2: Userland ex... |
1481 |
((fdq->d_blk_hardlimit >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_limit))) |
e285c1003 GFS2: Add set_xqu... |
1482 |
fdq->d_fieldmask ^= FS_DQ_BHARD; |
802ec9b66 GFS2: Allow gfs2 ... |
1483 1484 1485 1486 |
if ((fdq->d_fieldmask & FS_DQ_BCOUNT) && ((fdq->d_bcount >> sdp->sd_fsb2bb_shift) == be64_to_cpu(qd->qd_qb.qb_value))) fdq->d_fieldmask ^= FS_DQ_BCOUNT; |
e285c1003 GFS2: Add set_xqu... |
1487 1488 1489 1490 |
if (fdq->d_fieldmask == 0) goto out_i; offset = qd2offset(qd); |
461cb419f GFS2: Simplify gf... |
1491 |
alloc_required = gfs2_write_alloc_required(ip, offset, sizeof(struct gfs2_quota)); |
e79a46a03 GFS2: panics on q... |
1492 1493 |
if (gfs2_is_stuffed(ip)) alloc_required = 1; |
e285c1003 GFS2: Add set_xqu... |
1494 |
if (alloc_required) { |
e285c1003 GFS2: Add set_xqu... |
1495 1496 |
gfs2_write_calc_reserv(ip, sizeof(struct gfs2_quota), &data_blocks, &ind_blocks); |
564e12b11 GFS2: decouple qu... |
1497 1498 |
blocks = 1 + data_blocks + ind_blocks; error = gfs2_inplace_reserve(ip, blocks); |
e285c1003 GFS2: Add set_xqu... |
1499 |
if (error) |
564e12b11 GFS2: decouple qu... |
1500 |
goto out_i; |
54335b1fc GFS2: Cache the m... |
1501 |
blocks += gfs2_rg_blocks(ip); |
e285c1003 GFS2: Add set_xqu... |
1502 |
} |
e79a46a03 GFS2: panics on q... |
1503 1504 1505 |
/* Some quotas span block boundaries and can update two blocks, adding an extra block to the transaction to handle such quotas */ error = gfs2_trans_begin(sdp, blocks + RES_DINODE + 2, 0); |
e285c1003 GFS2: Add set_xqu... |
1506 1507 1508 1509 1510 1511 1512 1513 |
if (error) goto out_release; /* Apply changes */ error = gfs2_adjust_quota(ip, offset, 0, qd, fdq); gfs2_trans_end(sdp); out_release: |
564e12b11 GFS2: decouple qu... |
1514 |
if (alloc_required) |
e285c1003 GFS2: Add set_xqu... |
1515 |
gfs2_inplace_release(ip); |
e285c1003 GFS2: Add set_xqu... |
1516 1517 1518 1519 1520 1521 1522 1523 1524 |
out_i: gfs2_glock_dq_uninit(&i_gh); out_q: gfs2_glock_dq_uninit(&q_gh); out_put: mutex_unlock(&ip->i_inode.i_mutex); qd_put(qd); return error; } |
cc632e7f9 GFS2: Hook gfs2_q... |
1525 1526 |
const struct quotactl_ops gfs2_quotactl_ops = { .quota_sync = gfs2_quota_sync, |
1d371b5e1 GFS2: Add get_xst... |
1527 |
.get_xstate = gfs2_quota_get_xstate, |
b9b2dd36c quota: unify ->ge... |
1528 |
.get_dqblk = gfs2_get_dqblk, |
c472b4327 quota: unify ->se... |
1529 |
.set_dqblk = gfs2_set_dqblk, |
cc632e7f9 GFS2: Hook gfs2_q... |
1530 |
}; |