Commit 401a8b8f authored by Jeff Layton's avatar Jeff Layton
Browse files

filelock: add a new locks_inode_context accessor function



There are a number of places in the kernel that are accessing the
inode->i_flctx field without smp_load_acquire. This is required to
ensure that the caller doesn't see a partially-initialized structure.

Add a new accessor function for it to make this clear and convert all of
the relevant accesses in locks.c to use it. Also, convert
locks_free_lock_context to use the helper as well instead of just doing
a "bare" assignment.

Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarJeff Layton <jlayton@kernel.org>
parent ab1ddef9
Loading
Loading
Loading
Loading
+12 −12
Original line number Diff line number Diff line
@@ -175,7 +175,7 @@ locks_get_lock_context(struct inode *inode, int type)
	struct file_lock_context *ctx;

	/* paired with cmpxchg() below */
	ctx = smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (likely(ctx) || type == F_UNLCK)
		goto out;

@@ -194,7 +194,7 @@ locks_get_lock_context(struct inode *inode, int type)
	 */
	if (cmpxchg(&inode->i_flctx, NULL, ctx)) {
		kmem_cache_free(flctx_cache, ctx);
		ctx = smp_load_acquire(&inode->i_flctx);
		ctx = locks_inode_context(inode);
	}
out:
	trace_locks_get_lock_context(inode, type, ctx);
@@ -247,7 +247,7 @@ locks_check_ctx_file_list(struct file *filp, struct list_head *list,
void
locks_free_lock_context(struct inode *inode)
{
	struct file_lock_context *ctx = inode->i_flctx;
	struct file_lock_context *ctx = locks_inode_context(inode);

	if (unlikely(ctx)) {
		locks_check_ctx_lists(inode);
@@ -891,7 +891,7 @@ posix_test_lock(struct file *filp, struct file_lock *fl)
	void *owner;
	void (*func)(void);

	ctx = smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (!ctx || list_empty_careful(&ctx->flc_posix)) {
		fl->fl_type = F_UNLCK;
		return;
@@ -1483,7 +1483,7 @@ int __break_lease(struct inode *inode, unsigned int mode, unsigned int type)
	new_fl->fl_flags = type;

	/* typically we will check that ctx is non-NULL before calling */
	ctx = smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (!ctx) {
		WARN_ON_ONCE(1);
		goto free_lock;
@@ -1588,7 +1588,7 @@ void lease_get_mtime(struct inode *inode, struct timespec64 *time)
	struct file_lock_context *ctx;
	struct file_lock *fl;

	ctx = smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (ctx && !list_empty_careful(&ctx->flc_lease)) {
		spin_lock(&ctx->flc_lock);
		fl = list_first_entry_or_null(&ctx->flc_lease,
@@ -1634,7 +1634,7 @@ int fcntl_getlease(struct file *filp)
	int type = F_UNLCK;
	LIST_HEAD(dispose);

	ctx = smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (ctx && !list_empty_careful(&ctx->flc_lease)) {
		percpu_down_read(&file_rwsem);
		spin_lock(&ctx->flc_lock);
@@ -1823,7 +1823,7 @@ static int generic_delete_lease(struct file *filp, void *owner)
	struct file_lock_context *ctx;
	LIST_HEAD(dispose);

	ctx = smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (!ctx) {
		trace_generic_delete_lease(inode, NULL);
		return error;
@@ -2563,7 +2563,7 @@ void locks_remove_posix(struct file *filp, fl_owner_t owner)
	 * posix_lock_file().  Another process could be setting a lock on this
	 * file at the same time, but we wouldn't remove that lock anyway.
	 */
	ctx =  smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (!ctx || list_empty(&ctx->flc_posix))
		return;

@@ -2636,7 +2636,7 @@ void locks_remove_file(struct file *filp)
{
	struct file_lock_context *ctx;

	ctx = smp_load_acquire(&locks_inode(filp)->i_flctx);
	ctx = locks_inode_context(locks_inode(filp));
	if (!ctx)
		return;

@@ -2684,7 +2684,7 @@ bool vfs_inode_has_locks(struct inode *inode)
	struct file_lock_context *ctx;
	bool ret;

	ctx = smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (!ctx)
		return false;

@@ -2865,7 +2865,7 @@ void show_fd_locks(struct seq_file *f,
	struct file_lock_context *ctx;
	int id = 0;

	ctx = smp_load_acquire(&inode->i_flctx);
	ctx = locks_inode_context(inode);
	if (!ctx)
		return;

+14 −0
Original line number Diff line number Diff line
@@ -1187,6 +1187,13 @@ extern void show_fd_locks(struct seq_file *f,
			 struct file *filp, struct files_struct *files);
extern bool locks_owner_has_blockers(struct file_lock_context *flctx,
			fl_owner_t owner);

static inline struct file_lock_context *
locks_inode_context(const struct inode *inode)
{
	return smp_load_acquire(&inode->i_flctx);
}

#else /* !CONFIG_FILE_LOCKING */
static inline int fcntl_getlk(struct file *file, unsigned int cmd,
			      struct flock __user *user)
@@ -1332,6 +1339,13 @@ static inline bool locks_owner_has_blockers(struct file_lock_context *flctx,
{
	return false;
}

static inline struct file_lock_context *
locks_inode_context(const struct inode *inode)
{
	return NULL;
}

#endif /* !CONFIG_FILE_LOCKING */

static inline struct inode *file_inode(const struct file *f)