Browse Source

Merge branch 'bkl-removal' of git://git.lwn.net/linux-2.6

* 'bkl-removal' of git://git.lwn.net/linux-2.6:
  Rationalize fasync return values
  Move FASYNC bit handling to f_op->fasync()
  Use f_lock to protect f_flags
  Rename struct file->f_ep_lock
Linus Torvalds 16 years ago
parent
commit
8e9d208972

+ 5 - 2
Documentation/filesystems/Locking

@@ -437,8 +437,11 @@ grab BKL for cases when we close a file that had been opened r/w, but that
 can and should be done using the internal locking with smaller critical areas).
 can and should be done using the internal locking with smaller critical areas).
 Current worst offender is ext2_get_block()...
 Current worst offender is ext2_get_block()...
 
 
-->fasync() is a mess. This area needs a big cleanup and that will probably
-affect locking.
+->fasync() is called without BKL protection, and is responsible for
+maintaining the FASYNC bit in filp->f_flags.  Most instances call
+fasync_helper(), which does that maintenance, so it's not normally
+something one needs to worry about.  Return values > 0 will be mapped to
+zero in the VFS layer.
 
 
 ->readdir() and ->ioctl() on directories must be changed. Ideally we would
 ->readdir() and ->ioctl() on directories must be changed. Ideally we would
 move ->readdir() to inode_operations and use a separate method for directory
 move ->readdir() to inode_operations and use a separate method for directory

+ 1 - 6
drivers/char/sonypi.c

@@ -888,12 +888,7 @@ found:
 
 
 static int sonypi_misc_fasync(int fd, struct file *filp, int on)
 static int sonypi_misc_fasync(int fd, struct file *filp, int on)
 {
 {
-	int retval;
-
-	retval = fasync_helper(fd, filp, on, &sonypi_device.fifo_async);
-	if (retval < 0)
-		return retval;
-	return 0;
+	return fasync_helper(fd, filp, on, &sonypi_device.fifo_async);
 }
 }
 
 
 static int sonypi_misc_release(struct inode *inode, struct file *file)
 static int sonypi_misc_release(struct inode *inode, struct file *file)

+ 2 - 3
drivers/char/tty_io.c

@@ -2162,13 +2162,12 @@ static int fionbio(struct file *file, int __user *p)
 	if (get_user(nonblock, p))
 	if (get_user(nonblock, p))
 		return -EFAULT;
 		return -EFAULT;
 
 
-	/* file->f_flags is still BKL protected in the fs layer - vomit */
-	lock_kernel();
+	spin_lock(&file->f_lock);
 	if (nonblock)
 	if (nonblock)
 		file->f_flags |= O_NONBLOCK;
 		file->f_flags |= O_NONBLOCK;
 	else
 	else
 		file->f_flags &= ~O_NONBLOCK;
 		file->f_flags &= ~O_NONBLOCK;
-	unlock_kernel();
+	spin_unlock(&file->f_lock);
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 5
drivers/gpu/drm/drm_fops.c

@@ -337,14 +337,10 @@ int drm_fasync(int fd, struct file *filp, int on)
 {
 {
 	struct drm_file *priv = filp->private_data;
 	struct drm_file *priv = filp->private_data;
 	struct drm_device *dev = priv->minor->dev;
 	struct drm_device *dev = priv->minor->dev;
-	int retcode;
 
 
 	DRM_DEBUG("fd = %d, device = 0x%lx\n", fd,
 	DRM_DEBUG("fd = %d, device = 0x%lx\n", fd,
 		  (long)old_encode_dev(priv->minor->device));
 		  (long)old_encode_dev(priv->minor->device));
-	retcode = fasync_helper(fd, filp, on, &dev->buf_async);
-	if (retcode < 0)
-		return retcode;
-	return 0;
+	return fasync_helper(fd, filp, on, &dev->buf_async);
 }
 }
 EXPORT_SYMBOL(drm_fasync);
 EXPORT_SYMBOL(drm_fasync);
 
 

+ 1 - 4
drivers/hid/usbhid/hiddev.c

