📄 quota-deadlock-on-pagelock-core.patch
字号:
/* 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 super_block *sb = dquot->dq_sb;+ struct mem_dqinfo *info = sb_dqopt(sb)->info+dquot->dq_type; uint blk, i; struct v2_disk_dqdbheader *dh; struct v2_disk_dqblk *ddquot;@@ -309,22 +282,23 @@ static uint find_free_dqentry(struct dqu ddquot = GETENTRIES(buf); if (info->u.v2_i.dqi_free_entry) { blk = info->u.v2_i.dqi_free_entry;- if ((*err = read_blk(filp, blk, buf)) < 0)+ if ((*err = read_blk(sb, dquot->dq_type, blk, buf)) < 0) goto out_buf; } else {- blk = get_free_dqblk(filp, dquot->dq_type);+ blk = get_free_dqblk(sb, dquot->dq_type); if ((int)blk < 0) { *err = blk; freedqbuf(buf); return 0; } memset(buf, 0, V2_DQBLKSIZE);- info->u.v2_i.dqi_free_entry = blk; /* This is enough as block is already zeroed and entry list is empty... */- mark_info_dirty(dquot->dq_sb, dquot->dq_type);+ /* This is enough as block is already zeroed and entry list is empty... */+ info->u.v2_i.dqi_free_entry = blk;+ mark_info_dirty(sb, dquot->dq_type); } if (le16_to_cpu(dh->dqdh_entries)+1 >= V2_DQSTRINBLK) /* Block will be full? */- if ((*err = remove_free_dqentry(filp, dquot->dq_type, buf, blk)) < 0) {+ if ((*err = remove_free_dqentry(sb, dquot->dq_type, buf, blk)) < 0) { printk(KERN_ERR "VFS: find_free_dqentry(): Can't remove block (%u) from entry free list.\n", blk); goto out_buf; }@@ -339,7 +313,7 @@ static uint find_free_dqentry(struct dqu goto out_buf; } #endif- if ((*err = write_blk(filp, blk, buf)) < 0) {+ if ((*err = write_blk(sb, dquot->dq_type, blk, buf)) < 0) { printk(KERN_ERR "VFS: find_free_dqentry(): Can't write quota data block %u.\n", blk); goto out_buf; }@@ -354,7 +328,7 @@ 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 super_block *sb = dquot->dq_sb; dqbuf_t buf; int ret = 0, newson = 0, newact = 0; __le32 *ref;@@ -363,7 +337,7 @@ static int do_insert_tree(struct dquot * if (!(buf = getdqbuf())) return -ENOMEM; if (!*treeblk) {- ret = get_free_dqblk(filp, dquot->dq_type);+ ret = get_free_dqblk(sb, dquot->dq_type); if (ret < 0) goto out_buf; *treeblk = ret;@@ -371,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; }@@ -394,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, dquot->dq_type, buf, *treeblk);+ put_free_dqblk(sb, dquot->dq_type, buf, *treeblk); out_buf: freedqbuf(buf); return ret;@@ -416,20 +390,15 @@ 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; /* dq_off is guarded by dqio_sem */ 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; spin_lock(&dq_data_lock); mem2diskdqb(&ddquot, &dquot->dq_dqb, dquot->dq_id); /* Argh... We may need to write structure full of zeroes but that would be@@ -439,10 +408,8 @@ static int v2_write_dquot(struct dquot * if (!memcmp(&empty, &ddquot, sizeof(struct v2_disk_dqblk))) ddquot.dqb_itime = cpu_to_le64(1); spin_unlock(&dq_data_lock);- 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)@@ -458,7 +425,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 super_block *sb = dquot->dq_sb;+ int type = dquot->dq_type; struct v2_disk_dqdbheader *dh; dqbuf_t buf = getdqbuf(); int ret = 0;@@ -466,34 +434,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, dquot->dq_type, buf, blk)) < 0 ||- (ret = put_free_dqblk(filp, dquot->dq_type, 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, dquot->dq_type, 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; } }@@ -506,7 +479,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 super_block *sb = dquot->dq_sb;+ int type = dquot->dq_type; dqbuf_t buf = getdqbuf(); int ret = 0; uint newblk;@@ -514,7 +488,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; }@@ -530,12 +504,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, dquot->dq_type, 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);@@ -555,7 +530,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;@@ -563,27 +537,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;@@ -592,14 +570,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; __le32 *ref = (__le32 *)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; }@@ -625,16 +602,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 || !sb_dqopt(dquot->dq_sb)->files[type]) { printk(KERN_ERR "VFS: Quota invalidated while reading!\n"); return -EIO; }@@ -642,7 +616,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; set_bit(DQ_FAKE_B, &dquot->dq_flags); memset(&dquot->dq_dqb, 0, sizeof(struct mem_dqblk));@@ -650,12 +625,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 {@@ -666,7 +642,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); if (!dquot->dq_dqb.dqb_bhardlimit && !dquot->dq_dqb.dqb_bsoftlimit &&diff -rup RH_2_6_9_55.orig/include/linux/fs.h RH_2_6_9_55/include/linux/fs.h--- RH_2_6_9_55.orig/include/linux/fs.h+++ RH_2_6_9_55/include/linux/fs.h@@ -1042,6 +1042,9 @@ struct super_operations { void (*umount_lustre) (struct super_block *); int (*show_options)(struct seq_file *, struct vfsmount *);++ ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);+ ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t); }; /* Inode state bits. Protected by inode_lock. */diff -rup RH_2_6_9_55.orig/include/linux/quota.h RH_2_6_9_55/include/linux/quota.h--- RH_2_6_9_55.orig/include/linux/quota.h+++ RH_2_6_9_55/include/linux/quota.h@@ -285,7 +285,7 @@ struct quota_info { struct semaphore dqio_sem; /* lock device while I/O in progress */ struct semaphore dqonoff_sem; /* Serialize quotaon & quotaoff */ struct rw_semaphore dqptr_sem; /* serialize ops using quota_info struct, pointers from inode to dquots */- struct file *files[MAXQUOTAS]; /* fp's to quotafiles */+ struct inode *files[MAXQUOTAS]; /* inodes of quotafiles */ struct mem_dqinfo info[MAXQUOTAS]; /* Information for each quota type */ struct quota_format_ops *ops[MAXQUOTAS]; /* Operations for each type */ };diff -rup RH_2_6_9_55.orig/include/linux/security.h RH_2_6_9_55/include/linux/security.h--- RH_2_6_9_55.orig/include/linux/security.h+++ RH_2_6_9_55/include/linux/security.h@@ -1033,7 +1033,7 @@ struct security_operations { 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 (*quota_on) (struct file * f);+ int (*quota_on) (struct dentry * dentry); int (*syslog) (int type); int (*vm_enough_memory) (long pages);@@ -1281,9 +1281,9 @@ static inline int security_quotactl (int return security_ops->quotactl (cmds, type, id, sb); } -static inline int security_quota_on (struct file * file)+static inline int security_quota_on (struct dentry * dentry) {- return security_ops->quota_on (file);+ return security_ops->quota_on (dentry); } static inline int security_syslog(int type)@@ -1953,7 +1953,7 @@ static inline int security_quotactl (int return 0; } -static inline int security_quota_on (struct file * file)+static inline int security_quota_on (struct dentry * dentry) { return 0; }diff -rup RH_2_6_9_55.orig/security/dummy.c RH_2_6_9_55/security/dummy.c--- RH_2_6_9_55.orig/security/dummy.c+++ RH_2_6_9_55/security/dummy.c@@ -92,7 +92,7 @@ static int dummy_quotactl (int cmds, int return 0; } -static int dummy_quota_on (struct file *f)+static int dummy_quota_on (struct dentry *dentry) { return 0; }diff -rup RH_2_6_9_55.orig/security/selinux/hooks.c RH_2_6_9_55/security/selinux/hooks.c--- RH_2_6_9_55.orig/security/selinux/hooks.c+++ RH_2_6_9_55/security/selinux/hooks.c@@ -1485,9 +1485,9 @@ static int selinux_quotactl(int cmds, in return rc; } -static int selinux_quota_on(struct file *f)+static int selinux_quota_on(struct dentry *dentry) {- return file_has_perm(current, f, FILE__QUOTAON);+ return dentry_has_perm(current, NULL, dentry, FILE__QUOTAON); } static int selinux_syslog(int type)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -