diff --git a/kmod/src/data.c b/kmod/src/data.c index 8c249acd..05083e8b 100644 --- a/kmod/src/data.c +++ b/kmod/src/data.c @@ -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); diff --git a/kmod/src/file.c b/kmod/src/file.c index 2878d61e..b59df5e0 100644 --- a/kmod/src/file.c +++ b/kmod/src/file.c @@ -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); diff --git a/kmod/src/inode.c b/kmod/src/inode.c index 4b144faa..08e7b31e 100644 --- a/kmod/src/inode.c +++ b/kmod/src/inode.c @@ -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); diff --git a/kmod/src/inode.h b/kmod/src/inode.h index f590fdfb..dc9a2e60 100644 --- a/kmod/src/inode.h +++ b/kmod/src/inode.h @@ -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;