@@ -227,12 +227,9 @@ void hiddev_report_event(struct hid_device *hid, struct hid_report *report)
  */
  */
 static int hiddev_fasync(int fd, struct file *file, int on)
 static int hiddev_fasync(int fd, struct file *file, int on)
 {
 {
-	int retval;
 	struct hiddev_list *list = file->private_data;
 	struct hiddev_list *list = file->private_data;
 
 
-	retval = fasync_helper(fd, file, on, &list->fasync);
-
-	return retval < 0 ? retval : 0;
+	return fasync_helper(fd, file, on, &list->fasync);
 }
 }
 
 
 
 

+ 1 - 5
drivers/ieee1394/dv1394.c

@@ -1325,11 +1325,7 @@ static int dv1394_fasync(int fd, struct file *file, int on)
 
 
 	struct video_card *video = file_to_video_card(file);
 	struct video_card *video = file_to_video_card(file);
 
 
-	int retval = fasync_helper(fd, file, on, &video->fasync);
-
-	if (retval < 0)
-		return retval;
-        return 0;
+	return fasync_helper(fd, file, on, &video->fasync);
 }
 }
 
 
 static ssize_t dv1394_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
 static ssize_t dv1394_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)

+ 1 - 4
drivers/input/evdev.c

@@ -94,11 +94,8 @@ static void evdev_event(struct input_handle *handle,
 static int evdev_fasync(int fd, struct file *file, int on)
 static int evdev_fasync(int fd, struct file *file, int on)
 {
 {
 	struct evdev_client *client = file->private_data;
 	struct evdev_client *client = file->private_data;
-	int retval;
-
-	retval = fasync_helper(fd, file, on, &client->fasync);
 
 
-	return retval < 0 ? retval : 0;
+	return fasync_helper(fd, file, on, &client->fasync);
 }
 }
 
 
 static int evdev_flush(struct file *file, fl_owner_t id)
 static int evdev_flush(struct file *file, fl_owner_t id)

+ 1 - 4
drivers/input/joydev.c

@@ -159,12 +159,9 @@ static void joydev_event(struct input_handle *handle,
 
 
 static int joydev_fasync(int fd, struct file *file, int on)
 static int joydev_fasync(int fd, struct file *file, int on)
 {
 {
-	int retval;
 	struct joydev_client *client = file->private_data;
 	struct joydev_client *client = file->private_data;
 
 
-	retval = fasync_helper(fd, file, on, &client->fasync);
-
-	return retval < 0 ? retval : 0;
+	return fasync_helper(fd, file, on, &client->fasync);
 }
 }
 
 
 static void joydev_free(struct device *dev)
 static void joydev_free(struct device *dev)

+ 1 - 4
drivers/input/mousedev.c

@@ -403,12 +403,9 @@ static void mousedev_event(struct input_handle *handle,
 
 
 static int mousedev_fasync(int fd, struct file *file, int on)
 static int mousedev_fasync(int fd, struct file *file, int on)
 {
 {
-	int retval;
 	struct mousedev_client *client = file->private_data;
 	struct mousedev_client *client = file->private_data;
 
 
-	retval = fasync_helper(fd, file, on, &client->fasync);
-
-	return retval < 0 ? retval : 0;
+	return fasync_helper(fd, file, on, &client->fasync);
 }
 }
 
 
 static void mousedev_free(struct device *dev)
 static void mousedev_free(struct device *dev)

+ 1 - 3
drivers/input/serio/serio_raw.c

@@ -58,10 +58,8 @@ static unsigned int serio_raw_no;
 static int serio_raw_fasync(int fd, struct file *file, int on)
 static int serio_raw_fasync(int fd, struct file *file, int on)
 {
 {
 	struct serio_raw_list *list = file->private_data;
 	struct serio_raw_list *list = file->private_data;
-	int retval;
 
 
-	retval = fasync_helper(fd, file, on, &list->fasync);
-	return retval < 0 ? retval : 0;
+	return fasync_helper(fd, file, on, &list->fasync);
 }
 }
 
 
 static struct serio_raw *serio_raw_locate(int minor)
 static struct serio_raw *serio_raw_locate(int minor)

+ 2 - 2
drivers/net/wan/cosa.c

@@ -998,8 +998,8 @@ static struct fasync_struct *fasync[256] = { NULL, };
 static int cosa_fasync(struct inode *inode, struct file *file, int on)
 static int cosa_fasync(struct inode *inode, struct file *file, int on)
 {
 {
         int port = iminor(inode);
         int port = iminor(inode);
-        int rv = fasync_helper(inode, file, on, &fasync[port]);
-        return rv < 0 ? rv : 0;
+
+	return fasync_helper(inode, file, on, &fasync[port]);
 }
 }
 #endif
 #endif
 
 

+ 1 - 6
drivers/platform/x86/sony-laptop.c

@@ -1917,12 +1917,7 @@ static struct sonypi_compat_s sonypi_compat = {
 
 
 static int sonypi_misc_fasync(int fd, struct file *filp, int on)
 static int sonypi_misc_fasync(int fd, struct file *filp, int on)
 {
 {
-	int retval;
-
-	retval = fasync_helper(fd, filp, on, &sonypi_compat.fifo_async);
-	if (retval < 0)
-		return retval;
-	return 0;
+	return fasync_helper(fd, filp, on, &sonypi_compat.fifo_async);
 }
 }
 
 
 static int sonypi_misc_release(struct inode *inode, struct file *file)
 static int sonypi_misc_release(struct inode *inode, struct file *file)

+ 1 - 3
drivers/scsi/sg.c

@@ -1154,7 +1154,6 @@ sg_poll(struct file *filp, poll_table * wait)
 static int
 static int
 sg_fasync(int fd, struct file *filp, int mode)
 sg_fasync(int fd, struct file *filp, int mode)
 {
 {
-	int retval;
 	Sg_device *sdp;
 	Sg_device *sdp;
 	Sg_fd *sfp;
 	Sg_fd *sfp;
 
 
@@ -1163,8 +1162,7 @@ sg_fasync(int fd, struct file *filp, int mode)
 	SCSI_LOG_TIMEOUT(3, printk("sg_fasync: %s, mode=%d\n",
 	SCSI_LOG_TIMEOUT(3, printk("sg_fasync: %s, mode=%d\n",
 				   sdp->disk->disk_name, mode));
 				   sdp->disk->disk_name, mode));
 
 
-	retval = fasync_helper(fd, filp, mode, &sfp->async_qp);
-	return (retval < 0) ? retval : 0;
+	return fasync_helper(fd, filp, mode, &sfp->async_qp);
 }
 }
 
 
 static int
 static int

+ 6 - 1
drivers/usb/gadget/file_storage.c

@@ -1711,7 +1711,9 @@ static int do_write(struct fsg_dev *fsg)
 		curlun->sense_data = SS_WRITE_PROTECTED;
 		curlun->sense_data = SS_WRITE_PROTECTED;
 		return -EINVAL;
 		return -EINVAL;
 	}
 	}
+	spin_lock(&curlun->filp->f_lock);
 	curlun->filp->f_flags &= ~O_SYNC;	// Default is not to wait
 	curlun->filp->f_flags &= ~O_SYNC;	// Default is not to wait
+	spin_unlock(&curlun->filp->f_lock);
 
 
 	/* Get the starting Logical Block Address and check that it's
 	/* Get the starting Logical Block Address and check that it's
 	 * not too big */
 	 * not too big */
@@ -1728,8 +1730,11 @@ static int do_write(struct fsg_dev *fsg)
 			curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
 			curlun->sense_data = SS_INVALID_FIELD_IN_CDB;
 			return -EINVAL;
 			return -EINVAL;
 		}
 		}
