filelock: add a new locks_inode_context accessor function
authorJeff Layton <jlayton@kernel.org>
Wed, 16 Nov 2022 14:02:30 +0000 (09:02 -0500)
committerJeff Layton <jlayton@kernel.org>
Wed, 30 Nov 2022 10:08:10 +0000 (05:08 -0500)
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: Christoph Hellwig <hch@lst.de>
Signed-off-by: Jeff Layton <jlayton@kernel.org>
fs/locks.c
include/linux/fs.h

index 9ccf89b..8e48b3d 100644 (file)
@@ -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;
 
index 6165c62..fd0a795 100644 (file)
@@ -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)