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