-		if (fsg->cmnd[1] & 0x08)	// FUA
+		if (fsg->cmnd[1] & 0x08) {	// FUA
+			spin_lock(&curlun->filp->f_lock);
 			curlun->filp->f_flags |= O_SYNC;
 			curlun->filp->f_flags |= O_SYNC;
+			spin_unlock(&curlun->filp->f_lock);
+		}
 	}
 	}
 	if (lba >= curlun->num_sectors) {
 	if (lba >= curlun->num_sectors) {
 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;
 		curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE;

+ 7 - 5
fs/eventpoll.c

@@ -417,10 +417,10 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi)
 	ep_unregister_pollwait(ep, epi);
 	ep_unregister_pollwait(ep, epi);
 
 
 	/* Remove the current item from the list of epoll hooks */
 	/* Remove the current item from the list of epoll hooks */
-	spin_lock(&file->f_ep_lock);
+	spin_lock(&file->f_lock);
 	if (ep_is_linked(&epi->fllink))
 	if (ep_is_linked(&epi->fllink))
 		list_del_init(&epi->fllink);
 		list_del_init(&epi->fllink);
-	spin_unlock(&file->f_ep_lock);
+	spin_unlock(&file->f_lock);
 
 
 	rb_erase(&epi->rbn, &ep->rbr);
 	rb_erase(&epi->rbn, &ep->rbr);
 
 
@@ -538,7 +538,7 @@ void eventpoll_release_file(struct file *file)
 	struct epitem *epi;
 	struct epitem *epi;
 
 
 	/*
 	/*
-	 * We don't want to get "file->f_ep_lock" because it is not
+	 * We don't want to get "file->f_lock" because it is not
 	 * necessary. It is not necessary because we're in the "struct file"
 	 * necessary. It is not necessary because we're in the "struct file"
 	 * cleanup path, and this means that noone is using this file anymore.
 	 * cleanup path, and this means that noone is using this file anymore.
 	 * So, for example, epoll_ctl() cannot hit here sicne if we reach this
 	 * So, for example, epoll_ctl() cannot hit here sicne if we reach this
@@ -547,6 +547,8 @@ void eventpoll_release_file(struct file *file)
 	 * will correctly serialize the operation. We do need to acquire
 	 * will correctly serialize the operation. We do need to acquire
 	 * "ep->mtx" after "epmutex" because ep_remove() requires it when called
 	 * "ep->mtx" after "epmutex" because ep_remove() requires it when called
 	 * from anywhere but ep_free().
 	 * from anywhere but ep_free().
+	 *
+	 * Besides, ep_remove() acquires the lock, so we can't hold it here.
 	 */
 	 */
 	mutex_lock(&epmutex);
 	mutex_lock(&epmutex);
 
 
@@ -785,9 +787,9 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
 		goto error_unregister;
 		goto error_unregister;
 
 
 	/* Add the current item to the list of active epoll hook for this file */
 	/* Add the current item to the list of active epoll hook for this file */
-	spin_lock(&tfile->f_ep_lock);
+	spin_lock(&tfile->f_lock);
 	list_add_tail(&epi->fllink, &tfile->f_ep_links);
 	list_add_tail(&epi->fllink, &tfile->f_ep_links);
-	spin_unlock(&tfile->f_ep_lock);
+	spin_unlock(&tfile->f_lock);
 
 
 	/*
 	/*
 	 * Add the current item to the RB tree. All RB tree operations are
 	 * Add the current item to the RB tree. All RB tree operations are

+ 20 - 13
fs/fcntl.c

@@ -141,7 +141,7 @@ SYSCALL_DEFINE1(dup, unsigned int, fildes)
 	return ret;
 	return ret;
 }
 }
 
 
-#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC | O_DIRECT | O_NOATIME)
+#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | O_DIRECT | O_NOATIME)
 
 
 static int setfl(int fd, struct file * filp, unsigned long arg)
 static int setfl(int fd, struct file * filp, unsigned long arg)
 {
 {
@@ -177,21 +177,21 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
 		return error;
 		return error;
 
 
 	/*
 	/*
-	 * We still need a lock here for now to keep multiple FASYNC calls
-	 * from racing with each other.
+	 * ->fasync() is responsible for setting the FASYNC bit.
 	 */
 	 */
-	lock_kernel();
-	if ((arg ^ filp->f_flags) & FASYNC) {
-		if (filp->f_op && filp->f_op->fasync) {
-			error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
-			if (error < 0)
-				goto out;
-		}
+	if (((arg ^ filp->f_flags) & FASYNC) && filp->f_op &&
+			filp->f_op->fasync) {
+		error = filp->f_op->fasync(fd, filp, (arg & FASYNC) != 0);
+		if (error < 0)
+			goto out;
+		if (error > 0)
+			error = 0;
 	}
 	}
-
+	spin_lock(&filp->f_lock);
 	filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
 	filp->f_flags = (arg & SETFL_MASK) | (filp->f_flags & ~SETFL_MASK);
+	spin_unlock(&filp->f_lock);
+
  out:
  out:
-	unlock_kernel();
 	return error;
 	return error;
 }
 }
 
 
