📄 2.6.5-quotafix.patch
字号:
int ret = 0, newson = 0, newact = 0; u32 *ref;@@ -358,7 +337,7 @@ static int do_insert_tree(struct dquot * if (!(buf = getdqbuf())) return -ENOMEM; if (!*treeblk) {- ret = get_free_dqblk(filp, info);+ ret = get_free_dqblk(sb, dquot->dq_type); if (ret < 0) goto out_buf; *treeblk = ret;@@ -366,7 +345,7 @@ static int do_insert_tree(struct dquot * newact = 1; } else {- if ((ret = read_blk(filp, *treeblk, buf)) < 0) {+ if ((ret = read_blk(sb, dquot->dq_type, *treeblk, buf)) < 0) { printk(KERN_ERR "VFS: Can't read tree quota block %u.\n", *treeblk); goto out_buf; }@@ -389,10 +368,10 @@ static int do_insert_tree(struct dquot * ret = do_insert_tree(dquot, &newblk, depth+1); if (newson && ret >= 0) { ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(newblk);- ret = write_blk(filp, *treeblk, buf);+ ret = write_blk(sb, dquot->dq_type, *treeblk, buf); } else if (newact && ret < 0)- put_free_dqblk(filp, info, buf, *treeblk);+ put_free_dqblk(sb, dquot->dq_type, buf, *treeblk); out_buf: freedqbuf(buf); return ret;@@ -411,19 +390,14 @@ static inline int dq_insert_tree(struct static int v2_write_dquot(struct dquot *dquot) { int type = dquot->dq_type;- struct file *filp;- mm_segment_t fs;- loff_t offset; ssize_t ret; struct v2_disk_dqblk ddquot, empty; if (!dquot->dq_off) if ((ret = dq_insert_tree(dquot)) < 0) {- printk(KERN_ERR "VFS: Error %Zd occurred while creating quota.\n", ret);+ printk(KERN_ERR "VFS: Error %d occurred while creating quota.\n", ret); return ret; }- filp = sb_dqopt(dquot->dq_sb)->files[type];- offset = dquot->dq_off; mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id); /* Argh... We may need to write structure full of zeroes but that would be * treated as an empty place by the rest of the code. Format change would@@ -431,10 +405,10 @@ static int v2_write_dquot(struct dquot * memset(&empty, 0, sizeof(struct v2_disk_dqblk)); if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk))) ddquot.dqb_itime = cpu_to_le64(1);- fs = get_fs();- set_fs(KERNEL_DS);- ret = filp->f_op->write(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset);- set_fs(fs);+ + ret = dquot->dq_sb->s_op->quota_write(dquot->dq_sb, type,+ (char *)&ddquot, sizeof(struct v2_disk_dqblk), dquot->dq_off);+ if (ret != sizeof(struct v2_disk_dqblk)) { printk(KERN_WARNING "VFS: dquota write failed on dev %s\n", dquot->dq_sb->s_id); if (ret >= 0)@@ -450,8 +424,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 super_block *sb = dquot->dq_sb;+ int type = dquot->dq_type; struct v2_disk_dqdbheader *dh; dqbuf_t buf = getdqbuf(); int ret = 0;@@ -459,34 +433,39 @@ static int free_dqentry(struct dquot *dq if (!buf) return -ENOMEM; if (dquot->dq_off >> V2_DQBLKSIZE_BITS != blk) {- printk(KERN_ERR "VFS: Quota structure has offset to other block (%u) than it should (%u).\n", blk, (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS));+ printk(KERN_ERR "VFS: Quota structure has offset to other "+ "block (%u) than it should (%u).\n", blk,+ (uint)(dquot->dq_off >> V2_DQBLKSIZE_BITS)); goto out_buf; }- if ((ret = read_blk(filp, blk, buf)) < 0) {+ if ((ret = read_blk(sb, type, blk, buf)) < 0) { printk(KERN_ERR "VFS: Can't read quota data block %u\n", blk); goto out_buf; } dh = (struct v2_disk_dqdbheader *)buf; dh->dqdh_entries = cpu_to_le16(le16_to_cpu(dh->dqdh_entries)-1); if (!le16_to_cpu(dh->dqdh_entries)) { /* Block got free? */- if ((ret = remove_free_dqentry(filp, info, buf, blk)) < 0 ||- (ret = put_free_dqblk(filp, info, buf, blk)) < 0) {- printk(KERN_ERR "VFS: Can't move quota data block (%u) to free list.\n", blk);+ if ((ret = remove_free_dqentry(sb, type, buf, blk)) < 0 ||+ (ret = put_free_dqblk(sb, type, buf, blk)) < 0) {+ printk(KERN_ERR "VFS: Can't move quota data block (%u) "+ "to free list.\n", blk); goto out_buf; } } else {- memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0, sizeof(struct v2_disk_dqblk));+ memset(buf+(dquot->dq_off & ((1 << V2_DQBLKSIZE_BITS)-1)), 0, + sizeof(struct v2_disk_dqblk)); if (le16_to_cpu(dh->dqdh_entries) == V2_DQSTRINBLK-1) { /* Insert will write block itself */- if ((ret = insert_free_dqentry(filp, info, buf, blk)) < 0) {+ if ((ret = insert_free_dqentry(sb, type, buf, blk)) < 0) { printk(KERN_ERR "VFS: Can't insert quota data block (%u) to free entry list.\n", blk); goto out_buf; } } else- if ((ret = write_blk(filp, blk, buf)) < 0) {- printk(KERN_ERR "VFS: Can't write quota data block %u\n", blk);+ if ((ret = write_blk(sb, type, blk, buf)) < 0) {+ printk(KERN_ERR "VFS: Can't write quota data "+ "block %u\n", blk); goto out_buf; } }@@ -499,8 +478,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 super_block *sb = dquot->dq_sb;+ int type = dquot->dq_type; dqbuf_t buf = getdqbuf(); int ret = 0; uint newblk;@@ -508,7 +487,7 @@ static int remove_tree(struct dquot *dqu if (!buf) return -ENOMEM;- if ((ret = read_blk(filp, *blk, buf)) < 0) {+ if ((ret = read_blk(sb, type, *blk, buf)) < 0) { printk(KERN_ERR "VFS: Can't read quota data block %u\n", *blk); goto out_buf; }@@ -524,12 +503,13 @@ static int remove_tree(struct dquot *dqu ref[GETIDINDEX(dquot->dq_id, depth)] = cpu_to_le32(0); for (i = 0; i < V2_DQBLKSIZE && !buf[i]; i++); /* Block got empty? */ if (i == V2_DQBLKSIZE) {- put_free_dqblk(filp, info, buf, *blk);+ put_free_dqblk(sb, type, buf, *blk); *blk = 0; } else- if ((ret = write_blk(filp, *blk, buf)) < 0)- printk(KERN_ERR "VFS: Can't write quota tree block %u.\n", *blk);+ if ((ret = write_blk(sb, type, *blk, buf)) < 0)+ printk(KERN_ERR "VFS: Can't write quota tree "+ "block %u.\n", *blk); } out_buf: freedqbuf(buf);@@ -549,7 +529,6 @@ 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]; dqbuf_t buf = getdqbuf(); loff_t ret = 0; int i;@@ -557,27 +536,31 @@ static loff_t find_block_dqentry(struct if (!buf) return -ENOMEM;- if ((ret = read_blk(filp, blk, buf)) < 0) {+ if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) { printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); goto out_buf; } if (dquot->dq_id)- for (i = 0; i < V2_DQSTRINBLK && le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++);+ for (i = 0; i < V2_DQSTRINBLK &&+ le32_to_cpu(ddquot[i].dqb_id) != dquot->dq_id; i++); else { /* ID 0 as a bit more complicated searching... */ struct v2_disk_dqblk fakedquot; memset(&fakedquot, 0, sizeof(struct v2_disk_dqblk)); for (i = 0; i < V2_DQSTRINBLK; i++)- if (!le32_to_cpu(ddquot[i].dqb_id) && memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk)))+ if (!le32_to_cpu(ddquot[i].dqb_id) &&+ memcmp(&fakedquot, ddquot+i, sizeof(struct v2_disk_dqblk))) break; } if (i == V2_DQSTRINBLK) {- printk(KERN_ERR "VFS: Quota for id %u referenced but not present.\n", dquot->dq_id);+ printk(KERN_ERR "VFS: Quota for id %u referenced "+ "but not present.\n", dquot->dq_id); ret = -EIO; goto out_buf; } else- ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk);+ ret = (blk << V2_DQBLKSIZE_BITS) + sizeof(struct+ v2_disk_dqdbheader) + i * sizeof(struct v2_disk_dqblk); out_buf: freedqbuf(buf); return ret;@@ -586,14 +569,13 @@ 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]; dqbuf_t buf = getdqbuf(); loff_t ret = 0; u32 *ref = (u32 *)buf; if (!buf) return -ENOMEM;- if ((ret = read_blk(filp, blk, buf)) < 0) {+ if ((ret = read_blk(dquot->dq_sb, dquot->dq_type, blk, buf)) < 0) { printk(KERN_ERR "VFS: Can't read quota tree block %u.\n", blk); goto out_buf; }@@ -619,16 +601,13 @@ static inline loff_t find_dqentry(struct static int v2_read_dquot(struct dquot *dquot) { int type = dquot->dq_type;- struct file *filp;- mm_segment_t fs; loff_t offset; struct v2_disk_dqblk ddquot, empty; int ret = 0; - filp = sb_dqopt(dquot->dq_sb)->files[type];- #ifdef __QUOTA_V2_PARANOIA- if (!filp || !dquot->dq_sb) { /* Invalidated quota? */+ /* Invalidated quota? */+ if (!dquot->dq_sb || !dquot->dq_sb->s_op->quota_read) { printk(KERN_ERR "VFS: Quota invalidated while reading!\n"); return -EIO; }@@ -636,7 +615,8 @@ static int v2_read_dquot(struct dquot *d offset = find_dqentry(dquot); if (offset <= 0) { /* Entry not present? */ if (offset < 0)- printk(KERN_ERR "VFS: Can't read quota structure for id %u.\n", dquot->dq_id);+ printk(KERN_ERR "VFS: Can't read quota "+ "structure for id %u.\n", dquot->dq_id); dquot->dq_off = 0; dquot->dq_flags |= DQ_FAKE; memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));@@ -644,12 +624,13 @@ static int v2_read_dquot(struct dquot *d } else { dquot->dq_off = offset;- fs = get_fs();- set_fs(KERNEL_DS);- if ((ret = filp->f_op->read(filp, (char *)&ddquot, sizeof(struct v2_disk_dqblk), &offset)) != sizeof(struct v2_disk_dqblk)) {+ if ((ret = dquot->dq_sb->s_op->quota_read(dquot->dq_sb, type,+ (char *)&ddquot, sizeof(struct v2_disk_dqblk), offset))+ != sizeof(struct v2_disk_dqblk)) { if (ret >= 0) ret = -EIO;- printk(KERN_ERR "VFS: Error while reading quota structure for id %u.\n", dquot->dq_id);+ printk(KERN_ERR "VFS: Error while reading quota "+ "structure for id %u.\n", dquot->dq_id); memset(&ddquot, 0, sizeof(struct v2_disk_dqblk)); } else {@@ -660,7 +641,6 @@ static int v2_read_dquot(struct dquot *d if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk))) ddquot.dqb_itime = 0; }- set_fs(fs); disk2memdqb(&dquot->dq_dqb, &ddquot); } dqstats.reads++;@@ -668,15 +648,13 @@ static int v2_read_dquot(struct dquot *d return ret; } -/* Commit changes of dquot to disk - it might also mean deleting it when quota became fake one and user has no blocks... */-static int v2_commit_dquot(struct dquot *dquot)+/* Check whether dquot should not be deleted. We know we are+ * * the only one operating on dquot (thanks to dq_lock) */+static int v2_release_dquot(struct dquot *dquot) {- /* We clear the flag everytime so we don't loop when there was an IO error... */- dquot->dq_flags &= ~DQ_MOD;- if (dquot->dq_flags & DQ_FAKE && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace))+ if (test_bit(DQ_FAKE_B, &dquot->dq_flags) && !(dquot->dq_dqb.dqb_curinodes | dquot->dq_dqb.dqb_curspace)) return v2_delete_dquot(dquot);- else- return v2_write_dquot(dquot);+ return 0; } static struct quota_format_ops v2_format_ops = {@@ -685,7 +663,8 @@ static struct quota_format_ops v2_format .write_file_info = v2_write_file_info, .free_file_info = NULL, .read_dqblk = v2_read_dquot,- .commit_dqblk = v2_commit_dquot,+ .commit_dqblk = v2_write_dquot,+ .release_dqblk = v2_release_dquot, }; static struct quota_format_type v2_quota_format = {Index: linux-2.6.5-7.283/fs/quota.c===================================================================--- linux-2.6.5-7.283.orig/fs/quota.c+++ linux-2.6.5-7.283/fs/quota.c@@ -14,6 +14,9 @@ #include <linux/smp_lock.h> #include <linux/security.h> #include <linux/audit.h>+#include <linux/syscalls.h>+#include <linux/buffer_head.h>+ /* Check validity of quotactl */ static int check_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id)@@ -134,16 +137,54 @@ restart: return NULL; } +void quota_sync_sb(struct super_block *sb, int type)+{+ int cnt;+ struct inode *discard[MAXQUOTAS];++ sb->s_qcop->quota_sync(sb, type);+ /* This is not very clever (and fast) but currently I don't know about+ * any other simple way of getting quota data to disk and we must get+ * them there for userspace to be visible... */+ if (sb->s_op->sync_fs)+ sb->s_op->sync_fs(sb, 1);+ sync_blockdev(sb->s_bdev);++ /* Now when everything is written we can discard the pagecache so+ * that userspace sees the changes. We need i_sem and so we could+ * not do it inside dqonoff_sem. Moreover we need to be carefull+ * about races with quotaoff() (that is the reason why we have own+ * reference to inode). */+ down(&sb_dqopt(sb)->dqonoff_sem);+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {+ discard[cnt] = NULL;+ if (type != -1 && cnt != type)+ continue;+ if (!sb_has_quota_enabled(sb, cnt))+ continue;+ discard[cnt] = igrab(sb_dqopt(sb)->files[cnt]);+ }+ up(&sb_dqopt(sb)->dqonoff_sem);+ for (cnt = 0; cnt < MAXQUOTAS; cnt++) {+ if (discard[cnt]) {+ down(&discard[cnt]->i_sem);+ truncate_inode_pages(&discard[cnt]->i_data, 0);+ up(&discard[cnt]->i_sem);+ iput(discard[cnt]);+ }+ }+}+ void sync_dquots(struct super_block *sb, int type) { if (sb) { if (sb->s_qcop->quota_sync)- sb->s_qcop->quota_sync(sb, type);+ quota_sync_sb(sb, type); } else {- while ((sb = get_super_to_sync(type))) {+ while ((sb = get_super_to_sync(type)) != NULL) { if (sb->s_qcop->quota_sync)- sb->s_qcop->quota_sync(sb, type);+ quota_sync_sb(sb, type); drop_super(sb); } }Index: linux-2.6.5-7.283/fs/ext3/inode.c===================================================================--- linux-2.6.5-7.283.orig/fs/ext3/inode.c+++ linux-2.6.5-7.283/fs/ext3/inode.c@@ -1015,7 +1015,7 @@ out: return ret; } -static int+int ext3_journal_dirty_data(handle_t *handle, struct buffer_head *bh) { int err = journal_dirty_data(handle, bh);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -