Whamcloud - gitweb
Branch HEAD
[fs/lustre-release.git] / lustre / kernel_patches / patches / quota-umount-race-fix.patch
1
2 From: Jan Kara <jack@suse.cz>
3
4 Fix possible races between umount and quota on/off.
5
6 Finally I decided to take a reference to vfsmount during vfs_quota_on() and
7 to drop it after the final cleanup in the vfs_quota_off().  This way we
8 should be all the time guarded against umount.  This way was protected also
9 the old code which used filp_open() for opening quota files.  I was also
10 thinking about other ways of protection but there would be always a window
11 (provided I don't want to play much with namespace locks) where
12 vfs_quota_on() could be called while umount() is in progress resulting in
13 the "Busy inodes after unmount" messages...
14
15 Get a reference to vfsmount during quotaon() so that we are guarded against
16 umount (as was the old code using filp_open()).
17
18 Signed-off-by: Jan Kara <jack@suse.cz>
19 Signed-off-by: Andrew Morton <akpm@osdl.org>
20 ---
21
22  25-akpm/fs/dquot.c               |   45 ++++++++++++++++++++++++++++-----------
23  25-akpm/include/linux/quota.h    |    1 
24  25-akpm/include/linux/quotaops.h |    2 -
25  3 files changed, 35 insertions(+), 13 deletions(-)
26
27 diff -puN fs/dquot.c~quota-umount-race-fix fs/dquot.c
28 --- 25/fs/dquot.c~quota-umount-race-fix Tue Nov 23 17:11:34 2004
29 +++ 25-akpm/fs/dquot.c  Tue Nov 23 17:11:34 2004
30 @@ -1314,12 +1314,14 @@ int vfs_quota_off(struct super_block *sb
31  {
32         int cnt;
33         struct quota_info *dqopt = sb_dqopt(sb);
34 -       struct inode *toput[MAXQUOTAS];
35 +       struct inode *toputinode[MAXQUOTAS];
36 +       struct vfsmount *toputmnt[MAXQUOTAS];
37  
38         /* We need to serialize quota_off() for device */
39         down(&dqopt->dqonoff_sem);
40         for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
41 -               toput[cnt] = NULL;
42 +               toputinode[cnt] = NULL;
43 +               toputmnt[cnt] = NULL;
44                 if (type != -1 && cnt != type)
45                         continue;
46                 if (!sb_has_quota_enabled(sb, cnt))
47 @@ -1339,8 +1341,10 @@ int vfs_quota_off(struct super_block *sb
48                         dqopt->ops[cnt]->free_file_info(sb, cnt);
49                 put_quota_format(dqopt->info[cnt].dqi_format);
50  
51 -               toput[cnt] = dqopt->files[cnt];
52 +               toputinode[cnt] = dqopt->files[cnt];
53 +               toputmnt[cnt] = dqopt->mnt[cnt];
54                 dqopt->files[cnt] = NULL;
55 +               dqopt->mnt[cnt] = NULL;
56                 dqopt->info[cnt].dqi_flags = 0;
57                 dqopt->info[cnt].dqi_igrace = 0;
58                 dqopt->info[cnt].dqi_bgrace = 0;
59 @@ -1348,7 +1352,10 @@ int vfs_quota_off(struct super_block *sb
60         }
61         up(&dqopt->dqonoff_sem);
62         /* Sync the superblock so that buffers with quota data are written to
63 -         * disk (and so userspace sees correct data afterwards) */
64 +        * disk (and so userspace sees correct data afterwards).
65 +        * The reference to vfsmnt we are still holding protects us from
66 +        * umount (we don't have it only when quotas are turned on/off for
67 +        * journal replay but in that case we are guarded by the fs anyway). */
68         if (sb->s_op->sync_fs)
69                 sb->s_op->sync_fs(sb, 1);
70         sync_blockdev(sb->s_bdev);
71 @@ -1358,13 +1365,24 @@ int vfs_quota_off(struct super_block *sb
72          * must also discard the blockdev buffers so that we see the
73          * changes done by userspace on the next quotaon() */
74         for (cnt = 0; cnt < MAXQUOTAS; cnt++)
75 -               if (toput[cnt]) {
76 -                       down(&toput[cnt]->i_sem);
77 -                       toput[cnt]->i_flags &= ~(S_IMMUTABLE | S_NOATIME | S_NOQUOTA);
78 -                       truncate_inode_pages(&toput[cnt]->i_data, 0);
79 -                       up(&toput[cnt]->i_sem);
80 -                       mark_inode_dirty(toput[cnt]);
81 -                       iput(toput[cnt]);
82 +               if (toputinode[cnt]) {
83 +                       down(&dqopt->dqonoff_sem);
84 +                       /* If quota was reenabled in the meantime, we have
85 +                        * nothing to do */
86 +                       if (!sb_has_quota_enabled(sb, cnt)) {
87 +                               down(&toputinode[cnt]->i_sem);
88 +                               toputinode[cnt]->i_flags &= ~(S_IMMUTABLE |
89 +                                 S_NOATIME | S_NOQUOTA);
90 +                               truncate_inode_pages(&toputinode[cnt]->i_data, 0);
91 +                               up(&toputinode[cnt]->i_sem);
92 +                               mark_inode_dirty(toputinode[cnt]);
93 +                               iput(toputinode[cnt]);
94 +                       }
95 +                       up(&dqopt->dqonoff_sem);
96 +                       /* We don't hold the reference when we turned on quotas
97 +                        * just for the journal replay... */
98 +                       if (toputmnt[cnt])
99 +                               mntput(toputmnt[cnt]);
100                 }
101         invalidate_bdev(sb->s_bdev, 0);
102         return 0;
103 @@ -1478,8 +1496,11 @@ int vfs_quota_on(struct super_block *sb,
104         /* Quota file not on the same filesystem? */
105         if (nd.mnt->mnt_sb != sb)
106                 error = -EXDEV;
107 -       else
108 +       else {
109                 error = vfs_quota_on_inode(nd.dentry->d_inode, type, format_id);
110 +               if (!error)
111 +                       sb_dqopt(sb)->mnt[type] = mntget(nd.mnt);
112 +       }
113  out_path:
114         path_release(&nd);
115         return error;
116 diff -puN include/linux/quota.h~quota-umount-race-fix include/linux/quota.h
117 --- 25/include/linux/quota.h~quota-umount-race-fix      Tue Nov 23 17:11:34 2004
118 +++ 25-akpm/include/linux/quota.h       Tue Nov 23 17:11:34 2004
119 @@ -286,6 +286,7 @@ struct quota_info {
120         struct semaphore dqonoff_sem;           /* Serialize quotaon & quotaoff */
121         struct rw_semaphore dqptr_sem;          /* serialize ops using quota_info struct, pointers from inode to dquots */
122         struct inode *files[MAXQUOTAS];         /* inodes of quotafiles */
123 +       struct vfsmount *mnt[MAXQUOTAS];        /* mountpoint entries of filesystems with quota files */
124         struct mem_dqinfo info[MAXQUOTAS];      /* Information for each quota type */
125         struct quota_format_ops *ops[MAXQUOTAS];        /* Operations for each type */
126  };
127 diff -puN include/linux/quotaops.h~quota-umount-race-fix include/linux/quotaops.h
128 --- 25/include/linux/quotaops.h~quota-umount-race-fix   Tue Nov 23 17:11:34 2004
129 +++ 25-akpm/include/linux/quotaops.h    Tue Nov 23 17:11:34 2004
130 @@ -177,7 +177,7 @@ static __inline__ int DQUOT_OFF(struct s
131  {
132         int ret = -ENOSYS;
133  
134 -       if (sb->s_qcop && sb->s_qcop->quota_off)
135 +       if (sb_any_quota_enabled(sb) && sb->s_qcop && sb->s_qcop->quota_off)
136                 ret = sb->s_qcop->quota_off(sb, -1);
137         return ret;
138  }
139 _