diff options
Diffstat (limited to 'fs/dquot.c')
-rw-r--r-- | fs/dquot.c | 59 |
1 files changed, 39 insertions, 20 deletions
diff --git a/fs/dquot.c b/fs/dquot.c index 0952cc474d9a..9eb166f91489 100644 --- a/fs/dquot.c +++ b/fs/dquot.c | |||
@@ -79,6 +79,7 @@ | |||
79 | #include <linux/buffer_head.h> | 79 | #include <linux/buffer_head.h> |
80 | #include <linux/capability.h> | 80 | #include <linux/capability.h> |
81 | #include <linux/quotaops.h> | 81 | #include <linux/quotaops.h> |
82 | #include <linux/writeback.h> /* for inode_lock, oddly enough.. */ | ||
82 | 83 | ||
83 | #include <asm/uaccess.h> | 84 | #include <asm/uaccess.h> |
84 | 85 | ||
@@ -600,11 +601,10 @@ static struct dquot *get_empty_dquot(struct super_block *sb, int type) | |||
600 | { | 601 | { |
601 | struct dquot *dquot; | 602 | struct dquot *dquot; |
602 | 603 | ||
603 | dquot = kmem_cache_alloc(dquot_cachep, GFP_NOFS); | 604 | dquot = kmem_cache_zalloc(dquot_cachep, GFP_NOFS); |
604 | if(!dquot) | 605 | if(!dquot) |
605 | return NODQUOT; | 606 | return NODQUOT; |
606 | 607 | ||
607 | memset((caddr_t)dquot, 0, sizeof(struct dquot)); | ||
608 | mutex_init(&dquot->dq_lock); | 608 | mutex_init(&dquot->dq_lock); |
609 | INIT_LIST_HEAD(&dquot->dq_free); | 609 | INIT_LIST_HEAD(&dquot->dq_free); |
610 | INIT_LIST_HEAD(&dquot->dq_inuse); | 610 | INIT_LIST_HEAD(&dquot->dq_inuse); |
@@ -688,23 +688,27 @@ static int dqinit_needed(struct inode *inode, int type) | |||
688 | /* This routine is guarded by dqonoff_mutex mutex */ | 688 | /* This routine is guarded by dqonoff_mutex mutex */ |
689 | static void add_dquot_ref(struct super_block *sb, int type) | 689 | static void add_dquot_ref(struct super_block *sb, int type) |
690 | { | 690 | { |
691 | struct list_head *p; | 691 | struct inode *inode; |
692 | 692 | ||
693 | restart: | 693 | restart: |
694 | file_list_lock(); | 694 | spin_lock(&inode_lock); |
695 | list_for_each(p, &sb->s_files) { | 695 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { |
696 | struct file *filp = list_entry(p, struct file, f_u.fu_list); | 696 | if (!atomic_read(&inode->i_writecount)) |
697 | struct inode *inode = filp->f_path.dentry->d_inode; | 697 | continue; |
698 | if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) { | 698 | if (!dqinit_needed(inode, type)) |
699 | struct dentry *dentry = dget(filp->f_path.dentry); | 699 | continue; |
700 | file_list_unlock(); | 700 | if (inode->i_state & (I_FREEING|I_WILL_FREE)) |
701 | sb->dq_op->initialize(inode, type); | 701 | continue; |
702 | dput(dentry); | 702 | |
703 | /* As we may have blocked we had better restart... */ | 703 | __iget(inode); |
704 | goto restart; | 704 | spin_unlock(&inode_lock); |
705 | } | 705 | |
706 | sb->dq_op->initialize(inode, type); | ||
707 | iput(inode); | ||
708 | /* As we may have blocked we had better restart... */ | ||
709 | goto restart; | ||
706 | } | 710 | } |
707 | file_list_unlock(); | 711 | spin_unlock(&inode_lock); |
708 | } | 712 | } |
709 | 713 | ||
710 | /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */ | 714 | /* Return 0 if dqput() won't block (note that 1 doesn't necessarily mean blocking) */ |
@@ -756,15 +760,30 @@ static void put_dquot_list(struct list_head *tofree_head) | |||
756 | } | 760 | } |
757 | } | 761 | } |
758 | 762 | ||
763 | static void remove_dquot_ref(struct super_block *sb, int type, | ||
764 | struct list_head *tofree_head) | ||
765 | { | ||
766 | struct inode *inode; | ||
767 | |||
768 | spin_lock(&inode_lock); | ||
769 | list_for_each_entry(inode, &sb->s_inodes, i_sb_list) { | ||
770 | if (!IS_NOQUOTA(inode)) | ||
771 | remove_inode_dquot_ref(inode, type, tofree_head); | ||
772 | } | ||
773 | spin_unlock(&inode_lock); | ||
774 | } | ||
775 | |||
759 | /* Gather all references from inodes and drop them */ | 776 | /* Gather all references from inodes and drop them */ |
760 | static void drop_dquot_ref(struct super_block *sb, int type) | 777 | static void drop_dquot_ref(struct super_block *sb, int type) |
761 | { | 778 | { |
762 | LIST_HEAD(tofree_head); | 779 | LIST_HEAD(tofree_head); |
763 | 780 | ||
764 | down_write(&sb_dqopt(sb)->dqptr_sem); | 781 | if (sb->dq_op) { |
765 | remove_dquot_ref(sb, type, &tofree_head); | 782 | down_write(&sb_dqopt(sb)->dqptr_sem); |
766 | up_write(&sb_dqopt(sb)->dqptr_sem); | 783 | remove_dquot_ref(sb, type, &tofree_head); |
767 | put_dquot_list(&tofree_head); | 784 | up_write(&sb_dqopt(sb)->dqptr_sem); |
785 | put_dquot_list(&tofree_head); | ||
786 | } | ||
768 | } | 787 | } |
769 | 788 | ||
770 | static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number) | 789 | static inline void dquot_incr_inodes(struct dquot *dquot, unsigned long number) |