; ; Quota Hash Abstraction ; ; separate quota hashes per superblock to speed up ; hash lookups and generalize the quota hash interface. ; ; (C) 2003 Herbert Pötzl ; ; Changelog: ; ; 0.04 - first public release ; 0.05 - trivial fix (lost temp variable) ; - some required locking added ; 0.06 - cleanup of invalidate_dquots ; - cleanup of new_dqhash ; - remove_dquot_ref restricted to hash ; - check_compat_quotactl_valid checks for hash ; - added dummy code for CONFIG_QUOTA disabled ; 0.07 - added refcounting for dqhashes ; - adapted quota to use dqhget/dqhput ; - dqhash_valid (NULL handling) ; 0.08 - bugfix release kernel lock in find ; - bugfix dqh_any_quota_enabled ; - whitespace cleanups ; 0.09 - superblock quota ops back as default ; 0.10 - possible race in DQUOT_INIT fixed ; 0.11 - cleanup regarding list_del_init() ; 0.12 - namechange and minor cleanup ; ; this patch is free software; you can redistribute it and/or ; modify it under the terms of the GNU General Public License ; as published by the Free Software Foundation; either version 2 ; of the License, or (at your option) any later version. ; ; this patch is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; diff -NurpP --minimal linux-2.6.0-test9/fs/dquot.c linux-2.6.0-test9-qh0.12/fs/dquot.c --- linux-2.6.0-test9/fs/dquot.c Wed Oct 29 19:25:42 2003 +++ linux-2.6.0-test9-qh0.12/fs/dquot.c Wed Oct 29 20:32:58 2003 @@ -73,6 +73,7 @@ #include #include #include +#include #include #include @@ -150,7 +151,7 @@ static void put_quota_format(struct quot /* * Dquot List Management: * The quota code uses three lists for dquot management: the inuse_list, - * free_dquots, and dquot_hash[] array. A single dquot structure may be + * free_dquots, and hash->dqh_hash[] array. A single dquot structure may be * on all three lists, depending on its current state. * * All dquots are placed to the end of inuse_list when first created, and this @@ -164,7 +165,7 @@ static void put_quota_format(struct quot * dquot is invalidated it's completely released from memory. * * Dquots with a specific identity (device, type and id) are placed on - * one of the dquot_hash[] hash chains. The provides an efficient search + * one of the hash->dqh_hash[] hash chains. The provides an efficient search * mechanism to locate a specific dquot. */ @@ -187,37 +188,39 @@ static void put_quota_format(struct quot static LIST_HEAD(inuse_list); static LIST_HEAD(free_dquots); -static struct list_head dquot_hash[NR_DQHASH]; struct dqstats dqstats; -static inline int const hashfn(struct super_block *sb, unsigned int id, int type) +static inline int const hashfn(unsigned int id, int type) { - return((((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type)) % NR_DQHASH; + return (id * (MAXQUOTAS - type)) % NR_DQHASH; } /* * Following list functions expect dq_list_lock to be held */ -static inline void insert_dquot_hash(struct dquot *dquot) +static inline void insert_dquot_hash(struct dqhash *hash, struct dquot *dquot) { - struct list_head *head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type); + struct list_head *head = hash->dqh_hash + hashfn(dquot->dq_id, dquot->dq_type); list_add(&dquot->dq_hash, head); + dquot->dq_dqh = dqhget(hash); } static inline void remove_dquot_hash(struct dquot *dquot) { list_del_init(&dquot->dq_hash); + dqhput(dquot->dq_dqh); + dquot->dq_dqh = NULL; } -static inline struct dquot *find_dquot(unsigned int hashent, struct super_block *sb, unsigned int id, int type) +static inline struct dquot *find_dquot(struct dqhash *hash, unsigned int hashent, unsigned int id, int type) { struct list_head *head; struct dquot *dquot; - for (head = dquot_hash[hashent].next; head != dquot_hash+hashent; head = head->next) { + for (head = hash->dqh_hash[hashent].next; head != hash->dqh_hash+hashent; head = head->next) { dquot = list_entry(head, struct dquot, dq_hash); - if (dquot->dq_sb == sb && dquot->dq_id == id && dquot->dq_type == type) + if (dquot->dq_id == id && dquot->dq_type == type) return dquot; } return NODQUOT; @@ -261,7 +264,7 @@ static void wait_on_dquot(struct dquot * static int read_dqblk(struct dquot *dquot) { int ret; - struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); + struct quota_info *dqopt = dqh_dqopt(dquot->dq_dqh); down(&dquot->dq_lock); down(&dqopt->dqio_sem); @@ -274,7 +277,7 @@ static int read_dqblk(struct dquot *dquo static int commit_dqblk(struct dquot *dquot) { int ret; - struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); + struct quota_info *dqopt = dqh_dqopt(dquot->dq_dqh); down(&dqopt->dqio_sem); ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot); @@ -286,38 +289,108 @@ static int commit_dqblk(struct dquot *dq * quota is disabled so no new quota might be created. Because we hold dqptr_sem * for writing and pointers were already removed from inodes we actually know that * no quota for this sb+type should be held. */ -static void invalidate_dquots(struct super_block *sb, int type) +static void invalidate_dquots(struct dqhash *hash, int type) { - struct dquot *dquot; - struct list_head *head; + int i; spin_lock(&dq_list_lock); - for (head = inuse_list.next; head != &inuse_list;) { - dquot = list_entry(head, struct dquot, dq_inuse); - head = head->next; - if (dquot->dq_sb != sb) - continue; - if (dquot->dq_type != type) - continue; + for (i=0; idqh_hash[i]; + + while ((head = head->next) != &hash->dqh_hash[i]) { + struct dquot *dquot = list_entry(head, struct dquot, dq_hash); + + if (dquot->dq_type != type) + continue; #ifdef __DQUOT_PARANOIA - /* There should be no users of quota - we hold dqptr_sem for writing */ - if (atomic_read(&dquot->dq_count)) - BUG(); + /* There should be no users of quota - we hold dqptr_sem for writing */ + if (atomic_read(&dquot->dq_count)) + BUG(); #endif - /* Quota now have no users and it has been written on last dqput() */ - remove_dquot_hash(dquot); - remove_free_dquot(dquot); - remove_inuse(dquot); - kmem_cache_free(dquot_cachep, dquot); + /* Quota now have no users and it has been written on last dqput() */ + remove_dquot_hash(dquot); + remove_free_dquot(dquot); + remove_inuse(dquot); + kmem_cache_free(dquot_cachep, dquot); + /* now restart */ + head = &hash->dqh_hash[i]; + } } spin_unlock(&dq_list_lock); } -static int vfs_quota_sync(struct super_block *sb, int type) +/* Dquota Hash Management Functions */ + +static LIST_HEAD(dqhash_list); + +struct dqhash *new_dqhash(struct super_block *sb, unsigned int id) +{ + struct dqhash *hash; + int i; + + hash = kmalloc(sizeof(struct dqhash), GFP_USER); + if (!hash) + return ERR_PTR(-ENOMEM); + + memset(hash, 0, sizeof(struct dqhash)); + hash->dqh_id = id; + atomic_set(&hash->dqh_count, 1); + INIT_LIST_HEAD(&hash->dqh_list); + for (i = 0; i < NR_DQHASH; i++) + INIT_LIST_HEAD(hash->dqh_hash + i); + sema_init(&hash->dqh_dqopt.dqio_sem, 1); + sema_init(&hash->dqh_dqopt.dqonoff_sem, 1); + init_rwsem(&hash->dqh_dqopt.dqptr_sem); + hash->dqh_qop = sb->s_qop; + hash->dqh_qcop = sb->s_qcop; + hash->dqh_sb = sb; + + lock_kernel(); + list_add(&hash->dqh_list, &dqhash_list); + unlock_kernel(); + dprintk ("ˇˇˇ new_dqhash: %p [#0x%08x]\n", hash, hash->dqh_id); + return hash; +} + +void destroy_dqhash(struct dqhash *hash) +{ + int cnt; + + dprintk ("ˇˇˇ destroy_dqhash: %p [#0x%08x] c=%d\n", hash, hash->dqh_id, atomic_read(&hash->dqh_count)); + lock_kernel(); + list_del_init(&hash->dqh_list); + unlock_kernel(); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) /* should not be required anymore! */ + invalidate_dquots(hash, cnt); + kfree(hash); +} + + +struct dqhash *find_dqhash(unsigned int id) +{ + struct list_head *head; + struct dqhash *hash; + + lock_kernel(); + list_for_each(head, &dqhash_list) { + hash = list_entry(head, struct dqhash, dqh_list); + if (hash->dqh_id == id) + goto dqh_found; + } + unlock_kernel(); + return NULL; + +dqh_found: + unlock_kernel(); + return dqhget(hash); +} + + +static int vfs_quota_sync(struct dqhash *hash, int type) { struct list_head *head; struct dquot *dquot; - struct quota_info *dqopt = sb_dqopt(sb); + struct quota_info *dqopt = dqh_dqopt(hash); int cnt; down_read(&dqopt->dqptr_sem); @@ -325,29 +398,29 @@ restart: /* At this point any dirty dquot will definitely be written so we can clear dirty flag from info */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt)) + if ((cnt == type || type == -1) && dqh_has_quota_enabled(hash, cnt)) clear_bit(DQF_ANY_DQUOT_DIRTY_B, &dqopt->info[cnt].dqi_flags); spin_lock(&dq_list_lock); list_for_each(head, &inuse_list) { dquot = list_entry(head, struct dquot, dq_inuse); - if (sb && dquot->dq_sb != sb) + if (hash && dquot->dq_dqh != hash) continue; if (type != -1 && dquot->dq_type != type) continue; - if (!dquot->dq_sb) /* Invalidated? */ + if (!dquot->dq_dqh) /* Invalidated? */ continue; if (!dquot_dirty(dquot)) continue; spin_unlock(&dq_list_lock); - sb->dq_op->sync_dquot(dquot); + hash->dqh_qop->sync_dquot(dquot); goto restart; } spin_unlock(&dq_list_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) && info_dirty(&dqopt->info[cnt])) { + if ((cnt == type || type == -1) && dqh_has_quota_enabled(hash, cnt) && info_dirty(&dqopt->info[cnt])) { down(&dqopt->dqio_sem); - dqopt->ops[cnt]->write_file_info(sb, cnt); + dqopt->ops[cnt]->write_file_info(hash, cnt); up(&dqopt->dqio_sem); } spin_lock(&dq_list_lock); @@ -406,7 +479,7 @@ static void dqput(struct dquot *dquot) if (!atomic_read(&dquot->dq_count)) { printk("VFS: dqput: trying to free free dquot\n"); printk("VFS: device %s, dquot of %s %d\n", - dquot->dq_sb->s_id, + dquot->dq_dqh->dqh_sb->s_id, quotatypes[dquot->dq_type], dquot->dq_id); BUG(); @@ -439,7 +512,7 @@ we_slept: spin_unlock(&dq_list_lock); } -static struct dquot *get_empty_dquot(struct super_block *sb, int type) +static struct dquot *get_empty_dquot(int type) { struct dquot *dquot; @@ -452,7 +525,7 @@ static struct dquot *get_empty_dquot(str INIT_LIST_HEAD(&dquot->dq_free); INIT_LIST_HEAD(&dquot->dq_inuse); INIT_LIST_HEAD(&dquot->dq_hash); - dquot->dq_sb = sb; + dquot->dq_dqh = NULL; dquot->dq_type = type; atomic_set(&dquot->dq_count, 1); @@ -463,19 +536,19 @@ static struct dquot *get_empty_dquot(str * Get reference to dquot * MUST be called with dqptr_sem held */ -static struct dquot *dqget(struct super_block *sb, unsigned int id, int type) +static struct dquot *dqget(struct dqhash *hash, unsigned int id, int type) { - unsigned int hashent = hashfn(sb, id, type); + unsigned int hashent = hashfn(id, type); struct dquot *dquot, *empty = NODQUOT; - if (!sb_has_quota_enabled(sb, type)) + if (!dqh_has_quota_enabled(hash, type)) return NODQUOT; we_slept: spin_lock(&dq_list_lock); - if ((dquot = find_dquot(hashent, sb, id, type)) == NODQUOT) { + if ((dquot = find_dquot(hash, hashent, id, type)) == NODQUOT) { if (empty == NODQUOT) { spin_unlock(&dq_list_lock); - if ((empty = get_empty_dquot(sb, type)) == NODQUOT) + if ((empty = get_empty_dquot(type)) == NODQUOT) schedule(); /* Try to wait for a moment... */ goto we_slept; } @@ -484,7 +557,7 @@ we_slept: /* all dquots go on the inuse_list */ put_inuse(dquot); /* hash it first so it can be found */ - insert_dquot_hash(dquot); + insert_dquot_hash(hash, dquot); dqstats.lookups++; spin_unlock(&dq_list_lock); read_dqblk(dquot); @@ -501,7 +574,7 @@ we_slept: } #ifdef __DQUOT_PARANOIA - if (!dquot->dq_sb) /* Has somebody invalidated entry under us? */ + if (!dquot->dq_dqh) /* Has somebody invalidated entry under us? */ BUG(); #endif @@ -523,9 +596,10 @@ static int dqinit_needed(struct inode *i } /* This routine is guarded by dqptr_sem semaphore */ -static void add_dquot_ref(struct super_block *sb, int type) +static void add_dquot_ref(struct dqhash *hash, int type) { struct list_head *p; + struct super_block *sb = hash->dqh_sb; restart: file_list_lock(); @@ -536,7 +610,7 @@ restart: struct vfsmount *mnt = mntget(filp->f_vfsmnt); struct dentry *dentry = dget(filp->f_dentry); file_list_unlock(); - sb->dq_op->initialize(inode, type); + hash->dqh_qop->initialize(inode, type); dput(dentry); mntput(mnt); /* As we may have blocked we had better restart... */ @@ -668,7 +742,7 @@ static void print_warning(struct dquot * if (!need_print_warning(dquot) || (flag && test_and_set_bit(flag, &dquot->dq_flags))) return; - tty_write_message(current->tty, dquot->dq_sb->s_id); + tty_write_message(current->tty, dquot->dq_dqh->dqh_sb->s_id); if (warntype == ISOFTWARN || warntype == BSOFTWARN) tty_write_message(current->tty, ": warning, "); else @@ -708,7 +782,7 @@ static inline void flush_warnings(struct static inline char ignore_hardlimit(struct dquot *dquot) { - struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type]; + struct mem_dqinfo *info = &dqh_dqopt(dquot->dq_dqh)->info[dquot->dq_type]; return capable(CAP_SYS_RESOURCE) && (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD || !(info->dqi_flags & V1_DQF_RSQUASH)); @@ -740,7 +814,7 @@ static int check_idq(struct dquot *dquot (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit && dquot->dq_dqb.dqb_itime == 0) { *warntype = ISOFTWARN; - dquot->dq_dqb.dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace; + dquot->dq_dqb.dqb_itime = get_seconds() + dqh_dqopt(dquot->dq_dqh)->info[dquot->dq_type].dqi_igrace; } return QUOTA_OK; @@ -775,7 +849,7 @@ static int check_bdq(struct dquot *dquot dquot->dq_dqb.dqb_btime == 0) { if (!prealloc) { *warntype = BSOFTWARN; - dquot->dq_dqb.dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace; + dquot->dq_dqb.dqb_btime = get_seconds() + dqh_dqopt(dquot->dq_dqh)->info[dquot->dq_type].dqi_bgrace; } else /* @@ -796,12 +870,13 @@ static int check_bdq(struct dquot *dquot void dquot_initialize(struct inode *inode, int type) { unsigned int id = 0; + struct dqhash *dqh = inode->i_sb->s_dqh; int cnt; - down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + down_write(&dqh_dqopt(inode->i_dqh)->dqptr_sem); /* Having dqptr_sem we know NOQUOTA flags can't be altered... */ if (IS_NOQUOTA(inode)) { - up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_write(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return; } /* Build list of quotas to initialize... */ @@ -817,12 +892,12 @@ void dquot_initialize(struct inode *inod id = inode->i_gid; break; } - inode->i_dquot[cnt] = dqget(inode->i_sb, id, cnt); + inode->i_dquot[cnt] = dqget(dqh, id, cnt); if (inode->i_dquot[cnt]) inode->i_flags |= S_QUOTA; } } - up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_write(&dqh_dqopt(inode->i_dqh)->dqptr_sem); } /* @@ -848,9 +923,9 @@ void dquot_drop(struct inode *inode) struct dquot *to_drop[MAXQUOTAS]; int cnt; - down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + down_write(&dqh_dqopt(inode->i_dqh)->dqptr_sem); dquot_drop_iupdate(inode, to_drop); - up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_write(&dqh_dqopt(inode->i_dqh)->dqptr_sem); for (cnt = 0; cnt < MAXQUOTAS; cnt++) if (to_drop[cnt] != NODQUOT) dqput(to_drop[cnt]); @@ -882,9 +957,9 @@ int dquot_alloc_space(struct inode *inod for (cnt = 0; cnt < MAXQUOTAS; cnt++) warntype[cnt] = NOWARN; - down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + down_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); if (IS_NOQUOTA(inode)) { - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return QUOTA_OK; } spin_lock(&dq_data_lock); @@ -904,7 +979,7 @@ int dquot_alloc_space(struct inode *inod warn_put_all: spin_unlock(&dq_data_lock); flush_warnings(inode->i_dquot, warntype); - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return ret; } @@ -918,9 +993,9 @@ int dquot_alloc_inode(const struct inode for (cnt = 0; cnt < MAXQUOTAS; cnt++) warntype[cnt] = NOWARN; - down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + down_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); if (IS_NOQUOTA(inode)) { - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return QUOTA_OK; } spin_lock(&dq_data_lock); @@ -940,7 +1015,7 @@ int dquot_alloc_inode(const struct inode warn_put_all: spin_unlock(&dq_data_lock); flush_warnings((struct dquot **)inode->i_dquot, warntype); - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return ret; } @@ -951,9 +1026,9 @@ void dquot_free_space(struct inode *inod { unsigned int cnt; - down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + down_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); if (IS_NOQUOTA(inode)) { - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return; } spin_lock(&dq_data_lock); @@ -964,7 +1039,7 @@ void dquot_free_space(struct inode *inod } inode_sub_bytes(inode, number); spin_unlock(&dq_data_lock); - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); } /* @@ -974,9 +1049,9 @@ void dquot_free_inode(const struct inode { unsigned int cnt; - down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + down_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); if (IS_NOQUOTA(inode)) { - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return; } spin_lock(&dq_data_lock); @@ -986,7 +1061,7 @@ void dquot_free_inode(const struct inode dquot_decr_inodes(inode->i_dquot[cnt], number); } spin_unlock(&dq_data_lock); - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); } /* @@ -999,6 +1074,7 @@ int dquot_transfer(struct inode *inode, qsize_t space; struct dquot *transfer_from[MAXQUOTAS]; struct dquot *transfer_to[MAXQUOTAS]; + struct dqhash *dqh = inode->i_sb->s_dqh; int cnt, ret = NO_QUOTA, chuid = (iattr->ia_valid & ATTR_UID) && inode->i_uid != iattr->ia_uid, chgid = (iattr->ia_valid & ATTR_GID) && inode->i_gid != iattr->ia_gid; char warntype[MAXQUOTAS]; @@ -1008,7 +1084,7 @@ int dquot_transfer(struct inode *inode, transfer_to[cnt] = transfer_from[cnt] = NODQUOT; warntype[cnt] = NOWARN; } - down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + down_write(&dqh_dqopt(inode->i_dqh)->dqptr_sem); if (IS_NOQUOTA(inode)) /* File without quota accounting? */ goto warn_put_all; /* First build the transfer_to list - here we can block on reading of dquots... */ @@ -1017,12 +1093,12 @@ int dquot_transfer(struct inode *inode, case USRQUOTA: if (!chuid) continue; - transfer_to[cnt] = dqget(inode->i_sb, iattr->ia_uid, cnt); + transfer_to[cnt] = dqget(dqh, iattr->ia_uid, cnt); break; case GRPQUOTA: if (!chgid) continue; - transfer_to[cnt] = dqget(inode->i_sb, iattr->ia_gid, cnt); + transfer_to[cnt] = dqget(dqh, iattr->ia_gid, cnt); break; } } @@ -1067,7 +1143,7 @@ warn_put_all: if (ret == NO_QUOTA && transfer_to[cnt] != NODQUOT) dqput(transfer_to[cnt]); } - up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_write(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return ret; } @@ -1116,18 +1192,15 @@ static inline void reset_enable_flags(st } /* Function in inode.c - remove pointers to dquots in icache */ -extern void remove_dquot_ref(struct super_block *, int); +extern void remove_dquot_ref(struct dqhash *, int); /* * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount) */ -int vfs_quota_off(struct super_block *sb, int type) +int vfs_quota_off(struct dqhash *hash, int type) { int cnt; - struct quota_info *dqopt = sb_dqopt(sb); - - if (!sb) - goto out; + struct quota_info *dqopt = dqh_dqopt(hash); /* We need to serialize quota_off() for device */ down(&dqopt->dqonoff_sem); @@ -1135,24 +1208,24 @@ int vfs_quota_off(struct super_block *sb for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (type != -1 && cnt != type) continue; - if (!sb_has_quota_enabled(sb, cnt)) + if (!dqh_has_quota_enabled(hash, cnt)) continue; reset_enable_flags(dqopt, cnt); /* Note: these are blocking operations */ - remove_dquot_ref(sb, cnt); - invalidate_dquots(sb, cnt); + remove_dquot_ref(hash, cnt); + invalidate_dquots(hash, cnt); /* * Now all dquots should be invalidated, all writes done so we should be only * users of the info. No locks needed. */ if (info_dirty(&dqopt->info[cnt])) { down(&dqopt->dqio_sem); - dqopt->ops[cnt]->write_file_info(sb, cnt); + dqopt->ops[cnt]->write_file_info(hash, cnt); up(&dqopt->dqio_sem); } if (dqopt->ops[cnt]->free_file_info) - dqopt->ops[cnt]->free_file_info(sb, cnt); + dqopt->ops[cnt]->free_file_info(hash, cnt); put_quota_format(dqopt->info[cnt].dqi_format); fput(dqopt->files[cnt]); @@ -1164,15 +1237,14 @@ int vfs_quota_off(struct super_block *sb } up_write(&dqopt->dqptr_sem); up(&dqopt->dqonoff_sem); -out: return 0; } -int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path) +int vfs_quota_on(struct dqhash *hash, int type, int format_id, char *path) { struct file *f; struct inode *inode; - struct quota_info *dqopt = sb_dqopt(sb); + struct quota_info *dqopt = dqh_dqopt(hash); struct quota_format_type *fmt = find_quota_format(format_id); int error; unsigned int oldflags; @@ -1197,14 +1269,14 @@ int vfs_quota_on(struct super_block *sb, down(&dqopt->dqonoff_sem); down_write(&dqopt->dqptr_sem); - if (sb_has_quota_enabled(sb, type)) { + if (dqh_has_quota_enabled(hash, type)) { error = -EBUSY; goto out_lock; } oldflags = inode->i_flags; dqopt->files[type] = f; error = -EINVAL; - if (!fmt->qf_ops->check_quota_file(sb, type)) + if (!fmt->qf_ops->check_quota_file(hash, type)) goto out_file_init; /* We don't want quota on quota files */ dquot_drop_nolock(inode); @@ -1213,7 +1285,7 @@ int vfs_quota_on(struct super_block *sb, dqopt->ops[type] = fmt->qf_ops; dqopt->info[type].dqi_format = fmt; down(&dqopt->dqio_sem); - if ((error = dqopt->ops[type]->read_file_info(sb, type)) < 0) { + if ((error = dqopt->ops[type]->read_file_info(hash, type)) < 0) { up(&dqopt->dqio_sem); goto out_file_init; } @@ -1221,7 +1293,7 @@ int vfs_quota_on(struct super_block *sb, set_enable_flags(dqopt, type); up_write(&dqopt->dqptr_sem); - add_dquot_ref(sb, type); + add_dquot_ref(hash, type); up(&dqopt->dqonoff_sem); return 0; @@ -1258,18 +1330,18 @@ static void do_get_dqblk(struct dquot *d spin_unlock(&dq_data_lock); } -int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di) +int vfs_get_dqblk(struct dqhash *hash, int type, qid_t id, struct if_dqblk *di) { struct dquot *dquot; - down_read(&sb_dqopt(sb)->dqptr_sem); - if (!(dquot = dqget(sb, id, type))) { - up_read(&sb_dqopt(sb)->dqptr_sem); + down_read(&dqh_dqopt(hash)->dqptr_sem); + if (!(dquot = dqget(hash, id, type))) { + up_read(&dqh_dqopt(hash)->dqptr_sem); return -ESRCH; } do_get_dqblk(dquot, di); dqput(dquot); - up_read(&sb_dqopt(sb)->dqptr_sem); + up_read(&dqh_dqopt(hash)->dqptr_sem); return 0; } @@ -1309,7 +1381,7 @@ static void do_set_dqblk(struct dquot *d clear_bit(DQ_BLKS_B, &dquot->dq_flags); } else if (!(di->dqb_valid & QIF_BTIME)) /* Set grace only if user hasn't provided his own... */ - dm->dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace; + dm->dqb_btime = get_seconds() + dqh_dqopt(dquot->dq_dqh)->info[dquot->dq_type].dqi_bgrace; } if (check_ilim) { if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) { @@ -1317,7 +1389,7 @@ static void do_set_dqblk(struct dquot *d clear_bit(DQ_INODES_B, &dquot->dq_flags); } else if (!(di->dqb_valid & QIF_ITIME)) /* Set grace only if user hasn't provided his own... */ - dm->dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace; + dm->dqb_itime = get_seconds() + dqh_dqopt(dquot->dq_dqh)->info[dquot->dq_type].dqi_igrace; } if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit) clear_bit(DQ_FAKE_B, &dquot->dq_flags); @@ -1327,53 +1399,53 @@ static void do_set_dqblk(struct dquot *d spin_unlock(&dq_data_lock); } -int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di) +int vfs_set_dqblk(struct dqhash *hash, int type, qid_t id, struct if_dqblk *di) { struct dquot *dquot; - down_read(&sb_dqopt(sb)->dqptr_sem); - if (!(dquot = dqget(sb, id, type))) { - up_read(&sb_dqopt(sb)->dqptr_sem); + down_read(&dqh_dqopt(hash)->dqptr_sem); + if (!(dquot = dqget(hash, id, type))) { + up_read(&dqh_dqopt(hash)->dqptr_sem); return -ESRCH; } do_set_dqblk(dquot, di); dqput(dquot); - up_read(&sb_dqopt(sb)->dqptr_sem); + up_read(&dqh_dqopt(hash)->dqptr_sem); return 0; } /* Generic routine for getting common part of quota file information */ -int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) +int vfs_get_dqinfo(struct dqhash *hash, int type, struct if_dqinfo *ii) { struct mem_dqinfo *mi; - down_read(&sb_dqopt(sb)->dqptr_sem); - if (!sb_has_quota_enabled(sb, type)) { - up_read(&sb_dqopt(sb)->dqptr_sem); + down_read(&dqh_dqopt(hash)->dqptr_sem); + if (!dqh_has_quota_enabled(hash, type)) { + up_read(&dqh_dqopt(hash)->dqptr_sem); return -ESRCH; } - mi = sb_dqopt(sb)->info + type; + mi = dqh_dqopt(hash)->info + type; spin_lock(&dq_data_lock); ii->dqi_bgrace = mi->dqi_bgrace; ii->dqi_igrace = mi->dqi_igrace; ii->dqi_flags = mi->dqi_flags & DQF_MASK; ii->dqi_valid = IIF_ALL; spin_unlock(&dq_data_lock); - up_read(&sb_dqopt(sb)->dqptr_sem); + up_read(&dqh_dqopt(hash)->dqptr_sem); return 0; } /* Generic routine for setting common part of quota file information */ -int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) +int vfs_set_dqinfo(struct dqhash *hash, int type, struct if_dqinfo *ii) { struct mem_dqinfo *mi; - down_read(&sb_dqopt(sb)->dqptr_sem); - if (!sb_has_quota_enabled(sb, type)) { - up_read(&sb_dqopt(sb)->dqptr_sem); + down_read(&dqh_dqopt(hash)->dqptr_sem); + if (!dqh_has_quota_enabled(hash, type)) { + up_read(&dqh_dqopt(hash)->dqptr_sem); return -ESRCH; } - mi = sb_dqopt(sb)->info + type; + mi = dqh_dqopt(hash)->info + type; spin_lock(&dq_data_lock); if (ii->dqi_valid & IIF_BGRACE) mi->dqi_bgrace = ii->dqi_bgrace; @@ -1383,7 +1455,7 @@ int vfs_set_dqinfo(struct super_block *s mi->dqi_flags = (mi->dqi_flags & ~DQF_MASK) | (ii->dqi_flags & DQF_MASK); mark_info_dirty(mi); spin_unlock(&dq_data_lock); - up_read(&sb_dqopt(sb)->dqptr_sem); + up_read(&dqh_dqopt(hash)->dqptr_sem); return 0; } @@ -1490,11 +1562,8 @@ kmem_cache_t *dquot_cachep; static int __init dquot_init(void) { - int i; register_sysctl_table(sys_table, 0); - for (i = 0; i < NR_DQHASH; i++) - INIT_LIST_HEAD(dquot_hash + i); printk(KERN_NOTICE "VFS: Disk quotas %s\n", __DQUOT_VERSION__); dquot_cachep = kmem_cache_create("dquot", diff -NurpP --minimal linux-2.6.0-test9/fs/ext3/super.c linux-2.6.0-test9-qh0.12/fs/ext3/super.c --- linux-2.6.0-test9/fs/ext3/super.c Wed Oct 8 21:24:44 2003 +++ linux-2.6.0-test9-qh0.12/fs/ext3/super.c Wed Oct 29 20:29:47 2003 @@ -1291,7 +1291,7 @@ static int ext3_fill_super (struct super */ sb->s_op = &ext3_sops; sb->s_export_op = &ext3_export_ops; - sb->dq_op = &ext3_qops; + sb->s_dqh->dqh_qop = &ext3_qops; INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ sb->s_root = 0; @@ -1952,7 +1952,7 @@ static int ext3_sync_dquot(struct dquot int ret; int err; handle_t *handle; - struct quota_info *dqops = sb_dqopt(dquot->dq_sb); + struct quota_info *dqops = dqh_dqopt(dquot->dq_dqh); struct inode *qinode; switch (dqops->info[dquot->dq_type].dqi_format->qf_fmt_id) { diff -NurpP --minimal linux-2.6.0-test9/fs/inode.c linux-2.6.0-test9-qh0.12/fs/inode.c --- linux-2.6.0-test9/fs/inode.c Wed Oct 29 19:25:16 2003 +++ linux-2.6.0-test9-qh0.12/fs/inode.c Wed Oct 29 20:29:47 2003 @@ -114,6 +114,7 @@ static struct inode *alloc_inode(struct struct address_space * const mapping = &inode->i_data; inode->i_sb = sb; + inode->i_dqh = dqhget(sb->s_dqh); inode->i_blkbits = sb->s_blocksize_bits; inode->i_flags = 0; atomic_set(&inode->i_count, 1); @@ -160,6 +161,8 @@ void destroy_inode(struct inode *inode) if (inode_has_buffers(inode)) BUG(); security_inode_free(inode); + if (dqhash_valid(inode->i_dqh)) + dqhput(inode->i_dqh); if (inode->i_sb->s_op->destroy_inode) inode->i_sb->s_op->destroy_inode(inode); else @@ -1218,40 +1221,42 @@ EXPORT_SYMBOL(inode_needs_sync); void put_dquot_list(struct list_head *); int remove_inode_dquot_ref(struct inode *, int, struct list_head *); -void remove_dquot_ref(struct super_block *sb, int type) +void remove_dquot_ref(struct dqhash *hash, int type) { struct inode *inode; struct list_head *act_head; + struct super_block *sb = hash->dqh_sb; LIST_HEAD(tofree_head); - if (!sb->dq_op) + if (!hash->dqh_qop) return; /* nothing to do */ spin_lock(&inode_lock); /* This lock is for inodes code */ /* We don't have to lock against quota code - test IS_QUOTAINIT is just for speedup... */ list_for_each(act_head, &inode_in_use) { inode = list_entry(act_head, struct inode, i_list); - if (inode->i_sb == sb && IS_QUOTAINIT(inode)) + if (inode->i_dqh == hash && IS_QUOTAINIT(inode)) remove_inode_dquot_ref(inode, type, &tofree_head); } list_for_each(act_head, &inode_unused) { inode = list_entry(act_head, struct inode, i_list); - if (inode->i_sb == sb && IS_QUOTAINIT(inode)) + if (inode->i_dqh == hash && IS_QUOTAINIT(inode)) remove_inode_dquot_ref(inode, type, &tofree_head); } list_for_each(act_head, &sb->s_dirty) { inode = list_entry(act_head, struct inode, i_list); - if (IS_QUOTAINIT(inode)) + if (inode->i_dqh == hash && IS_QUOTAINIT(inode)) remove_inode_dquot_ref(inode, type, &tofree_head); } list_for_each(act_head, &sb->s_io) { inode = list_entry(act_head, struct inode, i_list); - if (IS_QUOTAINIT(inode)) + if (inode->i_dqh == hash && IS_QUOTAINIT(inode)) remove_inode_dquot_ref(inode, type, &tofree_head); } spin_unlock(&inode_lock); put_dquot_list(&tofree_head); + dqhput(hash); /* is this required? */ } #endif diff -NurpP --minimal linux-2.6.0-test9/fs/namespace.c linux-2.6.0-test9-qh0.12/fs/namespace.c --- linux-2.6.0-test9/fs/namespace.c Wed Oct 8 21:24:17 2003 +++ linux-2.6.0-test9-qh0.12/fs/namespace.c Wed Oct 29 20:29:47 2003 @@ -346,7 +346,7 @@ static int do_umount(struct vfsmount *mn /* last instance - try to be smart */ spin_unlock(&vfsmount_lock); lock_kernel(); - DQUOT_OFF(sb); + DQUOT_OFF(sb->s_dqh); acct_auto_close(sb); unlock_kernel(); security_sb_umount_close(mnt); diff -NurpP --minimal linux-2.6.0-test9/fs/quota.c linux-2.6.0-test9-qh0.12/fs/quota.c --- linux-2.6.0-test9/fs/quota.c Wed Oct 8 21:24:51 2003 +++ linux-2.6.0-test9-qh0.12/fs/quota.c Wed Oct 29 20:29:47 2003 @@ -15,63 +15,63 @@ #include /* Check validity of quotactl */ -static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) +static int check_quotactl_valid(struct dqhash *hash, int type, int cmd, qid_t id) { if (type >= MAXQUOTAS) return -EINVAL; - if (!sb && cmd != Q_SYNC) + if (!hash && cmd != Q_SYNC) return -ENODEV; /* Is operation supported? */ - if (sb && !sb->s_qcop) + if (hash && !hash->dqh_qcop) return -ENOSYS; switch (cmd) { case Q_GETFMT: break; case Q_QUOTAON: - if (!sb->s_qcop->quota_on) + if (!hash->dqh_qcop->quota_on) return -ENOSYS; break; case Q_QUOTAOFF: - if (!sb->s_qcop->quota_off) + if (!hash->dqh_qcop->quota_off) return -ENOSYS; break; case Q_SETINFO: - if (!sb->s_qcop->set_info) + if (!hash->dqh_qcop->set_info) return -ENOSYS; break; case Q_GETINFO: - if (!sb->s_qcop->get_info) + if (!hash->dqh_qcop->get_info) return -ENOSYS; break; case Q_SETQUOTA: - if (!sb->s_qcop->set_dqblk) + if (!hash->dqh_qcop->set_dqblk) return -ENOSYS; break; case Q_GETQUOTA: - if (!sb->s_qcop->get_dqblk) + if (!hash->dqh_qcop->get_dqblk) return -ENOSYS; break; case Q_SYNC: - if (sb && !sb->s_qcop->quota_sync) + if (hash && !hash->dqh_qcop->quota_sync) return -ENOSYS; break; case Q_XQUOTAON: case Q_XQUOTAOFF: case Q_XQUOTARM: - if (!sb->s_qcop->set_xstate) + if (!hash->dqh_qcop->set_xstate) return -ENOSYS; break; case Q_XGETQSTAT: - if (!sb->s_qcop->get_xstate) + if (!hash->dqh_qcop->get_xstate) return -ENOSYS; break; case Q_XSETQLIM: - if (!sb->s_qcop->set_xquota) + if (!hash->dqh_qcop->set_xquota) return -ENOSYS; break; case Q_XGETQUOTA: - if (!sb->s_qcop->get_xquota) + if (!hash->dqh_qcop->get_xquota) return -ENOSYS; break; default: @@ -87,7 +87,7 @@ static int check_quotactl_valid(struct s case Q_SETQUOTA: case Q_GETQUOTA: /* This is just informative test so we are satisfied without a lock */ - if (!sb_has_quota_enabled(sb, type)) + if (!dqh_has_quota_enabled(hash, type)) return -ESRCH; } /* Check privileges */ @@ -101,7 +101,7 @@ static int check_quotactl_valid(struct s if (!capable(CAP_SYS_ADMIN)) return -EPERM; - return security_quotactl (cmd, type, id, sb); + return security_quotactl (cmd, type, id, hash); } static struct super_block *get_super_to_sync(int type) @@ -113,10 +113,11 @@ restart: spin_lock(&sb_lock); list_for_each(head, &super_blocks) { struct super_block *sb = list_entry(head, struct super_block, s_list); + struct dqhash *dqh = sb->s_dqh; for (cnt = 0, dirty = 0; cnt < MAXQUOTAS; cnt++) - if ((type == cnt || type == -1) && sb_has_quota_enabled(sb, cnt) - && info_any_dquot_dirty(&sb_dqopt(sb)->info[cnt])) + if ((type == cnt || type == -1) && dqh_has_quota_enabled(dqh, cnt) + && info_any_dquot_dirty(&dqh_dqopt(dqh)->info[cnt])) dirty = 1; if (!dirty) continue; @@ -133,23 +134,33 @@ restart: return NULL; } +void sync_dquots_dqh(struct dqhash *hash, int type) +{ + if (hash->dqh_qcop->quota_sync) + hash->dqh_qcop->quota_sync(hash, type); +} + void sync_dquots(struct super_block *sb, int type) { + struct dqhash *dqh; + if (sb) { - if (sb->s_qcop->quota_sync) - sb->s_qcop->quota_sync(sb, type); - } - else { - while ((sb = get_super_to_sync(type))) { - if (sb->s_qcop->quota_sync) - sb->s_qcop->quota_sync(sb, type); - drop_super(sb); - } + dqh = sb->s_dqh; + if (dqh && dqh->dqh_qcop->quota_sync) + dqh->dqh_qcop->quota_sync(dqh, type); } + else { + while ((sb = get_super_to_sync(type))) { + dqh = sb->s_dqh; + if (dqh && dqh->dqh_qcop->quota_sync) + dqh->dqh_qcop->quota_sync(dqh, type); + drop_super(sb); + } + } } /* Copy parameters and call proper function */ -static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id, caddr_t addr) +static int do_quotactl(struct dqhash *hash, int type, int cmd, qid_t id, caddr_t addr) { int ret; @@ -159,23 +170,23 @@ static int do_quotactl(struct super_bloc if (IS_ERR(pathname = getname(addr))) return PTR_ERR(pathname); - ret = sb->s_qcop->quota_on(sb, type, id, pathname); + ret = hash->dqh_qcop->quota_on(hash, type, id, pathname); putname(pathname); return ret; } case Q_QUOTAOFF: - return sb->s_qcop->quota_off(sb, type); + return hash->dqh_qcop->quota_off(hash, type); case Q_GETFMT: { __u32 fmt; - down_read(&sb_dqopt(sb)->dqptr_sem); - if (!sb_has_quota_enabled(sb, type)) { - up_read(&sb_dqopt(sb)->dqptr_sem); + down_read(&dqh_dqopt(hash)->dqptr_sem); + if (!dqh_has_quota_enabled(hash, type)) { + up_read(&dqh_dqopt(hash)->dqptr_sem); return -ESRCH; } - fmt = sb_dqopt(sb)->info[type].dqi_format->qf_fmt_id; - up_read(&sb_dqopt(sb)->dqptr_sem); + fmt = dqh_dqopt(hash)->info[type].dqi_format->qf_fmt_id; + up_read(&dqh_dqopt(hash)->dqptr_sem); if (copy_to_user(addr, &fmt, sizeof(fmt))) return -EFAULT; return 0; @@ -183,7 +194,7 @@ static int do_quotactl(struct super_bloc case Q_GETINFO: { struct if_dqinfo info; - if ((ret = sb->s_qcop->get_info(sb, type, &info))) + if ((ret = hash->dqh_qcop->get_info(hash, type, &info))) return ret; if (copy_to_user(addr, &info, sizeof(info))) return -EFAULT; @@ -194,12 +205,12 @@ static int do_quotactl(struct super_bloc if (copy_from_user(&info, addr, sizeof(info))) return -EFAULT; - return sb->s_qcop->set_info(sb, type, &info); + return hash->dqh_qcop->set_info(hash, type, &info); } case Q_GETQUOTA: { struct if_dqblk idq; - if ((ret = sb->s_qcop->get_dqblk(sb, type, id, &idq))) + if ((ret = hash->dqh_qcop->get_dqblk(hash, type, id, &idq))) return ret; if (copy_to_user(addr, &idq, sizeof(idq))) return -EFAULT; @@ -210,10 +221,10 @@ static int do_quotactl(struct super_bloc if (copy_from_user(&idq, addr, sizeof(idq))) return -EFAULT; - return sb->s_qcop->set_dqblk(sb, type, id, &idq); + return hash->dqh_qcop->set_dqblk(hash, type, id, &idq); } case Q_SYNC: - sync_dquots(sb, type); + sync_dquots_dqh(hash, type); return 0; case Q_XQUOTAON: @@ -223,12 +234,12 @@ static int do_quotactl(struct super_bloc if (copy_from_user(&flags, addr, sizeof(flags))) return -EFAULT; - return sb->s_qcop->set_xstate(sb, flags, cmd); + return hash->dqh_qcop->set_xstate(hash, flags, cmd); } case Q_XGETQSTAT: { struct fs_quota_stat fqs; - if ((ret = sb->s_qcop->get_xstate(sb, &fqs))) + if ((ret = hash->dqh_qcop->get_xstate(hash, &fqs))) return ret; if (copy_to_user(addr, &fqs, sizeof(fqs))) return -EFAULT; @@ -239,12 +250,12 @@ static int do_quotactl(struct super_bloc if (copy_from_user(&fdq, addr, sizeof(fdq))) return -EFAULT; - return sb->s_qcop->set_xquota(sb, type, id, &fdq); + return hash->dqh_qcop->set_xquota(hash, type, id, &fdq); } case Q_XGETQUOTA: { struct fs_disk_quota fdq; - if ((ret = sb->s_qcop->get_xquota(sb, type, id, &fdq))) + if ((ret = hash->dqh_qcop->get_xquota(hash, type, id, &fdq))) return ret; if (copy_to_user(addr, &fdq, sizeof(fdq))) return -EFAULT; @@ -267,6 +278,7 @@ asmlinkage long sys_quotactl(unsigned in { uint cmds, type; struct super_block *sb = NULL; + struct dqhash *dqh = NULL; struct block_device *bdev; char *tmp; int ret; @@ -287,10 +299,11 @@ asmlinkage long sys_quotactl(unsigned in if (!sb) return -ENODEV; } - - ret = check_quotactl_valid(sb, type, cmds, id); + if (sb) + dqh = sb->s_dqh; + ret = check_quotactl_valid(dqh, type, cmds, id); if (ret >= 0) - ret = do_quotactl(sb, type, cmds, id, addr); + ret = do_quotactl(dqh, type, cmds, id, addr); if (sb) drop_super(sb); diff -NurpP --minimal linux-2.6.0-test9/fs/quota_v1.c linux-2.6.0-test9-qh0.12/fs/quota_v1.c --- linux-2.6.0-test9/fs/quota_v1.c Wed Oct 8 21:24:26 2003 +++ linux-2.6.0-test9-qh0.12/fs/quota_v1.c Wed Oct 29 20:29:47 2003 @@ -46,7 +46,7 @@ static int v1_read_dqblk(struct dquot *d loff_t offset; struct v1_disk_dqblk dqblk; - filp = sb_dqopt(dquot->dq_sb)->files[type]; + filp = dqh_dqopt(dquot->dq_dqh)->files[type]; if (filp == (struct file *)NULL) return -EINVAL; @@ -75,7 +75,7 @@ static int v1_commit_dqblk(struct dquot ssize_t ret; struct v1_disk_dqblk dqblk; - filp = sb_dqopt(dquot->dq_sb)->files[type]; + filp = dqh_dqopt(dquot->dq_dqh)->files[type]; offset = v1_dqoff(dquot->dq_id); fs = get_fs(); set_fs(KERNEL_DS); @@ -87,8 +87,8 @@ static int v1_commit_dqblk(struct dquot v1_mem2disk_dqblk(&dqblk, &dquot->dq_dqb); dquot->dq_flags &= ~DQ_MOD; if (dquot->dq_id == 0) { - dqblk.dqb_btime = sb_dqopt(dquot->dq_sb)->info[type].dqi_bgrace; - dqblk.dqb_itime = sb_dqopt(dquot->dq_sb)->info[type].dqi_igrace; + dqblk.dqb_btime = dqh_dqopt(dquot->dq_dqh)->info[type].dqi_bgrace; + dqblk.dqb_itime = dqh_dqopt(dquot->dq_dqh)->info[type].dqi_igrace; } ret = 0; if (filp) @@ -96,7 +96,7 @@ static int v1_commit_dqblk(struct dquot sizeof(struct v1_disk_dqblk), &offset); if (ret != sizeof(struct v1_disk_dqblk)) { printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", - dquot->dq_sb->s_id); + dquot->dq_dqh->dqh_sb->s_id); if (ret >= 0) ret = -EIO; goto out; @@ -122,9 +122,9 @@ struct v2_disk_dqheader { __u32 dqh_version; /* File version */ }; -static int v1_check_quota_file(struct super_block *sb, int type) +static int v1_check_quota_file(struct dqhash *hash, int type) { - struct file *f = sb_dqopt(sb)->files[type]; + struct file *f = dqh_dqopt(hash)->files[type]; struct inode *inode = f->f_dentry->d_inode; ulong blocks; size_t off; @@ -151,13 +151,13 @@ static int v1_check_quota_file(struct su return 1; /* Probably not new format */ if (le32_to_cpu(dqhead.dqh_magic) != quota_magics[type]) return 1; /* Definitely not new format */ - printk(KERN_INFO "VFS: %s: Refusing to turn on old quota format on given file. It probably contains newer quota format.\n", sb->s_id); + printk(KERN_INFO "VFS: Refusing to turn on old quota format on given file. It probably contains newer quota format.\n"); return 0; /* Seems like a new format file -> refuse it */ } -static int v1_read_file_info(struct super_block *sb, int type) +static int v1_read_file_info(struct dqhash *hash, int type) { - struct quota_info *dqopt = sb_dqopt(sb); + struct quota_info *dqopt = dqh_dqopt(hash); mm_segment_t fs; loff_t offset; struct file *filp = dqopt->files[type]; @@ -180,9 +180,9 @@ out: return ret; } -static int v1_write_file_info(struct super_block *sb, int type) +static int v1_write_file_info(struct dqhash *hash, int type) { - struct quota_info *dqopt = sb_dqopt(sb); + struct quota_info *dqopt = dqh_dqopt(hash); mm_segment_t fs; struct file *filp = dqopt->files[type]; struct v1_disk_dqblk dqblk; diff -NurpP --minimal linux-2.6.0-test9/fs/quota_v2.c linux-2.6.0-test9-qh0.12/fs/quota_v2.c --- linux-2.6.0-test9/fs/quota_v2.c Wed Oct 8 21:24:27 2003 +++ linux-2.6.0-test9-qh0.12/fs/quota_v2.c Wed Oct 29 20:29:47 2003 @@ -27,10 +27,10 @@ typedef char *dqbuf_t; #define GETENTRIES(buf) ((struct v2_disk_dqblk *)(((char *)buf)+sizeof(struct v2_disk_dqdbheader))) /* Check whether given file is really vfsv0 quotafile */ -static int v2_check_quota_file(struct super_block *sb, int type) +static int v2_check_quota_file(struct dqhash *hash, int type) { struct v2_disk_dqheader dqhead; - struct file *f = sb_dqopt(sb)->files[type]; + struct file *f = dqh_dqopt(hash)->files[type]; mm_segment_t fs; ssize_t size; loff_t offset = 0; @@ -50,12 +50,12 @@ static int v2_check_quota_file(struct su } /* Read information header from quota file */ -static int v2_read_file_info(struct super_block *sb, int type) +static int v2_read_file_info(struct dqhash *hash, int type) { mm_segment_t fs; struct v2_disk_dqinfo dinfo; - struct mem_dqinfo *info = sb_dqopt(sb)->info+type; - struct file *f = sb_dqopt(sb)->files[type]; + struct mem_dqinfo *info = dqh_dqopt(hash)->info+type; + struct file *f = dqh_dqopt(hash)->files[type]; ssize_t size; loff_t offset = V2_DQINFOOFF; @@ -78,12 +78,12 @@ static int v2_read_file_info(struct supe } /* Write information header to quota file */ -static int v2_write_file_info(struct super_block *sb, int type) +static int v2_write_file_info(struct dqhash *hash, int type) { mm_segment_t fs; struct v2_disk_dqinfo dinfo; - struct mem_dqinfo *info = sb_dqopt(sb)->info+type; - struct file *f = sb_dqopt(sb)->files[type]; + struct mem_dqinfo *info = dqh_dqopt(hash)->info+type; + struct file *f = dqh_dqopt(hash)->files[type]; ssize_t size; loff_t offset = V2_DQINFOOFF; @@ -286,8 +286,8 @@ out_buf: /* Find space for dquot */ static uint find_free_dqentry(struct dquot *dquot, int *err) { - struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; - struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info+dquot->dq_type; + struct file *filp = dqh_dqopt(dquot->dq_dqh)->files[dquot->dq_type]; + struct mem_dqinfo *info = dqh_dqopt(dquot->dq_dqh)->info+dquot->dq_type; uint blk, i; struct v2_disk_dqdbheader *dh; struct v2_disk_dqblk *ddquot; @@ -348,8 +348,8 @@ out_buf: /* Insert reference to structure into the trie */ static int do_insert_tree(struct dquot *dquot, uint *treeblk, int depth) { - struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; - struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type; + struct file *filp = dqh_dqopt(dquot->dq_dqh)->files[dquot->dq_type]; + struct mem_dqinfo *info = dqh_dqopt(dquot->dq_dqh)->info + dquot->dq_type; dqbuf_t buf; int ret = 0, newson = 0, newact = 0; u32 *ref; @@ -422,7 +422,7 @@ static int v2_write_dquot(struct dquot * printk(KERN_ERR "VFS: Error %Zd occurred while creating quota.\n", ret); return ret; } - filp = sb_dqopt(dquot->dq_sb)->files[type]; + filp = dqh_dqopt(dquot->dq_dqh)->files[type]; offset = dquot->dq_off; mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id); fs = get_fs(); @@ -430,7 +430,7 @@ static int v2_write_dquot(struct dquot * ret = filp->f_op->write(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset); set_fs(fs); if (ret != sizeof(struct v2_disk_dqblk)) { - printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id); + printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_dqh->dqh_sb->s_id); if (ret >= 0) ret = -ENOSPC; } @@ -444,8 +444,8 @@ static int v2_write_dquot(struct dquot * /* Free dquot entry in data block */ static int free_dqentry(struct dquot *dquot, uint blk) { - struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; - struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type; + struct file *filp = dqh_dqopt(dquot->dq_dqh)->files[dquot->dq_type]; + struct mem_dqinfo *info = dqh_dqopt(dquot->dq_dqh)->info + dquot->dq_type; struct v2_disk_dqdbheader *dh; dqbuf_t buf = getdqbuf(); int ret = 0; @@ -493,8 +493,8 @@ out_buf: /* Remove reference to dquot from tree */ static int remove_tree(struct dquot *dquot, uint *blk, int depth) { - struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; - struct mem_dqinfo *info = sb_dqopt(dquot->dq_sb)->info + dquot->dq_type; + struct file *filp = dqh_dqopt(dquot->dq_dqh)->files[dquot->dq_type]; + struct mem_dqinfo *info = dqh_dqopt(dquot->dq_dqh)->info + dquot->dq_type; dqbuf_t buf = getdqbuf(); int ret = 0; uint newblk; @@ -543,7 +543,7 @@ static int v2_delete_dquot(struct dquot /* Find entry in block */ static loff_t find_block_dqentry(struct dquot *dquot, uint blk) { - struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + struct file *filp = dqh_dqopt(dquot->dq_dqh)->files[dquot->dq_type]; dqbuf_t buf = getdqbuf(); loff_t ret = 0; int i; @@ -580,7 +580,7 @@ out_buf: /* Find entry for given id in the tree */ static loff_t find_tree_dqentry(struct dquot *dquot, uint blk, int depth) { - struct file *filp = sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + struct file *filp = dqh_dqopt(dquot->dq_dqh)->files[dquot->dq_type]; dqbuf_t buf = getdqbuf(); loff_t ret = 0; u32 *ref = (u32 *)buf; @@ -619,10 +619,10 @@ static int v2_read_dquot(struct dquot *d struct v2_disk_dqblk ddquot; int ret = 0; - filp = sb_dqopt(dquot->dq_sb)->files[type]; + filp = dqh_dqopt(dquot->dq_dqh)->files[type]; #ifdef __QUOTA_V2_PARANOIA - if (!filp || !dquot->dq_sb) { /* Invalidated quota? */ + if (!filp || !dquot->dq_dqh) { /* Invalidated quota? */ printk(KERN_ERR "VFS: Quota invalidated while reading!\n"); return -EIO; } diff -NurpP --minimal linux-2.6.0-test9/fs/super.c linux-2.6.0-test9-qh0.12/fs/super.c --- linux-2.6.0-test9/fs/super.c Wed Oct 8 21:24:04 2003 +++ linux-2.6.0-test9-qh0.12/fs/super.c Wed Oct 29 20:29:47 2003 @@ -72,13 +72,12 @@ static struct super_block *alloc_super(v s->s_count = S_BIAS; atomic_set(&s->s_active, 1); sema_init(&s->s_vfs_rename_sem,1); - sema_init(&s->s_dquot.dqio_sem, 1); - sema_init(&s->s_dquot.dqonoff_sem, 1); - init_rwsem(&s->s_dquot.dqptr_sem); s->s_maxbytes = MAX_NON_LFS; - s->dq_op = sb_dquot_ops; + s->s_qop = sb_dquot_ops; s->s_qcop = sb_quotactl_ops; s->s_op = &default_op; + /* quick hack to make dqhash id unique, sufficient for now */ + s->s_dqh = new_dqhash(s, (unsigned int)s); } out: return s; @@ -93,6 +92,7 @@ out: static inline void destroy_super(struct super_block *s) { security_sb_free(s); + dqhput(s->s_dqh); kfree(s); } diff -NurpP --minimal linux-2.6.0-test9/fs/udf/super.c linux-2.6.0-test9-qh0.12/fs/udf/super.c --- linux-2.6.0-test9/fs/udf/super.c Wed Oct 8 21:24:17 2003 +++ linux-2.6.0-test9-qh0.12/fs/udf/super.c Wed Oct 29 20:29:47 2003 @@ -1558,7 +1558,7 @@ static int udf_fill_super(struct super_b /* Fill in the rest of the superblock */ sb->s_op = &udf_sb_ops; - sb->dq_op = NULL; + sb->s_qop = NULL; sb->s_dirt = 0; sb->s_magic = UDF_SUPER_MAGIC; diff -NurpP --minimal linux-2.6.0-test9/fs/ufs/super.c linux-2.6.0-test9-qh0.12/fs/ufs/super.c --- linux-2.6.0-test9/fs/ufs/super.c Wed Oct 8 21:24:00 2003 +++ linux-2.6.0-test9-qh0.12/fs/ufs/super.c Wed Oct 29 20:29:47 2003 @@ -785,7 +785,7 @@ magic_found: * Read ufs_super_block into internal data structures */ sb->s_op = &ufs_super_ops; - sb->dq_op = NULL; /***/ + sb->s_qop = NULL; /***/ sb->s_magic = fs32_to_cpu(sb, usb3->fs_magic); uspi->s_sblkno = fs32_to_cpu(sb, usb1->fs_sblkno); diff -NurpP --minimal linux-2.6.0-test9/include/linux/fs.h linux-2.6.0-test9-qh0.12/include/linux/fs.h --- linux-2.6.0-test9/include/linux/fs.h Wed Oct 8 21:24:03 2003 +++ linux-2.6.0-test9-qh0.12/include/linux/fs.h Wed Oct 29 20:29:47 2003 @@ -394,6 +394,7 @@ struct inode { struct file_lock *i_flock; struct address_space *i_mapping; struct address_space i_data; + struct dqhash *i_dqh; struct dquot *i_dquot[MAXQUOTAS]; /* These three should probably be a union */ struct list_head i_devices; @@ -673,7 +674,7 @@ struct super_block { unsigned long long s_maxbytes; /* Max file size */ struct file_system_type *s_type; struct super_operations *s_op; - struct dquot_operations *dq_op; + struct dquot_operations *s_qop; struct quotactl_ops *s_qcop; struct export_operations *s_export_op; unsigned long s_flags; @@ -694,7 +695,7 @@ struct super_block { struct block_device *s_bdev; struct list_head s_instances; - struct quota_info s_dquot; /* Diskquota specific options */ + struct dqhash *s_dqh; /* Diskquota hash */ char s_id[32]; /* Informational name */ diff -NurpP --minimal linux-2.6.0-test9/include/linux/quota.h linux-2.6.0-test9-qh0.12/include/linux/quota.h --- linux-2.6.0-test9/include/linux/quota.h Wed Oct 8 21:24:26 2003 +++ linux-2.6.0-test9-qh0.12/include/linux/quota.h Wed Oct 29 20:29:47 2003 @@ -57,6 +57,13 @@ extern spinlock_t dq_data_lock; #define kb2qb(x) ((x) >> (QUOTABLOCK_BITS-10)) #define toqb(x) (((x) + QUOTABLOCK_SIZE - 1) >> QUOTABLOCK_BITS) +/* are NULL dqhash ptrs valid? */ +#ifdef HANDLE_DQHASH_NULL +#define dqhash_valid(hash) ((hash) != NULL) +#else +#define dqhash_valid(hash) (0 == 0) +#endif + #define MAXQUOTAS 2 #define USRQUOTA 0 /* element used for user quotas */ #define GRPQUOTA 1 /* element used for group quotas */ @@ -183,7 +190,7 @@ extern inline void mark_info_dirty(struc #define info_any_dquot_dirty(info) test_bit(DQF_ANY_DQUOT_DIRTY_B, &(info)->dqi_flags) #define info_any_dirty(info) (info_dirty(info) || info_any_dquot_dirty(info)) -#define sb_dqopt(sb) (&(sb)->s_dquot) +#define dqh_dqopt(hash) (&(hash)->dqh_dqopt) struct dqstats { int lookups; @@ -198,7 +205,7 @@ struct dqstats { extern struct dqstats dqstats; -#define NR_DQHASH 43 /* Just an arbitrary number */ +#define NR_DQHASH 13 /* Just an arbitrary number */ #define DQ_MOD_B 0 #define DQ_BLKS_B 1 @@ -218,7 +225,7 @@ struct dquot { atomic_t dq_count; /* Use count */ /* fields after this point are cleared when invalidating */ - struct super_block *dq_sb; /* superblock this applies to */ + struct dqhash *dq_dqh; /* quota hash backpointer */ unsigned int dq_id; /* ID this applies to (uid, gid) */ loff_t dq_off; /* Offset of dquot on disk */ unsigned long dq_flags; /* See DQ_* */ @@ -233,12 +240,12 @@ struct dquot { /* Operations which must be implemented by each quota format */ struct quota_format_ops { - int (*check_quota_file)(struct super_block *sb, int type); /* Detect whether file is in our format */ - int (*read_file_info)(struct super_block *sb, int type); /* Read main info about file - called on quotaon() */ - int (*write_file_info)(struct super_block *sb, int type); /* Write main info about file */ - int (*free_file_info)(struct super_block *sb, int type); /* Called on quotaoff() */ - int (*read_dqblk)(struct dquot *dquot); /* Read structure for one user */ - int (*commit_dqblk)(struct dquot *dquot); /* Write (or delete) structure for one user */ + int (*check_quota_file)(struct dqhash *, int); /* Detect whether file is in our format */ + int (*read_file_info)(struct dqhash *, int); /* Read main info about file - called on quotaon() */ + int (*write_file_info)(struct dqhash *, int); /* Write main info about file */ + int (*free_file_info)(struct dqhash *, int); /* Called on quotaoff() */ + int (*read_dqblk)(struct dquot *); /* Read structure for one user */ + int (*commit_dqblk)(struct dquot *); /* Write (or delete) structure for one user */ }; /* Operations working with dquots */ @@ -255,17 +262,17 @@ struct dquot_operations { /* Operations handling requests from userspace */ struct quotactl_ops { - int (*quota_on)(struct super_block *, int, int, char *); - int (*quota_off)(struct super_block *, int); - int (*quota_sync)(struct super_block *, int); - int (*get_info)(struct super_block *, int, struct if_dqinfo *); - int (*set_info)(struct super_block *, int, struct if_dqinfo *); - int (*get_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *); - int (*set_dqblk)(struct super_block *, int, qid_t, struct if_dqblk *); - int (*get_xstate)(struct super_block *, struct fs_quota_stat *); - int (*set_xstate)(struct super_block *, unsigned int, int); - int (*get_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *); - int (*set_xquota)(struct super_block *, int, qid_t, struct fs_disk_quota *); + int (*quota_on)(struct dqhash *, int, int, char *); + int (*quota_off)(struct dqhash *, int); + int (*quota_sync)(struct dqhash *, int); + int (*get_info)(struct dqhash *, int, struct if_dqinfo *); + int (*set_info)(struct dqhash *, int, struct if_dqinfo *); + int (*get_dqblk)(struct dqhash *, int, qid_t, struct if_dqblk *); + int (*set_dqblk)(struct dqhash *, int, qid_t, struct if_dqblk *); + int (*get_xstate)(struct dqhash *, struct fs_quota_stat *); + int (*set_xstate)(struct dqhash *, unsigned int, int); + int (*get_xquota)(struct dqhash *, int, qid_t, struct fs_disk_quota *); + int (*set_xquota)(struct dqhash *, int, qid_t, struct fs_disk_quota *); }; struct quota_format_type { @@ -288,19 +295,13 @@ struct quota_info { struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */ }; -/* Inline would be better but we need to dereference super_block which is not defined yet */ -#define mark_dquot_dirty(dquot) do {\ - set_bit(DQF_ANY_DQUOT_DIRTY_B, &(sb_dqopt((dquot)->dq_sb)->info[(dquot)->dq_type].dqi_flags));\ - set_bit(DQ_MOD_B, &(dquot)->dq_flags);\ -} while (0) - #define dquot_dirty(dquot) test_bit(DQ_MOD_B, &(dquot)->dq_flags) -#define sb_has_quota_enabled(sb, type) ((type)==USRQUOTA ? \ - (sb_dqopt(sb)->flags & DQUOT_USR_ENABLED) : (sb_dqopt(sb)->flags & DQUOT_GRP_ENABLED)) +#define dqh_has_quota_enabled(hash, type) (dqhash_valid(hash) && ((type)==USRQUOTA ? \ + (dqh_dqopt(hash)->flags & DQUOT_USR_ENABLED) : (dqh_dqopt(hash)->flags & DQUOT_GRP_ENABLED))) -#define sb_any_quota_enabled(sb) (sb_has_quota_enabled(sb, USRQUOTA) | \ - sb_has_quota_enabled(sb, GRPQUOTA)) +#define dqh_any_quota_enabled(hash) (dqhash_valid(hash) && \ + (dqh_has_quota_enabled(hash, USRQUOTA) || dqh_has_quota_enabled(hash, GRPQUOTA))) int register_quota_format(struct quota_format_type *fmt); void unregister_quota_format(struct quota_format_type *fmt); @@ -315,6 +316,55 @@ struct quota_module_name { {QFMT_VFS_OLD, "quota_v1"},\ {QFMT_VFS_V0, "quota_v2"},\ {0, NULL}} + +struct dqhash { + struct list_head dqh_list; /* List of all quota hashes */ + unsigned int dqh_id; /* ID for hash */ + atomic_t dqh_count; /* Use count */ + struct quota_info dqh_dqopt; /* Diskquota specific options */ + struct dquot_operations *dqh_qop; + struct quotactl_ops *dqh_qcop; + struct super_block *dqh_sb; /* super block */ + struct list_head dqh_hash[NR_DQHASH]; +}; + +#if defined(CONFIG_QUOTA) + + +struct dqhash *new_dqhash(struct super_block *, unsigned int); +void destroy_dqhash(struct dqhash *); +struct dqhash *find_dqhash(unsigned int); + +static inline void dqhput(struct dqhash *hash) +{ + if (dqhash_valid(hash)) + if (atomic_dec_and_test(&hash->dqh_count)) + destroy_dqhash(hash); +} + +static inline struct dqhash *dqhget(struct dqhash *hash) +{ + if (dqhash_valid(hash)) + atomic_inc(&hash->dqh_count); + return hash; +} + +static inline void mark_dquot_dirty(struct dquot *dq) +{ + dq->dq_flags |= DQ_MOD; + dqh_dqopt(dq->dq_dqh)->info[dq->dq_type].dqi_flags |= DQF_ANY_DQUOT_DIRTY; +} + +#else /* CONFIG_QUOTA */ + +#define new_dqhash(sb, dqdom) (0) +#define find_dqhash(dqdom) (0) +#define destroy_dqhash(hash) do { } while(0) + +#define dqhput(hash) do { } while(0) +#define dqhget(hash) (hash) + +#endif /* CONFIG_QUOTA */ #else diff -NurpP --minimal linux-2.6.0-test9/include/linux/quotaops.h linux-2.6.0-test9-qh0.12/include/linux/quotaops.h --- linux-2.6.0-test9/include/linux/quotaops.h Wed Oct 8 21:24:03 2003 +++ linux-2.6.0-test9-qh0.12/include/linux/quotaops.h Wed Oct 29 20:29:47 2003 @@ -15,6 +15,8 @@ #include +#define dprintk(...) /* printk(__VA_ARGS__) */ + #if defined(CONFIG_QUOTA) /* @@ -44,26 +46,28 @@ extern struct quotactl_ops vfs_quotactl_ static __inline__ void DQUOT_INIT(struct inode *inode) { - if (!inode->i_sb) + if (!dqhash_valid(inode->i_dqh)) + return; + if (!inode->i_dqh) BUG(); - if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) - inode->i_sb->dq_op->initialize(inode, -1); + if (dqh_any_quota_enabled(inode->i_dqh) && !IS_NOQUOTA(inode)) + inode->i_dqh->dqh_qop->initialize(inode, -1); } static __inline__ void DQUOT_DROP(struct inode *inode) { if (IS_QUOTAINIT(inode)) { - if (!inode->i_sb) + if (!inode->i_dqh) BUG(); - inode->i_sb->dq_op->drop(inode); /* Ops must be set when there's any quota... */ + inode->i_dqh->dqh_qop->drop(inode); /* Ops must be set when there's any quota... */ } } static __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { - if (sb_any_quota_enabled(inode->i_sb)) { + if (dqh_any_quota_enabled(inode->i_dqh)) { /* Used space is updated in alloc_space() */ - if (inode->i_sb->dq_op->alloc_space(inode, nr, 1) == NO_QUOTA) + if (inode->i_dqh->dqh_qop->alloc_space(inode, nr, 1) == NO_QUOTA) return 1; } else { @@ -84,9 +88,9 @@ static __inline__ int DQUOT_PREALLOC_SPA static __inline__ int DQUOT_ALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { - if (sb_any_quota_enabled(inode->i_sb)) { + if (dqh_any_quota_enabled(inode->i_dqh)) { /* Used space is updated in alloc_space() */ - if (inode->i_sb->dq_op->alloc_space(inode, nr, 0) == NO_QUOTA) + if (inode->i_dqh->dqh_qop->alloc_space(inode, nr, 0) == NO_QUOTA) return 1; } else { @@ -107,9 +111,9 @@ static __inline__ int DQUOT_ALLOC_SPACE( static __inline__ int DQUOT_ALLOC_INODE(struct inode *inode) { - if (sb_any_quota_enabled(inode->i_sb)) { + if (dqh_any_quota_enabled(inode->i_dqh)) { DQUOT_INIT(inode); - if (inode->i_sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) + if (inode->i_dqh->dqh_qop->alloc_inode(inode, 1) == NO_QUOTA) return 1; } return 0; @@ -117,8 +121,8 @@ static __inline__ int DQUOT_ALLOC_INODE( static __inline__ void DQUOT_FREE_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { - if (sb_any_quota_enabled(inode->i_sb)) - inode->i_sb->dq_op->free_space(inode, nr); + if (dqh_any_quota_enabled(inode->i_dqh)) + inode->i_dqh->dqh_qop->free_space(inode, nr); else { spin_lock(&dq_data_lock); inode_sub_bytes(inode, nr); @@ -134,28 +138,28 @@ static __inline__ void DQUOT_FREE_SPACE( static __inline__ void DQUOT_FREE_INODE(struct inode *inode) { - if (sb_any_quota_enabled(inode->i_sb)) - inode->i_sb->dq_op->free_inode(inode, 1); + if (dqh_any_quota_enabled(inode->i_dqh)) + inode->i_dqh->dqh_qop->free_inode(inode, 1); } static __inline__ int DQUOT_TRANSFER(struct inode *inode, struct iattr *iattr) { - if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) { + if (dqh_any_quota_enabled(inode->i_dqh) && !IS_NOQUOTA(inode)) { DQUOT_INIT(inode); - if (inode->i_sb->dq_op->transfer(inode, iattr) == NO_QUOTA) + if (inode->i_dqh->dqh_qop->transfer(inode, iattr) == NO_QUOTA) return 1; } return 0; } -#define DQUOT_SYNC(sb) sync_dquots(sb, -1) +#define DQUOT_SYNC(hash) sync_dquots(hash, -1) -static __inline__ int DQUOT_OFF(struct super_block *sb) +static __inline__ int DQUOT_OFF(struct dqhash *hash) { int ret = -ENOSYS; - if (sb->s_qcop && sb->s_qcop->quota_off) - ret = sb->s_qcop->quota_off(sb, -1); + if (hash->dqh_qcop && hash->dqh_qcop->quota_off) + ret = hash->dqh_qcop->quota_off(hash, -1); return ret; } @@ -171,8 +175,8 @@ static __inline__ int DQUOT_OFF(struct s #define DQUOT_DROP(inode) do { } while(0) #define DQUOT_ALLOC_INODE(inode) (0) #define DQUOT_FREE_INODE(inode) do { } while(0) -#define DQUOT_SYNC(sb) do { } while(0) -#define DQUOT_OFF(sb) do { } while(0) +#define DQUOT_SYNC(hash) do { } while(0) +#define DQUOT_OFF(hash) do { } while(0) #define DQUOT_TRANSFER(inode, iattr) (0) extern __inline__ int DQUOT_PREALLOC_SPACE_NODIRTY(struct inode *inode, qsize_t nr) { diff -NurpP --minimal linux-2.6.0-test9/include/linux/security.h linux-2.6.0-test9-qh0.12/include/linux/security.h --- linux-2.6.0-test9/include/linux/security.h Wed Oct 8 21:24:26 2003 +++ linux-2.6.0-test9-qh0.12/include/linux/security.h Wed Oct 29 20:29:47 2003 @@ -992,7 +992,7 @@ struct security_operations { int (*acct) (struct file * file); int (*sysctl) (ctl_table * table, int op); int (*capable) (struct task_struct * tsk, int cap); - int (*quotactl) (int cmds, int type, int id, struct super_block * sb); + int (*quotactl) (int cmds, int type, int id, dqhash * hash); int (*quota_on) (struct file * f); int (*syslog) (int type); int (*vm_enough_memory) (long pages); @@ -1230,9 +1230,9 @@ static inline int security_sysctl(ctl_ta } static inline int security_quotactl (int cmds, int type, int id, - struct super_block *sb) + struct dqhash *hash) { - return security_ops->quotactl (cmds, type, id, sb); + return security_ops->quotactl (cmds, type, id, hash); } static inline int security_quota_on (struct file * file) @@ -1896,7 +1896,7 @@ static inline int security_sysctl(ctl_ta } static inline int security_quotactl (int cmds, int type, int id, - struct super_block * sb) + struct dqhash * hash) { return 0; }