diff options
author | Jonathan Corbet <corbet@lwn.net> | 2009-02-06 17:25:24 -0500 |
---|---|---|
committer | Jonathan Corbet <corbet@lwn.net> | 2009-03-16 10:32:27 -0400 |
commit | db1dd4d376134eba0e08af523b61cc566a4ea1cd (patch) | |
tree | 8882c673abbaa5713511b7046493fa862b9140d1 | |
parent | 684999149002dd046269666a390458e0acb38280 (diff) |
Use f_lock to protect f_flags
Traditionally, changes to struct file->f_flags have been done under BKL
protection, or with no protection at all. This patch causes all f_flags
changes after file open/creation time to be done under protection of
f_lock. This allows the removal of some BKL usage and fixes a number of
longstanding (if microscopic) races.
Reviewed-by: Christoph Hellwig <hch@lst.de>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Jonathan Corbet <corbet@lwn.net>
-rw-r--r-- | drivers/char/tty_io.c | 5 | ||||
-rw-r--r-- | drivers/usb/gadget/file_storage.c | 7 | ||||
-rw-r--r-- | fs/fcntl.c | 2 | ||||
-rw-r--r-- | fs/ioctl.c | 7 | ||||
-rw-r--r-- | fs/nfsd/vfs.c | 5 | ||||
-rw-r--r-- | include/linux/fs.h | 2 | ||||
-rw-r--r-- | ipc/mqueue.c | 2 | ||||
-rw-r--r-- | sound/core/oss/pcm_oss.c | 2 | ||||
-rw-r--r-- | sound/oss/au1550_ac97.c | 2 | ||||
-rw-r--r-- | sound/oss/audio.c | 2 | ||||
-rw-r--r-- | sound/oss/sh_dac_audio.c | 2 | ||||
-rw-r--r-- | sound/oss/swarm_cs4297a.c | 2 | ||||
-rw-r--r-- | sound/oss/vwsnd.c | 2 |
13 files changed, 33 insertions, 9 deletions
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index bc84e125c6bc..224f271d8cbe 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c | |||
@@ -2162,13 +2162,12 @@ static int fionbio(struct file *file, int __user *p) | |||
2162 | if (get_user(nonblock, p)) | 2162 | if (get_user(nonblock, p)) |
2163 | return -EFAULT; | 2163 | return -EFAULT; |
2164 | 2164 | ||
2165 | /* file->f_flags is still BKL protected in the fs layer - vomit */ | 2165 | spin_lock(&file->f_lock); |
2166 | lock_kernel(); | ||
2167 | if (nonblock) | 2166 | if (nonblock) |
2168 | file->f_flags |= O_NONBLOCK; | 2167 | file->f_flags |= O_NONBLOCK; |
2169 | else | 2168 | else |
2170 | file->f_flags &= ~O_NONBLOCK; | 2169 | file->f_flags &= ~O_NONBLOCK; |
2171 | unlock_kernel(); | 2170 | spin_unlock(&file->f_lock); |
2172 | return 0; | 2171 | return 0; |
2173 | } | 2172 | } |
2174 | 2173 | ||
diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c index 1ab9dac7e12d..33bb76cef33c 100644 --- a/drivers/usb/gadget/file_storage.c +++ b/drivers/usb/gadget/file_storage.c | |||
@@ -1711,7 +1711,9 @@ static int do_write(struct fsg_dev *fsg) | |||
1711 | curlun->sense_data = SS_WRITE_PROTECTED; | 1711 | curlun->sense_data = SS_WRITE_PROTECTED; |
1712 | return -EINVAL; | 1712 | return -EINVAL; |
1713 | } | 1713 | } |
1714 | spin_lock(&curlun->filp->f_lock); | ||
1714 | curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait | 1715 | curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait |
1716 | spin_unlock(&curlun->filp->f_lock); | ||
1715 | 1717 | ||
1716 | /* Get the starting Logical Block Address and check that it's | 1718 | /* Get the starting Logical Block Address and check that it's |
1717 | * not too big */ | 1719 | * not too big */ |
@@ -1728,8 +1730,11 @@ static int do_write(struct fsg_dev *fsg) | |||
1728 | curlun->sense_data = SS_INVALID_FIELD_IN_CDB; | 1730 | curlun->sense_data = SS_INVALID_FIELD_IN_CDB; |
1729 | return -EINVAL; | 1731 | return -EINVAL; |
1730 | } | 1732 | } |
1731 | if (fsg->cmnd[1] & 0x08) // FUA | 1733 | if (fsg->cmnd[1] & 0x08) { // FUA |
1734 | spin_lock(&curlun->filp->f_lock); | ||
1732 | curlun->filp->f_flags |= O_SYNC; | 1735 | curlun->filp->f_flags |= O_SYNC; |
1736 | spin_unlock(&curlun->filp->f_lock); | ||
1737 | } | ||
1733 | } | 1738 | } |
1734 | if (lba >= curlun->num_sectors) { | 1739 | if (lba >= curlun->num_sectors) { |
1735 | curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; | 1740 | curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; |
diff --git a/fs/fcntl.c b/fs/fcntl.c index bd215cc791da..04df8570a2d2 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c | |||
@@ -189,7 +189,9 @@ static int setfl(int fd, struct file * filp, unsigned long arg) | |||
189 | } | 189 | } |
190 | } | 190 | } |
191 | 191 | ||
192 | spin_lock(&filp->f_lock); | ||
192 | filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK); | 193 | filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK); |
194 | spin_unlock(&filp->f_lock); | ||
193 | out: | 195 | out: |
194 | unlock_kernel(); | 196 | unlock_kernel(); |
195 | return error; | 197 | return error; |
diff --git a/fs/ioctl.c b/fs/ioctl.c index 240ec63984cb..421aab465dab 100644 --- a/fs/ioctl.c +++ b/fs/ioctl.c | |||
@@ -404,10 +404,12 @@ static int ioctl_fionbio(struct file *filp, int __user *argp) | |||
404 | if (O_NONBLOCK != O_NDELAY) | 404 | if (O_NONBLOCK != O_NDELAY) |
405 | flag |= O_NDELAY; | 405 | flag |= O_NDELAY; |
406 | #endif | 406 | #endif |
407 | spin_lock(&filp->f_lock); | ||
407 | if (on) | 408 | if (on) |
408 | filp->f_flags |= flag; | 409 | filp->f_flags |= flag; |
409 | else | 410 | else |
410 | filp->f_flags &= ~flag; | 411 | filp->f_flags &= ~flag; |
412 | spin_unlock(&filp->f_lock); | ||
411 | return error; | 413 | return error; |
412 | } | 414 | } |
413 | 415 | ||
@@ -432,10 +434,12 @@ static int ioctl_fioasync(unsigned int fd, struct file *filp, | |||
432 | if (error) | 434 | if (error) |
433 | return error; | 435 | return error; |
434 | 436 | ||
437 | spin_lock(&filp->f_lock); | ||
435 | if (on) | 438 | if (on) |
436 | filp->f_flags |= FASYNC; | 439 | filp->f_flags |= FASYNC; |
437 | else | 440 | else |
438 | filp->f_flags &= ~FASYNC; | 441 | filp->f_flags &= ~FASYNC; |
442 | spin_unlock(&filp->f_lock); | ||
439 | return error; | 443 | return error; |
440 | } | 444 | } |
441 | 445 | ||
@@ -499,10 +503,7 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd, | |||
499 | break; | 503 | break; |
500 | 504 | ||
501 | case FIONBIO: | 505 | case FIONBIO: |
502 | /* BKL needed to avoid races tweaking f_flags */ | ||
503 | lock_kernel(); | ||
504 | error = ioctl_fionbio(filp, argp); | 506 | error = ioctl_fionbio(filp, argp); |
505 | unlock_kernel(); | ||
506 | break; | 507 | break; |
507 | 508 | ||
508 | case FIOASYNC: | 509 | case FIOASYNC: |
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c index 6e50aaa56ca2..c165a6403df0 100644 --- a/fs/nfsd/vfs.c +++ b/fs/nfsd/vfs.c | |||
@@ -998,8 +998,11 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file, | |||
998 | 998 | ||
999 | if (!EX_ISSYNC(exp)) | 999 | if (!EX_ISSYNC(exp)) |
1000 | stable = 0; | 1000 | stable = 0; |
1001 | if (stable && !EX_WGATHER(exp)) | 1001 | if (stable && !EX_WGATHER(exp)) { |
1002 | spin_lock(&file->f_lock); | ||
1002 | file->f_flags |= O_SYNC; | 1003 | file->f_flags |= O_SYNC; |
1004 | spin_unlock(&file->f_lock); | ||
1005 | } | ||
1003 | 1006 | ||
1004 | /* Write the data. */ | 1007 | /* Write the data. */ |
1005 | oldfs = get_fs(); set_fs(KERNEL_DS); | 1008 | oldfs = get_fs(); set_fs(KERNEL_DS); |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 2011600d12c7..7428c6d35e65 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
@@ -848,7 +848,7 @@ struct file { | |||
848 | #define f_dentry f_path.dentry | 848 | #define f_dentry f_path.dentry |
849 | #define f_vfsmnt f_path.mnt | 849 | #define f_vfsmnt f_path.mnt |
850 | const struct file_operations *f_op; | 850 | const struct file_operations *f_op; |
851 | spinlock_t f_lock; /* f_ep_links */ | 851 | spinlock_t f_lock; /* f_ep_links, f_flags */ |
852 | atomic_long_t f_count; | 852 | atomic_long_t f_count; |
853 | unsigned int f_flags; | 853 | unsigned int f_flags; |
854 | fmode_t f_mode; | 854 | fmode_t f_mode; |
diff --git a/ipc/mqueue.c b/ipc/mqueue.c index 54b4077fed79..a8ddadbc7459 100644 --- a/ipc/mqueue.c +++ b/ipc/mqueue.c | |||
@@ -1156,10 +1156,12 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes, | |||
1156 | omqstat.mq_flags = filp->f_flags & O_NONBLOCK; | 1156 | omqstat.mq_flags = filp->f_flags & O_NONBLOCK; |
1157 | if (u_mqstat) { | 1157 | if (u_mqstat) { |
1158 | audit_mq_getsetattr(mqdes, &mqstat); | 1158 | audit_mq_getsetattr(mqdes, &mqstat); |
1159 | spin_lock(&filp->f_lock); | ||
1159 | if (mqstat.mq_flags & O_NONBLOCK) | 1160 | if (mqstat.mq_flags & O_NONBLOCK) |
1160 | filp->f_flags |= O_NONBLOCK; | 1161 | filp->f_flags |= O_NONBLOCK; |
1161 | else | 1162 | else |
1162 | filp->f_flags &= ~O_NONBLOCK; | 1163 | filp->f_flags &= ~O_NONBLOCK; |
1164 | spin_unlock(&filp->f_lock); | ||
1163 | 1165 | ||
1164 | inode->i_atime = inode->i_ctime = CURRENT_TIME; | 1166 | inode->i_atime = inode->i_ctime = CURRENT_TIME; |
1165 | } | 1167 | } |
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 0a1798eafb0b..d4460f18e76c 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
@@ -1895,7 +1895,9 @@ static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsig | |||
1895 | 1895 | ||
1896 | static int snd_pcm_oss_nonblock(struct file * file) | 1896 | static int snd_pcm_oss_nonblock(struct file * file) |
1897 | { | 1897 | { |
1898 | spin_lock(&file->f_lock); | ||
1898 | file->f_flags |= O_NONBLOCK; | 1899 | file->f_flags |= O_NONBLOCK; |
1900 | spin_unlock(&file->f_lock); | ||
1899 | return 0; | 1901 | return 0; |
1900 | } | 1902 | } |
1901 | 1903 | ||
diff --git a/sound/oss/au1550_ac97.c b/sound/oss/au1550_ac97.c index 81e1f443d094..4191acccbcdb 100644 --- a/sound/oss/au1550_ac97.c +++ b/sound/oss/au1550_ac97.c | |||
@@ -1627,7 +1627,9 @@ au1550_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | |||
1627 | sizeof(abinfo)) ? -EFAULT : 0; | 1627 | sizeof(abinfo)) ? -EFAULT : 0; |
1628 | 1628 | ||
1629 | case SNDCTL_DSP_NONBLOCK: | 1629 | case SNDCTL_DSP_NONBLOCK: |
1630 | spin_lock(&file->f_lock); | ||
1630 | file->f_flags |= O_NONBLOCK; | 1631 | file->f_flags |= O_NONBLOCK; |
1632 | spin_unlock(&file->f_lock); | ||
1631 | return 0; | 1633 | return 0; |
1632 | 1634 | ||
1633 | case SNDCTL_DSP_GETODELAY: | 1635 | case SNDCTL_DSP_GETODELAY: |
diff --git a/sound/oss/audio.c b/sound/oss/audio.c index 89bd27a5e865..b69c05b7ea7b 100644 --- a/sound/oss/audio.c +++ b/sound/oss/audio.c | |||
@@ -433,7 +433,9 @@ int audio_ioctl(int dev, struct file *file, unsigned int cmd, void __user *arg) | |||
433 | return dma_ioctl(dev, cmd, arg); | 433 | return dma_ioctl(dev, cmd, arg); |
434 | 434 | ||
435 | case SNDCTL_DSP_NONBLOCK: | 435 | case SNDCTL_DSP_NONBLOCK: |
436 | spin_lock(&file->f_lock); | ||
436 | file->f_flags |= O_NONBLOCK; | 437 | file->f_flags |= O_NONBLOCK; |
438 | spin_unlock(&file->f_lock); | ||
437 | return 0; | 439 | return 0; |
438 | 440 | ||
439 | case SNDCTL_DSP_GETCAPS: | 441 | case SNDCTL_DSP_GETCAPS: |
diff --git a/sound/oss/sh_dac_audio.c b/sound/oss/sh_dac_audio.c index e5d423994918..78cfb66e4c59 100644 --- a/sound/oss/sh_dac_audio.c +++ b/sound/oss/sh_dac_audio.c | |||
@@ -135,7 +135,9 @@ static int dac_audio_ioctl(struct inode *inode, struct file *file, | |||
135 | return put_user(AFMT_U8, (int *)arg); | 135 | return put_user(AFMT_U8, (int *)arg); |
136 | 136 | ||
137 | case SNDCTL_DSP_NONBLOCK: | 137 | case SNDCTL_DSP_NONBLOCK: |
138 | spin_lock(&file->f_lock); | ||
138 | file->f_flags |= O_NONBLOCK; | 139 | file->f_flags |= O_NONBLOCK; |
140 | spin_unlock(&file->f_lock); | ||
139 | return 0; | 141 | return 0; |
140 | 142 | ||
141 | case SNDCTL_DSP_GETCAPS: | 143 | case SNDCTL_DSP_GETCAPS: |
diff --git a/sound/oss/swarm_cs4297a.c b/sound/oss/swarm_cs4297a.c index 41562ecde5bb..1edab7b4ea83 100644 --- a/sound/oss/swarm_cs4297a.c +++ b/sound/oss/swarm_cs4297a.c | |||
@@ -2200,7 +2200,9 @@ static int cs4297a_ioctl(struct inode *inode, struct file *file, | |||
2200 | sizeof(abinfo)) ? -EFAULT : 0; | 2200 | sizeof(abinfo)) ? -EFAULT : 0; |
2201 | 2201 | ||
2202 | case SNDCTL_DSP_NONBLOCK: | 2202 | case SNDCTL_DSP_NONBLOCK: |
2203 | spin_lock(&file->f_lock); | ||
2203 | file->f_flags |= O_NONBLOCK; | 2204 | file->f_flags |= O_NONBLOCK; |
2205 | spin_unlock(&file->f_lock); | ||
2204 | return 0; | 2206 | return 0; |
2205 | 2207 | ||
2206 | case SNDCTL_DSP_GETODELAY: | 2208 | case SNDCTL_DSP_GETODELAY: |
diff --git a/sound/oss/vwsnd.c b/sound/oss/vwsnd.c index 78b8acc7c3b9..187f72750e8f 100644 --- a/sound/oss/vwsnd.c +++ b/sound/oss/vwsnd.c | |||
@@ -2673,7 +2673,9 @@ static int vwsnd_audio_do_ioctl(struct inode *inode, | |||
2673 | 2673 | ||
2674 | case SNDCTL_DSP_NONBLOCK: /* _SIO ('P',14) */ | 2674 | case SNDCTL_DSP_NONBLOCK: /* _SIO ('P',14) */ |
2675 | DBGX("SNDCTL_DSP_NONBLOCK\n"); | 2675 | DBGX("SNDCTL_DSP_NONBLOCK\n"); |
2676 | spin_lock(&file->f_lock); | ||
2676 | file->f_flags |= O_NONBLOCK; | 2677 | file->f_flags |= O_NONBLOCK; |
2678 | spin_unlock(&file->f_lock); | ||
2677 | return 0; | 2679 | return 0; |
2678 | 2680 | ||
2679 | case SNDCTL_DSP_RESET: /* _SIO ('P', 0) */ | 2681 | case SNDCTL_DSP_RESET: /* _SIO ('P', 0) */ |