@@ -516,7 +516,7 @@ static DEFINE_RWLOCK(fasync_lock);
 static struct kmem_cache *fasync_cache __read_mostly;
 static struct kmem_cache *fasync_cache __read_mostly;
 
 
 /*
 /*
- * fasync_helper() is used by some character device drivers (mainly mice)
+ * fasync_helper() is used by almost all character device drivers
  * to set up the fasync queue. It returns negative on error, 0 if it did
  * to set up the fasync queue. It returns negative on error, 0 if it did
  * no changes and positive if it added/deleted the entry.
  * no changes and positive if it added/deleted the entry.
  */
  */
@@ -555,6 +555,13 @@ int fasync_helper(int fd, struct file * filp, int on, struct fasync_struct **fap
 		result = 1;
 		result = 1;
 	}
 	}
 out:
 out:
+	/* Fix up FASYNC bit while still holding fasync_lock */
+	spin_lock(&filp->f_lock);
+	if (on)
+		filp->f_flags |= FASYNC;
+	else
+		filp->f_flags &= ~FASYNC;
+	spin_unlock(&filp->f_lock);
 	write_unlock_irq(&fasync_lock);
 	write_unlock_irq(&fasync_lock);
 	return result;
 	return result;
 }
 }

+ 1 - 0
fs/file_table.c

