===== fs/dquot.c 1.23 vs edited ===== --- 1.23/fs/dquot.c Tue Feb 12 00:52:32 2002 +++ edited/fs/dquot.c Mon Feb 25 20:05:57 2002 @@ -117,6 +117,8 @@ static struct dqstats dqstats; +spinlock_t dquot_lock; + static void dqput(struct dquot *); static struct dquot *dqduplicate(struct dquot *); @@ -271,8 +273,12 @@ struct semaphore *sem = &dquot->dq_sb->s_dquot.dqio_sem; struct dqblk dqbuf; - down(sem); filp = dquot->dq_sb->s_dquot.files[type]; + if(filp == (struct file *)NULL) + return; + spin_unlock(&dquot_lock); + + down(sem); offset = dqoff(dquot->dq_id); fs = get_fs(); set_fs(KERNEL_DS); @@ -282,10 +288,11 @@ * so we don't loop forever on failure. */ memcpy(&dqbuf, &dquot->dq_dqb, sizeof(struct dqblk)); + spin_lock(&dquot_lock); dquot->dq_flags &= ~DQ_MOD; + spin_unlock(&dquot_lock); ret = 0; - if (filp) - ret = filp->f_op->write(filp, (char *)&dqbuf, + ret = filp->f_op->write(filp, (char *)&dqbuf, sizeof(struct dqblk), &offset); if (ret != sizeof(struct dqblk)) printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", @@ -293,6 +300,7 @@ set_fs(fs); up(sem); + spin_lock(&dquot_lock); dqstats.writes++; } @@ -307,6 +315,7 @@ if (filp == (struct file *)NULL) return; + spin_unlock(&dquot_lock); lock_dquot(dquot); if (!dquot->dq_sb) /* Invalidated quota? */ goto out_lock; @@ -319,10 +328,12 @@ up(&dquot->dq_sb->s_dquot.dqio_sem); set_fs(fs); + spin_lock(&dquot_lock); if (dquot->dq_bhardlimit == 0 && dquot->dq_bsoftlimit == 0 && dquot->dq_ihardlimit == 0 && dquot->dq_isoftlimit == 0) dquot->dq_flags |= DQ_FAKE; dqstats.reads++; + spin_unlock(&dquot_lock); out_lock: unlock_dquot(dquot); } @@ -343,18 +354,23 @@ if (dquot->dq_type != type) continue; dquot->dq_flags |= DQ_INVAL; - if (dquot->dq_count) + if (dquot->dq_count) { + spin_unlock(&dquot_lock); /* * Wait for any users of quota. As we have already cleared the flags in * superblock and cleared all pointers from inodes we are assured * that there will be no new users of this quota. */ __wait_dquot_unused(dquot); + spin_lock(&dquot_lock); + } /* Quota now have no users and it has been written on last dqput() */ remove_dquot_hash(dquot); remove_free_dquot(dquot); remove_inuse(dquot); + spin_unlock(&dquot_lock); kmem_cache_free(dquot_cachep, dquot); + spin_lock(&dquot_lock); goto restart; } } @@ -364,7 +380,6 @@ struct list_head *head; struct dquot *dquot; - lock_kernel(); restart: for (head = inuse_list.next; head != &inuse_list; head = head->next) { dquot = list_entry(head, struct dquot, dq_inuse); @@ -378,15 +393,17 @@ continue; /* Raise use count so quota won't be invalidated. We can't use dqduplicate() as it does too many tests */ dquot->dq_count++; - if (dquot->dq_flags & DQ_LOCKED) + if (dquot->dq_flags & DQ_LOCKED) { + spin_unlock(&dquot_lock); wait_on_dquot(dquot); + spin_lock(&dquot_lock); + } if (dquot->dq_flags & DQ_MOD) write_dquot(dquot); dqput(dquot); goto restart; } dqstats.syncs++; - unlock_kernel(); return 0; } @@ -402,7 +419,9 @@ remove_dquot_hash(dquot); remove_free_dquot(dquot); remove_inuse(dquot); + spin_unlock(&dquot_lock); kmem_cache_free(dquot_cachep, dquot); + spin_lock(&dquot_lock); count--; head = free_dquots.prev; } @@ -423,11 +442,10 @@ int shrink_dqcache_memory(int priority, unsigned int gfp_mask) { int count = 0; - - lock_kernel(); + spin_lock(&dquot_lock); count = nr_free_dquots / priority; prune_dqcache(count); - unlock_kernel(); + spin_unlock(&dquot_lock); kmem_cache_shrink(dquot_cachep); return 0; } @@ -468,7 +486,9 @@ /* If dquot is going to be invalidated invalidate_dquots() is going to free it so */ if (!(dquot->dq_flags & DQ_INVAL)) put_dquot_last(dquot); /* Place at end of LRU free queue */ + spin_unlock(&dquot_lock); wake_up(&dquot->dq_wait_free); + spin_lock(&dquot_lock); } static struct dquot *get_empty_dquot(void) @@ -507,8 +527,11 @@ if ((dquot = find_dquot(hashent, sb, id, type)) == NODQUOT) { if (empty == NODQUOT) { - if ((empty = get_empty_dquot()) == NODQUOT) + if ((empty = get_empty_dquot()) == NODQUOT) { + spin_unlock(&dquot_lock); schedule(); /* Try to wait for a moment... */ + spin_lock(&dquot_lock); + } goto we_slept; } dquot = empty; @@ -518,11 +541,14 @@ /* hash it first so it can be found */ insert_dquot_hash(dquot); read_dquot(dquot); + spin_lock(&dquot_lock); } else { if (!dquot->dq_count++) remove_free_dquot(dquot); dqstats.cache_hits++; + spin_unlock(&dquot_lock); wait_on_dquot(dquot); + spin_lock(&dquot_lock); if (empty) dqput(empty); } @@ -576,6 +602,7 @@ if (!sb->dq_op) return; /* nothing to do */ + spin_unlock(&dquot_lock); restart: file_list_lock(); for (p = sb->s_files.next; p != &sb->s_files; p = p->next) { @@ -585,14 +612,17 @@ struct vfsmount *mnt = mntget(filp->f_vfsmnt); struct dentry *dentry = dget(filp->f_dentry); file_list_unlock(); + spin_lock(&dquot_lock); sb->dq_op->initialize(inode, type); dput(dentry); + spin_unlock(&dquot_lock); mntput(mnt); /* As we may have blocked we had better restart... */ goto restart; } } file_list_unlock(); + spin_lock(&dquot_lock); } /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */ @@ -636,7 +666,7 @@ struct list_head *act_head; struct dquot *dquot; - lock_kernel(); + spin_lock(&dquot_lock); act_head = tofree_head->next; /* So now we have dquots on the list... Just free them */ while (act_head != tofree_head) { @@ -646,7 +676,7 @@ INIT_LIST_HEAD(&dquot->dq_free); dqput(dquot); } - unlock_kernel(); + spin_unlock(&dquot_lock); } static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number) @@ -709,18 +739,21 @@ static void print_warning(struct dquot *dquot, const char warntype) { char *msg = NULL; + char *dq_sid = dquot->dq_sb->s_id; + char *dq_type = quotatypes[dquot->dq_type]; int flag = (warntype == BHARDWARN || warntype == BSOFTLONGWARN) ? DQ_BLKS : ((warntype == IHARDWARN || warntype == ISOFTLONGWARN) ? DQ_INODES : 0); if (!need_print_warning(dquot, flag)) return; dquot->dq_flags |= flag; - tty_write_message(current->tty, dquot->dq_sb->s_id); + spin_unlock(&dquot_lock); + tty_write_message(current->tty, dq_sid); if (warntype == ISOFTWARN || warntype == BSOFTWARN) tty_write_message(current->tty, ": warning, "); else tty_write_message(current->tty, ": write failed, "); - tty_write_message(current->tty, quotatypes[dquot->dq_type]); + tty_write_message(current->tty, dq_type); switch (warntype) { case IHARDWARN: msg = " file limit reached.\n"; @@ -742,6 +775,7 @@ break; } tty_write_message(current->tty, msg); + spin_lock(&dquot_lock); } static inline void flush_warnings(struct dquot **dquots, char *warntype) @@ -901,8 +935,10 @@ memcpy(&data, &dquot->dq_dqb, sizeof(struct dqblk)); /* We copy data to preserve them from changing */ dqput(dquot); error = -EFAULT; + spin_unlock(&dquot_lock); if (dqblk && !copy_to_user(dqblk, &data, sizeof(struct dqblk))) error = 0; + spin_lock(&dquot_lock); out: return error; } @@ -917,8 +953,10 @@ /* make a copy, in case we page-fault in user space */ memcpy(&stats, &dqstats, sizeof(struct dqstats)); + spin_unlock(&dquot_lock); if (!copy_to_user(addr, &stats, sizeof(struct dqstats))) error = 0; + spin_lock(&dquot_lock); return error; } @@ -930,10 +968,13 @@ return(-ENODEV); error = -EFAULT; + spin_unlock(&dquot_lock); if (!copy_from_user(&new_value, addr, sizeof(int))) { + spin_lock(&dquot_lock); sb_dqopt(sb)->rsquash[type] = new_value; error = 0; - } + } else + spin_lock(&dquot_lock); return error; } @@ -1039,7 +1080,6 @@ struct dquot *dquot[MAXQUOTAS]; char warntype[MAXQUOTAS]; - lock_kernel(); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { dquot[cnt] = NODQUOT; warntype[cnt] = NOWARN; @@ -1057,7 +1097,9 @@ continue; dquot_incr_blocks(dquot[cnt], number); } + lock_kernel(); inode->i_blocks += number << (BLOCK_SIZE_BITS - 9); + unlock_kernel(); /* NOBLOCK End */ ret = QUOTA_OK; warn_put_all: @@ -1065,7 +1107,6 @@ for (cnt = 0; cnt < MAXQUOTAS; cnt++) if (dquot[cnt] != NODQUOT) dqput(dquot[cnt]); - unlock_kernel(); return ret; } @@ -1083,7 +1124,6 @@ warntype[cnt] = NOWARN; } /* NOBLOCK Start */ - lock_kernel(); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { dquot[cnt] = dqduplicate(inode -> i_dquot[cnt]); if (dquot[cnt] == NODQUOT) @@ -1104,7 +1144,6 @@ for (cnt = 0; cnt < MAXQUOTAS; cnt++) if (dquot[cnt] != NODQUOT) dqput(dquot[cnt]); - unlock_kernel(); return ret; } @@ -1117,7 +1156,6 @@ struct dquot *dquot; /* NOBLOCK Start */ - lock_kernel(); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { dquot = dqduplicate(inode->i_dquot[cnt]); if (dquot == NODQUOT) @@ -1125,6 +1163,7 @@ dquot_decr_blocks(dquot, number); dqput(dquot); } + lock_kernel(); inode->i_blocks -= number << (BLOCK_SIZE_BITS - 9); unlock_kernel(); /* NOBLOCK End */ @@ -1139,7 +1178,6 @@ struct dquot *dquot; /* NOBLOCK Start */ - lock_kernel(); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { dquot = dqduplicate(inode->i_dquot[cnt]); if (dquot == NODQUOT) @@ -1147,7 +1185,6 @@ dquot_decr_inodes(dquot, number); dqput(dquot); } - unlock_kernel(); /* NOBLOCK End */ } @@ -1188,7 +1225,9 @@ } } /* NOBLOCK START: From now on we shouldn't block */ + lock_kernel(); blocks = (inode->i_blocks >> 1); + unlock_kernel(); /* Build the transfer_from list and check the limits */ for (cnt = 0; cnt < MAXQUOTAS; cnt++) { /* The second test can fail when quotaoff is in progress... */ @@ -1244,8 +1283,10 @@ { int i; + spin_lock(&dquot_lock); for (i = 0; i < NR_DQHASH; i++) INIT_LIST_HEAD(dquot_hash + i); + spin_unlock(&dquot_lock); printk(KERN_NOTICE "VFS: Diskquotas version %s initialized\n", __DQUOT_VERSION__); return 0; } @@ -1300,12 +1341,13 @@ short cnt; struct quota_mount_options *dqopt = sb_dqopt(sb); - lock_kernel(); if (!sb) goto out; + spin_unlock(&dquot_lock); /* We need to serialize quota_off() for device */ down(&dqopt->dqoff_sem); + spin_lock(&dquot_lock); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (type != -1 && cnt != type) continue; @@ -1313,19 +1355,22 @@ continue; reset_enable_flags(dqopt, cnt); + spin_unlock(&dquot_lock); /* Note: these are blocking operations */ remove_dquot_ref(sb, cnt); + spin_lock(&dquot_lock); invalidate_dquots(sb, cnt); filp = dqopt->files[cnt]; dqopt->files[cnt] = (struct file *)NULL; dqopt->inode_expire[cnt] = 0; dqopt->block_expire[cnt] = 0; + spin_unlock(&dquot_lock); fput(filp); } up(&dqopt->dqoff_sem); out: - unlock_kernel(); + spin_lock(&dquot_lock); return 0; } @@ -1349,6 +1394,7 @@ if (is_enabled(dqopt, type)) return -EBUSY; + spin_unlock(&dquot_lock); down(&dqopt->dqoff_sem); tmp = getname(path); error = PTR_ERR(tmp); @@ -1372,6 +1418,7 @@ if (inode->i_size == 0 || !check_quotafile_size(inode->i_size)) goto out_f; /* We don't want quota on quota files */ + spin_lock(&dquot_lock); dquot_drop(inode); inode->i_flags |= S_NOQUOTA; @@ -1386,14 +1433,16 @@ add_dquot_ref(sb, type); + spin_unlock(&dquot_lock); up(&dqopt->dqoff_sem); + spin_lock(&dquot_lock); return 0; out_f: filp_close(f, NULL); out_lock: up(&dqopt->dqoff_sem); - + spin_lock(&dquot_lock); return error; } @@ -1410,7 +1459,6 @@ struct super_block *sb = NULL; int ret = -EINVAL; - lock_kernel(); cmds = cmd >> SUBCMDSHIFT; type = cmd & SUBCMDMASK; @@ -1459,6 +1507,7 @@ } ret = -EINVAL; + spin_lock(&dquot_lock); switch (cmds) { case Q_QUOTAON: ret = quota_on(sb, type, (char *) addr); @@ -1494,9 +1543,9 @@ ret = -ENODEV; if (sb && sb_has_quota_enabled(sb, type)) ret = set_dqblk(sb, id, type, flags, (struct dqblk *) addr); + spin_unlock(&dquot_lock); out: if (sb) drop_super(sb); - unlock_kernel(); return ret; } ===== fs/inode.c 1.37 vs edited ===== --- 1.37/fs/inode.c Mon Feb 11 14:26:32 2002 +++ edited/fs/inode.c Mon Feb 25 19:51:57 2002 @@ -1213,6 +1213,7 @@ /* Functions back in dquot.c */ void put_dquot_list(struct list_head *); int remove_inode_dquot_ref(struct inode *, short, struct list_head *); +extern spinlock_t dquot_lock; void remove_dquot_ref(struct super_block *sb, short type) { @@ -1225,6 +1226,7 @@ /* We have to be protected against other CPUs */ lock_kernel(); /* This lock is for quota code */ spin_lock(&inode_lock); /* This lock is for inodes code */ + spin_lock(&dquot_lock); list_for_each(act_head, &inode_in_use) { inode = list_entry(act_head, struct inode, i_list); @@ -1246,6 +1248,7 @@ if (IS_QUOTAINIT(inode)) remove_inode_dquot_ref(inode, type, &tofree_head); } + spin_unlock(&dquot_lock); spin_unlock(&inode_lock); unlock_kernel(); ===== include/linux/quotaops.h 1.7 vs edited ===== --- 1.7/include/linux/quotaops.h Fri Feb 8 22:10:55 2002 +++ edited/include/linux/quotaops.h Mon Feb 25 20:04:35 2002 @@ -33,6 +33,7 @@ extern int dquot_transfer(struct inode *inode, struct iattr *iattr); +extern spinlock_t dquot_lock; /* * Operations supported for diskquotas. */ @@ -42,36 +43,39 @@ { if (!inode->i_sb) BUG(); - lock_kernel(); + spin_lock(&dquot_lock); if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) inode->i_sb->dq_op->initialize(inode, -1); - unlock_kernel(); + spin_unlock(&dquot_lock); } static __inline__ void DQUOT_DROP(struct inode *inode) { - lock_kernel(); + spin_lock(&dquot_lock); if (IS_QUOTAINIT(inode)) { if (!inode->i_sb) BUG(); inode->i_sb->dq_op->drop(inode); /* Ops must be set when there's any quota... */ } - unlock_kernel(); + spin_unlock(&dquot_lock); } static __inline__ int DQUOT_PREALLOC_BLOCK_NODIRTY(struct inode *inode, int nr) { - lock_kernel(); + spin_lock(&dquot_lock); if (sb_any_quota_enabled(inode->i_sb)) { /* Number of used blocks is updated in alloc_block() */ if (inode->i_sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize), 1) == NO_QUOTA) { - unlock_kernel(); + spin_unlock(&dquot_lock); return 1; } } - else + else { + lock_kernel(); inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9); - unlock_kernel(); + unlock_kernel(); + } + spin_unlock(&dquot_lock); return 0; } @@ -85,17 +89,20 @@ static __inline__ int DQUOT_ALLOC_BLOCK_NODIRTY(struct inode *inode, int nr) { - lock_kernel(); + spin_lock(&dquot_lock); if (sb_any_quota_enabled(inode->i_sb)) { /* Number of used blocks is updated in alloc_block() */ if (inode->i_sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize), 0) == NO_QUOTA) { - unlock_kernel(); + spin_unlock(&dquot_lock); return 1; } } - else + else { + lock_kernel(); inode->i_blocks += nr << (inode->i_sb->s_blocksize_bits - 9); - unlock_kernel(); + unlock_kernel(); + } + spin_unlock(&dquot_lock); return 0; } @@ -109,26 +116,31 @@ static __inline__ int DQUOT_ALLOC_INODE(struct inode *inode) { - lock_kernel(); + spin_lock(&dquot_lock); if (sb_any_quota_enabled(inode->i_sb)) { + spin_unlock(&dquot_lock); DQUOT_INIT(inode); + spin_lock(&dquot_lock); if (inode->i_sb->dq_op->alloc_inode(inode, 1) == NO_QUOTA) { - unlock_kernel(); + spin_unlock(&dquot_lock); return 1; } } - unlock_kernel(); + spin_unlock(&dquot_lock); return 0; } static __inline__ void DQUOT_FREE_BLOCK_NODIRTY(struct inode *inode, int nr) { - lock_kernel(); + spin_lock(&dquot_lock); if (sb_any_quota_enabled(inode->i_sb)) inode->i_sb->dq_op->free_block(inode, fs_to_dq_blocks(nr, inode->i_sb->s_blocksize)); - else + else { + lock_kernel(); inode->i_blocks -= nr << (inode->i_sb->s_blocksize_bits - 9); - unlock_kernel(); + unlock_kernel(); + } + spin_unlock(&dquot_lock); } static __inline__ void DQUOT_FREE_BLOCK(struct inode *inode, int nr) @@ -139,23 +151,23 @@ static __inline__ void DQUOT_FREE_INODE(struct inode *inode) { - lock_kernel(); + spin_lock(&dquot_lock); if (sb_any_quota_enabled(inode->i_sb)) inode->i_sb->dq_op->free_inode(inode, 1); - unlock_kernel(); + spin_unlock(&dquot_lock); } static __inline__ int DQUOT_TRANSFER(struct inode *inode, struct iattr *iattr) { - lock_kernel(); + spin_lock(&dquot_lock); if (sb_any_quota_enabled(inode->i_sb) && !IS_NOQUOTA(inode)) { DQUOT_INIT(inode); if (inode->i_sb->dq_op->transfer(inode, iattr) == NO_QUOTA) { - unlock_kernel(); + spin_unlock(&dquot_lock); return 1; } } - unlock_kernel(); + spin_unlock(&dquot_lock); return 0; }