patch-2.2.14 linux/fs/dquot.c
Next file: linux/fs/ext2/balloc.c
Previous file: linux/fs/devices.c
Back to the patch index
Back to the overall index
- Lines: 183
- Date:
Tue Jan 4 10:12:23 2000
- Orig file:
v2.2.13/linux/fs/dquot.c
- Orig date:
Tue Jan 4 11:10:39 2000
diff -u --recursive --new-file v2.2.13/linux/fs/dquot.c linux/fs/dquot.c
@@ -31,6 +31,9 @@
* add_dquot_ref() restarts after blocking
* Added check for bogus uid and fixed check for group in quotactl.
* Jan Kara, <jack@atrey.karlin.mff.cuni.cz>, 4-6/99
+ * Definitely (hopefully) fixed deadlock in write_dquot(). We no
+ * longer account quota files.
+ * Jan Kara, <jack@suse.cz>, 11/99, sposored by SuSE CR
*
* (C) Copyright 1994 - 1997 Marco van Wieringen
*/
@@ -245,6 +248,9 @@
wake_up(&dquot->dq_wait);
}
+/*
+ * We don't have to be afraid of deadlocks as we never have quotas on quota files...
+ */
static void write_dquot(struct dquot *dquot)
{
short type = dquot->dq_type;
@@ -252,20 +258,14 @@
mm_segment_t fs;
loff_t offset;
ssize_t ret;
- struct dqblk data;
struct semaphore *sem = &dquot->dq_mnt->mnt_dquot.dqio_sem;
- /*
- * We copy our data to preserve consistency when dquot is not locked.
- * We can't lock it because it can cause deadlocks - think about
- * growing the quota file...
- */
- memcpy(&data, &dquot->dq_dqb, sizeof(struct dqblk));
- down(sem);
+ lock_dquot(dquot);
if (!dquot->dq_mnt) { /* Invalidated quota? */
- up(sem);
+ unlock_dquot(dquot);
return;
}
+ down(sem);
filp = dquot->dq_mnt->mnt_dquot.files[type];
offset = dqoff(dquot->dq_id);
fs = get_fs();
@@ -278,18 +278,15 @@
dquot->dq_flags &= ~DQ_MOD;
ret = 0;
if (filp)
- ret = filp->f_op->write(filp, (char *)&data,
+ ret = filp->f_op->write(filp, (char *)&dquot->dq_dqb,
sizeof(struct dqblk), &offset);
if (ret != sizeof(struct dqblk))
printk(KERN_WARNING "VFS: dquota write failed on dev %s\n",
kdevname(dquot->dq_dev));
- /*
- * Be sure that anybody didn't invalidated the dquot in the mean time...
- * Nasty but I don't see other choice when we don't want to lock dquot.
- */
- up(sem);
set_fs(fs);
+ up(sem);
+ unlock_dquot(dquot);
dqstats.writes++;
}
@@ -572,10 +569,9 @@
/*
* Try pruning the dcache to free up some dquots ...
*/
- count = select_dcache(128, 0);
- if (count) {
- printk(KERN_DEBUG "get_empty_dquot: pruning %d\n", count);
- prune_dcache(count);
+ printk(KERN_DEBUG "get_empty_dquot: pruning %d\n", count);
+ if (prune_dcache(0, 128))
+ {
free_inode_memory(count);
goto repeat;
}
@@ -652,12 +648,31 @@
return dquot;
}
+/* Check whether this inode is quota file */
+static inline int is_quotafile(struct inode *inode)
+{
+ int cnt;
+ struct vfsmount *vfsmnt;
+ struct file **files;
+
+ vfsmnt = lookup_vfsmnt(inode->i_dev);
+ if (!vfsmnt)
+ return 0;
+ files = vfsmnt->mnt_dquot.files;
+ for (cnt = 0; cnt < MAXQUOTAS; cnt++)
+ if (files[cnt] && files[cnt]->f_dentry->d_inode == inode)
+ return 1;
+ return 0;
+}
+
static int dqinit_needed(struct inode *inode, short type)
{
int cnt;
if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || S_ISLNK(inode->i_mode)))
return 0;
+ if (is_quotafile(inode))
+ return 0;
if (type != -1)
return inode->i_dquot[type] == NODQUOT;
for (cnt = 0; cnt < MAXQUOTAS; cnt++)
@@ -717,7 +732,7 @@
}
inode->i_flags &= ~S_QUOTA;
put_it:
- if (dquot != NODQUOT)
+ if (dquot != NODQUOT) {
if (dqput_blocks(dquot)) {
spin_unlock(&inode_lock); /* We may block so drop the lock... */
dqput(dquot);
@@ -727,6 +742,8 @@
}
else
dqput(dquot); /* dqput() won't block so we can hold locks... */
+ }
+
return 0;
}
@@ -1070,6 +1087,9 @@
if (S_ISREG(inode->i_mode) ||
S_ISDIR(inode->i_mode) ||
S_ISLNK(inode->i_mode)) {
+ /* We don't want to have quotas on quota files - nasty deadlocks possible */
+ if (is_quotafile(inode))
+ return;
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
if (type != -1 && cnt != type)
continue;
@@ -1341,7 +1361,6 @@
dquot_incr_blocks(transfer_to[cnt], blocks);
unlock_dquot(transfer_from[cnt]);
- dqput(transfer_from[cnt]);
if (inode->i_dquot[cnt] != NODQUOT) {
struct dquot *temp = inode->i_dquot[cnt];
inode->i_dquot[cnt] = transfer_to[cnt];
@@ -1351,20 +1370,20 @@
unlock_dquot(transfer_to[cnt]);
dqput(transfer_to[cnt]);
}
+ dqput(transfer_from[cnt]);
}
return 0;
put_all:
for (disc = 0; disc < cnt; disc++) {
/* There should be none or both pointers set but... */
- if (transfer_to[disc] != NODQUOT) {
+ if (transfer_to[disc] != NODQUOT)
unlock_dquot(transfer_to[disc]);
- dqput(transfer_to[disc]);
- }
- if (transfer_from[disc] != NODQUOT) {
+ if (transfer_from[disc] != NODQUOT)
unlock_dquot(transfer_from[disc]);
- dqput(transfer_from[disc]);
- }
+ /* dqput() tests for NODQUOT itself... */
+ dqput(transfer_from[disc]);
+ dqput(transfer_to[disc]);
}
return error;
}
@@ -1513,6 +1532,7 @@
error = -EINVAL;
if (inode->i_size == 0 || (inode->i_size % sizeof(struct dqblk)) != 0)
goto out_f;
+ dquot_drop(inode); /* We don't want quota on quota files */
set_enable_flags(vfsmnt, type);
mnt_dquot->files[type] = f;
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)