@@ -128,6 +128,7 @@ struct file *get_empty_filp(void)
 	atomic_long_set(&f->f_count, 1);
 	atomic_long_set(&f->f_count, 1);
 	rwlock_init(&f->f_owner.lock);
 	rwlock_init(&f->f_owner.lock);
 	f->f_cred = get_cred(cred);
 	f->f_cred = get_cred(cred);
+	spin_lock_init(&f->f_lock);
 	eventpoll_init_file(f);
 	eventpoll_init_file(f);
 	/* f->f_version: 0 */
 	/* f->f_version: 0 */
 	return f;
 	return f;

+ 4 - 14
fs/ioctl.c

@@ -404,10 +404,12 @@ static int ioctl_fionbio(struct file *filp, int __user *argp)
 	if (O_NONBLOCK != O_NDELAY)
 	if (O_NONBLOCK != O_NDELAY)
 		flag |= O_NDELAY;
 		flag |= O_NDELAY;
 #endif
 #endif
+	spin_lock(&filp->f_lock);
 	if (on)
 	if (on)
 		filp->f_flags |= flag;
 		filp->f_flags |= flag;
 	else
 	else
 		filp->f_flags &= ~flag;
 		filp->f_flags &= ~flag;
+	spin_unlock(&filp->f_lock);
 	return error;
 	return error;
 }
 }
 
 
@@ -425,18 +427,12 @@ static int ioctl_fioasync(unsigned int fd, struct file *filp,
 	/* Did FASYNC state change ? */
 	/* Did FASYNC state change ? */
 	if ((flag ^ filp->f_flags) & FASYNC) {
 	if ((flag ^ filp->f_flags) & FASYNC) {
 		if (filp->f_op && filp->f_op->fasync)
 		if (filp->f_op && filp->f_op->fasync)
+			/* fasync() adjusts filp->f_flags */
 			error = filp->f_op->fasync(fd, filp, on);
 			error = filp->f_op->fasync(fd, filp, on);
 		else
 		else
 			error = -ENOTTY;
 			error = -ENOTTY;
 	}
 	}
-	if (error)
-		return error;
-
-	if (on)
-		filp->f_flags |= FASYNC;
-	else
-		filp->f_flags &= ~FASYNC;
-	return error;
+	return error < 0 ? error : 0;
 }
 }
 
 
 static int ioctl_fsfreeze(struct file *filp)
 static int ioctl_fsfreeze(struct file *filp)
