| Commit | Line | Data |
|---|---|---|
| e788edda FT |
1 | /* |
| 2 | * Copyright (c) 2011 François Tigeot <ftigeot@wolpond.org> | |
| 3 | * All rights reserved. | |
| 95bf5f78 | 4 | * |
| e788edda FT |
5 | * Redistribution and use in source and binary forms, with or without |
| 6 | * modification, are permitted provided that the following conditions | |
| 7 | * are met: | |
| 95bf5f78 | 8 | * |
| e788edda FT |
9 | * 1. Redistributions of source code must retain the above copyright |
| 10 | * notice, this list of conditions and the following disclaimer. | |
| 11 | * 2. Redistributions in binary form must reproduce the above copyright | |
| 12 | * notice, this list of conditions and the following disclaimer in | |
| 13 | * the documentation and/or other materials provided with the | |
| 14 | * distribution. | |
| 15 | * 3. Neither the name of The DragonFly Project nor the names of its | |
| 16 | * contributors may be used to endorse or promote products derived | |
| 17 | * from this software without specific, prior written permission. | |
| 95bf5f78 | 18 | * |
| e788edda FT |
19 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 21 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
| 22 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
| 23 | * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
| 24 | * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
| 25 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
| 26 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | |
| 27 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 28 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | |
| 29 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
| 30 | * SUCH DAMAGE. | |
| 31 | */ | |
| 32 | ||
| 33 | #include <sys/sysctl.h> | |
| 34 | #include <sys/mount.h> | |
| 35 | #include <sys/systm.h> | |
| 36 | #include <sys/nlookup.h> | |
| 37 | #include <sys/vnode.h> | |
| 38 | #include <sys/stat.h> | |
| 39 | #include <sys/vfs_quota.h> | |
| 95bf5f78 FT |
40 | #include <sys/spinlock.h> |
| 41 | #include <sys/spinlock2.h> | |
| 42 | ||
| 43 | /* in-memory accounting, red-black tree based */ | |
| 44 | ||
| 45 | /* FIXME: code duplication caused by uid_t / gid_t differences */ | |
| 46 | RB_PROTOTYPE(ac_utree, ac_unode, rb_entry, rb_ac_unode_cmp); | |
| 47 | RB_PROTOTYPE(ac_gtree, ac_gnode, rb_entry, rb_ac_gnode_cmp); | |
| 48 | ||
| 49 | static int | |
| 50 | rb_ac_unode_cmp(struct ac_unode *a, struct ac_unode *b); | |
| 51 | static int | |
| 52 | rb_ac_gnode_cmp(struct ac_gnode *a, struct ac_gnode *b); | |
| 53 | ||
| 54 | RB_GENERATE(ac_utree, ac_unode, rb_entry, rb_ac_unode_cmp); | |
| 55 | RB_GENERATE(ac_gtree, ac_gnode, rb_entry, rb_ac_gnode_cmp); | |
| 56 | ||
| 57 | struct ac_unode* unode_insert(struct mount*, uid_t); | |
| 58 | struct ac_gnode* gnode_insert(struct mount*, gid_t); | |
| 59 | ||
| 60 | static int | |
| 61 | rb_ac_unode_cmp(struct ac_unode *a, struct ac_unode *b) | |
| 62 | { | |
| 63 | if (a->left_bits < b->left_bits) | |
| 64 | return(-1); | |
| 65 | else if (a->left_bits > b->left_bits) | |
| 66 | return(1); | |
| 67 | return(0); | |
| 68 | } | |
| 69 | ||
| 70 | static int | |
| 71 | rb_ac_gnode_cmp(struct ac_gnode *a, struct ac_gnode *b) | |
| 72 | { | |
| 73 | if (a->left_bits < b->left_bits) | |
| 74 | return(-1); | |
| 75 | else if (a->left_bits > b->left_bits) | |
| 76 | return(1); | |
| 77 | return(0); | |
| 78 | } | |
| 79 | ||
| 80 | struct ac_unode* | |
| 81 | unode_insert(struct mount *mp, uid_t uid) | |
| 82 | { | |
| 83 | struct ac_unode *unp, *res; | |
| 84 | ||
| 3c716a91 | 85 | unp = kmalloc(sizeof(struct ac_unode), M_MOUNT, M_ZERO | M_WAITOK); |
| 95bf5f78 FT |
86 | |
| 87 | unp->left_bits = (uid >> ACCT_CHUNK_BITS); | |
| 88 | res = RB_INSERT(ac_utree, &mp->mnt_acct.ac_uroot, unp); | |
| 89 | KASSERT(res == NULL, ("unode_insert(): RB_INSERT didn't return NULL\n")); | |
| 90 | ||
| 91 | return unp; | |
| 92 | } | |
| 93 | ||
| 94 | struct ac_gnode* | |
| 95 | gnode_insert(struct mount *mp, gid_t gid) | |
| 96 | { | |
| 97 | struct ac_gnode *gnp, *res; | |
| 98 | ||
| 3c716a91 | 99 | gnp = kmalloc(sizeof(struct ac_gnode), M_MOUNT, M_ZERO | M_WAITOK); |
| 95bf5f78 FT |
100 | |
| 101 | gnp->left_bits = (gid >> ACCT_CHUNK_BITS); | |
| 102 | res = RB_INSERT(ac_gtree, &mp->mnt_acct.ac_groot, gnp); | |
| 103 | KASSERT(res == NULL, ("gnode_insert(): RB_INSERT didn't return NULL\n")); | |
| 104 | ||
| 105 | return gnp; | |
| 106 | } | |
| e788edda FT |
107 | |
| 108 | /* initializes global accounting data */ | |
| 109 | void | |
| 110 | vq_init(struct mount *mp) { | |
| 95bf5f78 FT |
111 | |
| 112 | /* initialize the rb trees */ | |
| 113 | RB_INIT(&mp->mnt_acct.ac_uroot); | |
| 114 | RB_INIT(&mp->mnt_acct.ac_groot); | |
| 115 | spin_init(&mp->mnt_acct.ac_spin); | |
| 116 | ||
| 117 | mp->mnt_acct.ac_bytes = 0; | |
| 118 | ||
| 119 | /* and enable data collection */ | |
| 120 | mp->mnt_op->vfs_account = vfs_stdaccount; | |
| 3c716a91 SW |
121 | if (bootverbose) |
| 122 | kprintf("vfs accounting enabled for %s\n", | |
| 123 | mp->mnt_stat.f_mntonname); | |
| e788edda FT |
124 | } |
| 125 | ||
| 126 | ||
| 127 | void | |
| 128 | vq_done(struct mount *mp) { | |
| 95bf5f78 FT |
129 | /* TODO: remove the rb trees here */ |
| 130 | } | |
| 131 | ||
| 132 | void | |
| 133 | vfs_stdaccount(struct mount *mp, uid_t uid, gid_t gid, int64_t delta) | |
| 134 | { | |
| 135 | struct ac_unode ufind, *unp; | |
| 136 | struct ac_gnode gfind, *gnp; | |
| 137 | ||
| 138 | /* find or create address of chunk */ | |
| 139 | ufind.left_bits = (uid >> ACCT_CHUNK_BITS); | |
| 140 | gfind.left_bits = (gid >> ACCT_CHUNK_BITS); | |
| 141 | ||
| 142 | spin_lock(&mp->mnt_acct.ac_spin); | |
| 143 | ||
| 144 | mp->mnt_acct.ac_bytes += delta; | |
| 145 | ||
| 146 | if ((unp = RB_FIND(ac_utree, &mp->mnt_acct.ac_uroot, &ufind)) == NULL) | |
| 147 | unp = unode_insert(mp, uid); | |
| 148 | if ((gnp = RB_FIND(ac_gtree, &mp->mnt_acct.ac_groot, &gfind)) == NULL) | |
| 149 | gnp = gnode_insert(mp, gid); | |
| 150 | ||
| 151 | /* update existing chunk */ | |
| 152 | unp->uid_chunk[(uid & ACCT_CHUNK_MASK)] += delta; | |
| 153 | gnp->gid_chunk[(gid & ACCT_CHUNK_MASK)] += delta; | |
| 154 | ||
| 155 | spin_unlock(&mp->mnt_acct.ac_spin); | |
| e788edda | 156 | } |