mirror of
https://github.com/versity/scoutfs.git
synced 2026-08-29 04:06:57 +00:00
scoutfs: add lock coverage for data paths
Use per_task storage on the inode to pass locks from high level read and write lock holders down into the callbacks that operate under the locks so that the locks can then be passed to the item functions. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
+22
-6
@@ -908,7 +908,8 @@ out:
|
||||
*/
|
||||
static int find_alloc_block(struct super_block *sb, struct block_mapping *map,
|
||||
struct scoutfs_key_buf *map_key,
|
||||
unsigned map_ind, bool map_exists)
|
||||
unsigned map_ind, bool map_exists,
|
||||
struct scoutfs_lock *data_lock)
|
||||
{
|
||||
DECLARE_DATA_INFO(sb, datinf);
|
||||
struct task_cursor *curs;
|
||||
@@ -958,7 +959,7 @@ static int find_alloc_block(struct super_block *sb, struct block_mapping *map,
|
||||
/* ensure that we can copy in encoded without failing */
|
||||
scoutfs_kvec_init(val, map->encoded, sizeof(map->encoded));
|
||||
if (map_exists)
|
||||
ret = scoutfs_item_update(sb, map_key, val, NULL);
|
||||
ret = scoutfs_item_update(sb, map_key, val, data_lock->end);
|
||||
else
|
||||
ret = scoutfs_item_create(sb, map_key, val);
|
||||
if (ret)
|
||||
@@ -1000,6 +1001,7 @@ static int scoutfs_get_block(struct inode *inode, sector_t iblock,
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_block_mapping_key bmk;
|
||||
struct scoutfs_key_buf key;
|
||||
struct scoutfs_lock *lock;
|
||||
struct block_mapping *map;
|
||||
SCOUTFS_DECLARE_KVEC(val);
|
||||
bool exists;
|
||||
@@ -1007,6 +1009,10 @@ static int scoutfs_get_block(struct inode *inode, sector_t iblock,
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
lock = scoutfs_per_task_get(&si->pt_data_lock);
|
||||
if (WARN_ON_ONCE(!lock))
|
||||
return -EINVAL;
|
||||
|
||||
map = kmalloc(sizeof(struct block_mapping), GFP_NOFS);
|
||||
if (!map)
|
||||
return -ENOMEM;
|
||||
@@ -1015,7 +1021,7 @@ static int scoutfs_get_block(struct inode *inode, sector_t iblock,
|
||||
scoutfs_kvec_init(val, map->encoded, sizeof(map->encoded));
|
||||
|
||||
/* find the mapping item that covers the logical block */
|
||||
ret = scoutfs_item_lookup(sb, &key, val, NULL);
|
||||
ret = scoutfs_item_lookup(sb, &key, val, lock);
|
||||
if (ret < 0) {
|
||||
if (ret != -ENOENT)
|
||||
goto out;
|
||||
@@ -1044,7 +1050,7 @@ static int scoutfs_get_block(struct inode *inode, sector_t iblock,
|
||||
* and try again if we've already done a bulk alloc in
|
||||
* our transaction.
|
||||
*/
|
||||
ret = find_alloc_block(sb, map, &key, ind, exists);
|
||||
ret = find_alloc_block(sb, map, &key, ind, exists, lock);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
@@ -1133,11 +1139,17 @@ static int scoutfs_write_begin(struct file *file,
|
||||
struct page **pagep, void **fsdata)
|
||||
{
|
||||
struct inode *inode = mapping->host;
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_lock *lock;
|
||||
int ret;
|
||||
|
||||
trace_scoutfs_write_begin(sb, scoutfs_ino(inode), (__u64)pos, len);
|
||||
|
||||
lock = scoutfs_per_task_get(&si->pt_data_lock);
|
||||
if (WARN_ON_ONCE(!lock))
|
||||
return -EINVAL;
|
||||
|
||||
ret = scoutfs_hold_trans(sb, SIC_WRITE_BEGIN());
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -1146,7 +1158,7 @@ static int scoutfs_write_begin(struct file *file,
|
||||
flags |= AOP_FLAG_NOFS;
|
||||
|
||||
/* generic write_end updates i_size and calls dirty_inode */
|
||||
ret = scoutfs_dirty_inode_item(inode, NULL);
|
||||
ret = scoutfs_dirty_inode_item(inode, lock);
|
||||
if (ret == 0)
|
||||
ret = block_write_begin(mapping, pos, len, flags, pagep,
|
||||
scoutfs_get_block);
|
||||
@@ -1163,11 +1175,15 @@ static int scoutfs_write_end(struct file *file, struct address_space *mapping,
|
||||
struct inode *inode = mapping->host;
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_lock *lock;
|
||||
int ret;
|
||||
|
||||
trace_scoutfs_write_end(sb, scoutfs_ino(inode), page->index, (u64)pos,
|
||||
len, copied);
|
||||
|
||||
/* always call write_end, update_inode will bark if there's no lock */
|
||||
lock = scoutfs_per_task_get(&si->pt_data_lock);
|
||||
|
||||
ret = generic_write_end(file, mapping, pos, len, copied, page, fsdata);
|
||||
if (ret > 0) {
|
||||
if (!si->staging) {
|
||||
@@ -1175,7 +1191,7 @@ static int scoutfs_write_end(struct file *file, struct address_space *mapping,
|
||||
scoutfs_inode_inc_data_version(inode);
|
||||
}
|
||||
/* XXX kind of a big hammer, inode life cycle needs work */
|
||||
scoutfs_update_inode_item(inode, NULL);
|
||||
scoutfs_update_inode_item(inode, lock);
|
||||
scoutfs_inode_queue_writeback(inode);
|
||||
}
|
||||
scoutfs_release_trans(sb);
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
#include "item.h"
|
||||
#include "lock.h"
|
||||
#include "file.h"
|
||||
#include "inode.h"
|
||||
#include "per_task.h"
|
||||
|
||||
/* TODO: Direct I/O, AIO */
|
||||
ssize_t scoutfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
|
||||
@@ -33,14 +35,18 @@ ssize_t scoutfs_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_lock *inode_lock = NULL;
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent);
|
||||
int ret;
|
||||
|
||||
ret = scoutfs_lock_inode(sb, DLM_LOCK_PR, SCOUTFS_LKF_REFRESH_INODE,
|
||||
inode, &inode_lock);
|
||||
if (ret == 0) {
|
||||
scoutfs_per_task_add(&si->pt_data_lock, &pt_ent, inode_lock);
|
||||
ret = generic_file_aio_read(iocb, iov, nr_segs, pos);
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
scoutfs_unlock(sb, inode_lock, DLM_LOCK_PR);
|
||||
}
|
||||
|
||||
@@ -52,8 +58,10 @@ ssize_t scoutfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
||||
{
|
||||
struct file *file = iocb->ki_filp;
|
||||
struct inode *inode = file_inode(file);
|
||||
struct scoutfs_inode_info *si = SCOUTFS_I(inode);
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct scoutfs_lock *inode_lock = NULL;
|
||||
SCOUTFS_DECLARE_PER_TASK_ENTRY(pt_ent);
|
||||
int ret;
|
||||
|
||||
if (iocb->ki_left == 0) /* Does this even happen? */
|
||||
@@ -65,10 +73,13 @@ ssize_t scoutfs_file_aio_write(struct kiocb *iocb, const struct iovec *iov,
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
scoutfs_per_task_add(&si->pt_data_lock, &pt_ent, inode_lock);
|
||||
|
||||
/* XXX: remove SUID bit */
|
||||
|
||||
ret = __generic_file_aio_write(iocb, iov, nr_segs, &iocb->ki_pos);
|
||||
|
||||
scoutfs_per_task_del(&si->pt_data_lock, &pt_ent);
|
||||
scoutfs_unlock(sb, inode_lock, DLM_LOCK_EX);
|
||||
out:
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
@@ -73,6 +73,7 @@ static void scoutfs_inode_ctor(void *obj)
|
||||
mutex_init(&ci->item_mutex);
|
||||
seqcount_init(&ci->seqcount);
|
||||
ci->staging = false;
|
||||
scoutfs_per_task_init(&ci->pt_data_lock);
|
||||
init_rwsem(&ci->xattr_rwsem);
|
||||
RB_CLEAR_NODE(&ci->writeback_node);
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "key.h"
|
||||
#include "lock.h"
|
||||
#include "per_task.h"
|
||||
|
||||
struct scoutfs_lock;
|
||||
|
||||
@@ -34,6 +35,7 @@ struct scoutfs_inode_info {
|
||||
/* initialized once for slab object */
|
||||
seqcount_t seqcount;
|
||||
bool staging; /* holder of i_mutex is staging */
|
||||
struct scoutfs_per_task pt_data_lock;
|
||||
struct rw_semaphore xattr_rwsem;
|
||||
struct rb_node writeback_node;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user