@@ -499,17 +495,11 @@ int do_vfs_ioctl(struct file *filp, unsigned int fd, unsigned int cmd,
 		break;
 		break;
 
 
 	case FIONBIO:
 	case FIONBIO:
-		/* BKL needed to avoid races tweaking f_flags */
-		lock_kernel();
 		error = ioctl_fionbio(filp, argp);
 		error = ioctl_fionbio(filp, argp);
-		unlock_kernel();
 		break;
 		break;
 
 
 	case FIOASYNC:
 	case FIOASYNC:
-		/* BKL needed to avoid races tweaking f_flags */
-		lock_kernel();
 		error = ioctl_fioasync(fd, filp, argp);
 		error = ioctl_fioasync(fd, filp, argp);
-		unlock_kernel();
 		break;
 		break;
 
 
 	case FIOQSIZE:
 	case FIOQSIZE:

+ 4 - 1
fs/nfsd/vfs.c

@@ -998,8 +998,11 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
 
 
 	if (!EX_ISSYNC(exp))
 	if (!EX_ISSYNC(exp))
 		stable = 0;
 		stable = 0;
-	if (stable && !EX_WGATHER(exp))
+	if (stable && !EX_WGATHER(exp)) {
+		spin_lock(&file->f_lock);
 		file->f_flags |= O_SYNC;
 		file->f_flags |= O_SYNC;
+		spin_unlock(&file->f_lock);
+	}
 
 
 	/* Write the data. */
 	/* Write the data. */
 	oldfs = get_fs(); set_fs(KERNEL_DS);
 	oldfs = get_fs(); set_fs(KERNEL_DS);

+ 3 - 13
fs/pipe.c

@@ -667,10 +667,7 @@ pipe_read_fasync(int fd, struct file *filp, int on)
 	retval = fasync_helper(fd, filp, on, &inode->i_pipe->fasync_readers);
 	retval = fasync_helper(fd, filp, on, &inode->i_pipe->fasync_readers);
 	mutex_unlock(&inode->i_mutex);
 	mutex_unlock(&inode->i_mutex);
 
 
-	if (retval < 0)
-		return retval;
-
-	return 0;
+	return retval;
 }
 }
 
 
 
 
@@ -684,10 +681,7 @@ pipe_write_fasync(int fd, struct file *filp, int on)
 	retval = fasync_helper(fd, filp, on, &inode->i_pipe->fasync_writers);
 	retval = fasync_helper(fd, filp, on, &inode->i_pipe->fasync_writers);
 	mutex_unlock(&inode->i_mutex);
 	mutex_unlock(&inode->i_mutex);
 
 
-	if (retval < 0)
-		return retval;
-
-	return 0;
+	return retval;
 }
 }
 
 
 
 
@@ -706,11 +700,7 @@ pipe_rdwr_fasync(int fd, struct file *filp, int on)
 			fasync_helper(-1, filp, 0, &pipe->fasync_readers);
 			fasync_helper(-1, filp, 0, &pipe->fasync_readers);
 	}
 	}
 	mutex_unlock(&inode->i_mutex);
 	mutex_unlock(&inode->i_mutex);
-
-	if (retval < 0)
-		return retval;
-
-	return 0;
+	return retval;
 }
 }
 
 
 
 

+ 0 - 1
include/linux/eventpoll.h

@@ -61,7 +61,6 @@ struct file;
 static inline void eventpoll_init_file(struct file *file)
 static inline void eventpoll_init_file(struct file *file)
 {
 {
 	INIT_LIST_HEAD(&file->f_ep_links);
 	INIT_LIST_HEAD(&file->f_ep_links);
-	spin_lock_init(&file->f_ep_lock);
 }
 }
 
 
 
 

+ 1 - 1
include/linux/fs.h

