Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit db1dd4d3 authored by Jonathan Corbet's avatar Jonathan Corbet
Browse files

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: default avatarChristoph Hellwig <hch@lst.de>
Cc: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: default avatarJonathan Corbet <corbet@lwn.net>
parent 68499914
Loading
Loading
Loading
Loading
+2 −3
Original line number Original line Diff line number Diff line
@@ -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 */
	spin_lock(&file->f_lock);
	lock_kernel();
	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;
}
}


+6 −1
Original line number Original line Diff line number Diff line
@@ -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;
+2 −0
Original line number Original line Diff line number Diff line
@@ -189,7 +189,9 @@ static int setfl(int fd, struct file * filp, unsigned long arg)
		}
		}
	}
	}


	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();
	unlock_kernel();
	return error;
	return error;
+4 −3
Original line number Original line Diff line number Diff line
@@ -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;
}
}


@@ -432,10 +434,12 @@ static int ioctl_fioasync(unsigned int fd, struct file *filp,
	if (error)
	if (error)
		return error;
		return error;


	spin_lock(&filp->f_lock);
	if (on)
	if (on)
		filp->f_flags |= FASYNC;
		filp->f_flags |= FASYNC;
	else
	else
		filp->f_flags &= ~FASYNC;
		filp->f_flags &= ~FASYNC;
	spin_unlock(&filp->f_lock);
	return error;
	return error;
}
}


@@ -499,10 +503,7 @@ 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:
+4 −1
Original line number Original line Diff line number Diff line
@@ -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);
Loading