@@ -849,6 +849,7 @@ struct file {
 #define f_dentry	f_path.dentry
 #define f_dentry	f_path.dentry
 #define f_vfsmnt	f_path.mnt
 #define f_vfsmnt	f_path.mnt
 	const struct file_operations	*f_op;
 	const struct file_operations	*f_op;
+	spinlock_t		f_lock;  /* f_ep_links, f_flags */
 	atomic_long_t		f_count;
 	atomic_long_t		f_count;
 	unsigned int 		f_flags;
 	unsigned int 		f_flags;
 	fmode_t			f_mode;
 	fmode_t			f_mode;
@@ -867,7 +868,6 @@ struct file {
 #ifdef CONFIG_EPOLL
 #ifdef CONFIG_EPOLL
 	/* Used by fs/eventpoll.c to link all the hooks to this file */
 	/* Used by fs/eventpoll.c to link all the hooks to this file */
 	struct list_head	f_ep_links;
 	struct list_head	f_ep_links;
-	spinlock_t		f_ep_lock;
 #endif /* #ifdef CONFIG_EPOLL */
 #endif /* #ifdef CONFIG_EPOLL */
 	struct address_space	*f_mapping;
 	struct address_space	*f_mapping;
 #ifdef CONFIG_DEBUG_WRITECOUNT
 #ifdef CONFIG_DEBUG_WRITECOUNT

+ 2 - 0
ipc/mqueue.c

@@ -1156,10 +1156,12 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
 	omqstat.mq_flags = filp->f_flags & O_NONBLOCK;
 	omqstat.mq_flags = filp->f_flags & O_NONBLOCK;
 	if (u_mqstat) {
 	if (u_mqstat) {
 		audit_mq_getsetattr(mqdes, &mqstat);
 		audit_mq_getsetattr(mqdes, &mqstat);
+		spin_lock(&filp->f_lock);
 		if (mqstat.mq_flags & O_NONBLOCK)
 		if (mqstat.mq_flags & O_NONBLOCK)
 			filp->f_flags |= O_NONBLOCK;
 			filp->f_flags |= O_NONBLOCK;
 		else
 		else
 			filp->f_flags &= ~O_NONBLOCK;
 			filp->f_flags &= ~O_NONBLOCK;
+		spin_unlock(&filp->f_lock);
 
 
 		inode->i_atime = inode->i_ctime = CURRENT_TIME;
 		inode->i_atime = inode->i_ctime = CURRENT_TIME;
 	}
 	}

+ 7 - 0
net/socket.c

@@ -1074,6 +1074,13 @@ static int sock_fasync(int fd, struct file *filp, int on)
 
 
 	lock_sock(sk);
 	lock_sock(sk);
 
 
+	spin_lock(&filp->f_lock);
+	if (on)
+		filp->f_flags |= FASYNC;
+	else
+		filp->f_flags &= ~FASYNC;
+	spin_unlock(&filp->f_lock);
+
 	prev = &(sock->fasync_list);
 	prev = &(sock->fasync_list);
 
 
 	for (fa = *prev; fa != NULL; prev = &fa->fa_next, fa = *prev)
 	for (fa = *prev; fa != NULL; prev = &fa->fa_next, fa = *prev)

+ 2 - 5
sound/core/control.c

@@ -1373,12 +1373,9 @@ EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
 static int snd_ctl_fasync(int fd, struct file * file, int on)
 static int snd_ctl_fasync(int fd, struct file * file, int on)
 {
 {
 	struct snd_ctl_file *ctl;
 	struct snd_ctl_file *ctl;
-	int err;
+
 	ctl = file->private_data;
 	ctl = file->private_data;
-	err = fasync_helper(fd, file, on, &ctl->fasync);
-	if (err < 0)
-		return err;
-	return 0;
+	return fasync_helper(fd, file, on, &ctl->fasync);
 }
 }
 
 
 /*
 /*

+ 2 - 0
sound/core/oss/pcm_oss.c

@@ -1903,7 +1903,9 @@ static int snd_pcm_oss_set_fragment(struct snd_pcm_oss_file *pcm_oss_file, unsig
 
 
 static int snd_pcm_oss_nonblock(struct file * file)
 static int snd_pcm_oss_nonblock(struct file * file)
 {
 {
+	spin_lock(&file->f_lock);
 	file->f_flags |= O_NONBLOCK;
 	file->f_flags |= O_NONBLOCK;
+	spin_unlock(&file->f_lock);
 	return 0;
 	return 0;
 }
 }
 
 

+ 1 - 3
sound/core/pcm_native.c

@@ -3246,9 +3246,7 @@ static int snd_pcm_fasync(int fd, struct file * file, int on)
 	err = fasync_helper(fd, file, on, &runtime->fasync);
 	err = fasync_helper(fd, file, on, &runtime->fasync);
 out:
 out:
 	unlock_kernel();
 	unlock_kernel();
-	if (err < 0)
-		return err;
-	return 0;
+	return err;
 }
 }
 
 
 /*
 /*

+ 1 - 5
sound/core/timer.c

@@ -1825,13 +1825,9 @@ static long snd_timer_user_ioctl(struct file *file, unsigned int cmd,
 static int snd_timer_user_fasync(int fd, struct file * file, int on)
 static int snd_timer_user_fasync(int fd, struct file * file, int on)
 {
 {
 	struct snd_timer_user *tu;
 	struct snd_timer_user *tu;
-	int err;
 
 
 	tu = file->private_data;
 	tu = file->private_data;
-	err = fasync_helper(fd, file, on, &tu->fasync);
-        if (err < 0)
-		return err;
-	return 0;
+	return fasync_helper(fd, file, on, &tu->fasync);
 }
 }
 
 
 static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,
 static ssize_t snd_timer_user_read(struct file *file, char __user *buffer,

+ 2 - 0
sound/oss/au1550_ac97.c

@@ -1627,7 +1627,9 @@ au1550_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
 				    sizeof(abinfo)) ? -EFAULT : 0;
 				    sizeof(abinfo)) ? -EFAULT : 0;
 
 
 	case SNDCTL_DSP_NONBLOCK:
 	case SNDCTL_DSP_NONBLOCK:
+		spin_lock(&file->f_lock);
 		file->f_flags |= O_NONBLOCK;
 		file->f_flags |= O_NONBLOCK;
+		spin_unlock(&file->f_lock);
 		return 0;
 		return 0;
 
 
 	case SNDCTL_DSP_GETODELAY:
 	case SNDCTL_DSP_GETODELAY:

+ 2 - 0
sound/oss/audio.c

@@ -433,7 +433,9 @@ int audio_ioctl(int dev, struct file *file, unsigned int cmd, void __user *arg)
 			return dma_ioctl(dev, cmd, arg);
 			return dma_ioctl(dev, cmd, arg);
 		
 		
 		case SNDCTL_DSP_NONBLOCK:
 		case SNDCTL_DSP_NONBLOCK:
+			spin_lock(&file->f_lock);
 			file->f_flags |= O_NONBLOCK;
 			file->f_flags |= O_NONBLOCK;
+			spin_unlock(&file->f_lock);
 			return 0;
 			return 0;
 
 
 		case SNDCTL_DSP_GETCAPS:
 		case SNDCTL_DSP_GETCAPS:

+ 2 - 0
sound/oss/sh_dac_audio.c

@@ -135,7 +135,9 @@ static int dac_audio_ioctl(struct inode *inode, struct file *file,
 		return put_user(AFMT_U8, (int *)arg);
 		return put_user(AFMT_U8, (int *)arg);
 
 
 	case SNDCTL_DSP_NONBLOCK:
 	case SNDCTL_DSP_NONBLOCK:
+		spin_lock(&file->f_lock);
 		file->f_flags |= O_NONBLOCK;
 		file->f_flags |= O_NONBLOCK;
+		spin_unlock(&file->f_lock);
 		return 0;
 		return 0;
 
 
 	case SNDCTL_DSP_GETCAPS:
 	case SNDCTL_DSP_GETCAPS:

+ 2 - 0
sound/oss/swarm_cs4297a.c

@@ -2200,7 +2200,9 @@ static int cs4297a_ioctl(struct inode *inode, struct file *file,
 				    sizeof(abinfo)) ? -EFAULT : 0;
 				    sizeof(abinfo)) ? -EFAULT : 0;
 
 
 	case SNDCTL_DSP_NONBLOCK:
 	case SNDCTL_DSP_NONBLOCK:
+		spin_lock(&file->f_lock);
 		file->f_flags |= O_NONBLOCK;
 		file->f_flags |= O_NONBLOCK;
+		spin_unlock(&file->f_lock);
 		return 0;
 		return 0;
 
 
 	case SNDCTL_DSP_GETODELAY:
 	case SNDCTL_DSP_GETODELAY:

+ 2 - 0
sound/oss/vwsnd.c

@@ -2673,7 +2673,9 @@ static int vwsnd_audio_do_ioctl(struct inode *inode,
 
 
 	case SNDCTL_DSP_NONBLOCK:	/* _SIO  ('P',14) */
 	case SNDCTL_DSP_NONBLOCK:	/* _SIO  ('P',14) */
 		DBGX("SNDCTL_DSP_NONBLOCK\n");
 		DBGX("SNDCTL_DSP_NONBLOCK\n");
+		spin_lock(&file->f_lock);
 		file->f_flags |= O_NONBLOCK;
 		file->f_flags |= O_NONBLOCK;
+		spin_unlock(&file->f_lock);
 		return 0;
 		return 0;
 
 
 	case SNDCTL_DSP_RESET:		/* _SIO  ('P', 0) */
 	case SNDCTL_DSP_RESET:		/* _SIO  ('P', 0) */