Commit f66fd9f0 authored by Yan, Zheng's avatar Yan, Zheng Committed by Ilya Dryomov

ceph: pre-allocate data structure that tracks caps flushing

Signed-off-by: default avatarYan, Zheng <zyan@redhat.com>
parent e548e9b9
...@@ -1308,12 +1308,17 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -1308,12 +1308,17 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
struct inode *inode = file_inode(vma->vm_file); struct inode *inode = file_inode(vma->vm_file);
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_file_info *fi = vma->vm_file->private_data; struct ceph_file_info *fi = vma->vm_file->private_data;
struct ceph_cap_flush *prealloc_cf;
struct page *page = vmf->page; struct page *page = vmf->page;
loff_t off = page_offset(page); loff_t off = page_offset(page);
loff_t size = i_size_read(inode); loff_t size = i_size_read(inode);
size_t len; size_t len;
int want, got, ret; int want, got, ret;
prealloc_cf = ceph_alloc_cap_flush();
if (!prealloc_cf)
return VM_FAULT_SIGBUS;
if (ci->i_inline_version != CEPH_INLINE_NONE) { if (ci->i_inline_version != CEPH_INLINE_NONE) {
struct page *locked_page = NULL; struct page *locked_page = NULL;
if (off == 0) { if (off == 0) {
...@@ -1323,8 +1328,10 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -1323,8 +1328,10 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
ret = ceph_uninline_data(vma->vm_file, locked_page); ret = ceph_uninline_data(vma->vm_file, locked_page);
if (locked_page) if (locked_page)
unlock_page(locked_page); unlock_page(locked_page);
if (ret < 0) if (ret < 0) {
return VM_FAULT_SIGBUS; ret = VM_FAULT_SIGBUS;
goto out_free;
}
} }
if (off + PAGE_CACHE_SIZE <= size) if (off + PAGE_CACHE_SIZE <= size)
...@@ -1346,7 +1353,8 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -1346,7 +1353,8 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
break; break;
if (ret != -ERESTARTSYS) { if (ret != -ERESTARTSYS) {
WARN_ON(1); WARN_ON(1);
return VM_FAULT_SIGBUS; ret = VM_FAULT_SIGBUS;
goto out_free;
} }
} }
dout("page_mkwrite %p %llu~%zd got cap refs on %s\n", dout("page_mkwrite %p %llu~%zd got cap refs on %s\n",
...@@ -1381,7 +1389,8 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -1381,7 +1389,8 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
int dirty; int dirty;
spin_lock(&ci->i_ceph_lock); spin_lock(&ci->i_ceph_lock);
ci->i_inline_version = CEPH_INLINE_NONE; ci->i_inline_version = CEPH_INLINE_NONE;
dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR); dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR,
&prealloc_cf);
spin_unlock(&ci->i_ceph_lock); spin_unlock(&ci->i_ceph_lock);
if (dirty) if (dirty)
__mark_inode_dirty(inode, dirty); __mark_inode_dirty(inode, dirty);
...@@ -1390,6 +1399,8 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf) ...@@ -1390,6 +1399,8 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
dout("page_mkwrite %p %llu~%zd dropping cap refs on %s ret %d\n", dout("page_mkwrite %p %llu~%zd dropping cap refs on %s ret %d\n",
inode, off, len, ceph_cap_string(got), ret); inode, off, len, ceph_cap_string(got), ret);
ceph_put_cap_refs(ci, got); ceph_put_cap_refs(ci, got);
out_free:
ceph_free_cap_flush(prealloc_cf);
return ret; return ret;
} }
......
...@@ -1356,7 +1356,8 @@ static void ceph_flush_snaps(struct ceph_inode_info *ci) ...@@ -1356,7 +1356,8 @@ static void ceph_flush_snaps(struct ceph_inode_info *ci)
* Caller is then responsible for calling __mark_inode_dirty with the * Caller is then responsible for calling __mark_inode_dirty with the
* returned flags value. * returned flags value.
*/ */
int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask,
struct ceph_cap_flush **pcf)
{ {
struct ceph_mds_client *mdsc = struct ceph_mds_client *mdsc =
ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc; ceph_sb_to_client(ci->vfs_inode.i_sb)->mdsc;
...@@ -1376,6 +1377,9 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) ...@@ -1376,6 +1377,9 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
ceph_cap_string(was | mask)); ceph_cap_string(was | mask));
ci->i_dirty_caps |= mask; ci->i_dirty_caps |= mask;
if (was == 0) { if (was == 0) {
WARN_ON_ONCE(ci->i_prealloc_cap_flush);
swap(ci->i_prealloc_cap_flush, *pcf);
if (!ci->i_head_snapc) { if (!ci->i_head_snapc) {
WARN_ON_ONCE(!rwsem_is_locked(&mdsc->snap_rwsem)); WARN_ON_ONCE(!rwsem_is_locked(&mdsc->snap_rwsem));
ci->i_head_snapc = ceph_get_snap_context( ci->i_head_snapc = ceph_get_snap_context(
...@@ -1391,6 +1395,8 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask) ...@@ -1391,6 +1395,8 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
ihold(inode); ihold(inode);
dirty |= I_DIRTY_SYNC; dirty |= I_DIRTY_SYNC;
} }
} else {
WARN_ON_ONCE(!ci->i_prealloc_cap_flush);
} }
BUG_ON(list_empty(&ci->i_dirty_item)); BUG_ON(list_empty(&ci->i_dirty_item));
if (((was | ci->i_flushing_caps) & CEPH_CAP_FILE_BUFFER) && if (((was | ci->i_flushing_caps) & CEPH_CAP_FILE_BUFFER) &&
...@@ -1446,6 +1452,17 @@ static void __add_cap_flushing_to_mdsc(struct ceph_mds_client *mdsc, ...@@ -1446,6 +1452,17 @@ static void __add_cap_flushing_to_mdsc(struct ceph_mds_client *mdsc,
rb_insert_color(&cf->g_node, &mdsc->cap_flush_tree); rb_insert_color(&cf->g_node, &mdsc->cap_flush_tree);
} }
struct ceph_cap_flush *ceph_alloc_cap_flush(void)
{
return kmem_cache_alloc(ceph_cap_flush_cachep, GFP_KERNEL);
}
void ceph_free_cap_flush(struct ceph_cap_flush *cf)
{
if (cf)
kmem_cache_free(ceph_cap_flush_cachep, cf);
}
static u64 __get_oldest_flush_tid(struct ceph_mds_client *mdsc) static u64 __get_oldest_flush_tid(struct ceph_mds_client *mdsc)
{ {
struct rb_node *n = rb_first(&mdsc->cap_flush_tree); struct rb_node *n = rb_first(&mdsc->cap_flush_tree);
...@@ -1469,11 +1486,12 @@ static int __mark_caps_flushing(struct inode *inode, ...@@ -1469,11 +1486,12 @@ static int __mark_caps_flushing(struct inode *inode,
{ {
struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc; struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_cap_flush *cf; struct ceph_cap_flush *cf = NULL;
int flushing; int flushing;
BUG_ON(ci->i_dirty_caps == 0); BUG_ON(ci->i_dirty_caps == 0);
BUG_ON(list_empty(&ci->i_dirty_item)); BUG_ON(list_empty(&ci->i_dirty_item));
BUG_ON(!ci->i_prealloc_cap_flush);
flushing = ci->i_dirty_caps; flushing = ci->i_dirty_caps;
dout("__mark_caps_flushing flushing %s, flushing_caps %s -> %s\n", dout("__mark_caps_flushing flushing %s, flushing_caps %s -> %s\n",
...@@ -1484,7 +1502,7 @@ static int __mark_caps_flushing(struct inode *inode, ...@@ -1484,7 +1502,7 @@ static int __mark_caps_flushing(struct inode *inode,
ci->i_dirty_caps = 0; ci->i_dirty_caps = 0;
dout(" inode %p now !dirty\n", inode); dout(" inode %p now !dirty\n", inode);
cf = kmalloc(sizeof(*cf), GFP_ATOMIC); swap(cf, ci->i_prealloc_cap_flush);
cf->caps = flushing; cf->caps = flushing;
cf->kick = false; cf->kick = false;
...@@ -3075,7 +3093,7 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid, ...@@ -3075,7 +3093,7 @@ static void handle_cap_flush_ack(struct inode *inode, u64 flush_tid,
cf = list_first_entry(&to_remove, cf = list_first_entry(&to_remove,
struct ceph_cap_flush, list); struct ceph_cap_flush, list);
list_del(&cf->list); list_del(&cf->list);
kfree(cf); ceph_free_cap_flush(cf);
} }
if (drop) if (drop)
iput(inode); iput(inode);
......
...@@ -939,6 +939,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -939,6 +939,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_osd_client *osdc = struct ceph_osd_client *osdc =
&ceph_sb_to_client(inode->i_sb)->client->osdc; &ceph_sb_to_client(inode->i_sb)->client->osdc;
struct ceph_cap_flush *prealloc_cf;
ssize_t count, written = 0; ssize_t count, written = 0;
int err, want, got; int err, want, got;
loff_t pos; loff_t pos;
...@@ -946,6 +947,10 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -946,6 +947,10 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
if (ceph_snap(inode) != CEPH_NOSNAP) if (ceph_snap(inode) != CEPH_NOSNAP)
return -EROFS; return -EROFS;
prealloc_cf = ceph_alloc_cap_flush();
if (!prealloc_cf)
return -ENOMEM;
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
/* We can write back this queue in page reclaim */ /* We can write back this queue in page reclaim */
...@@ -1050,7 +1055,8 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -1050,7 +1055,8 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
int dirty; int dirty;
spin_lock(&ci->i_ceph_lock); spin_lock(&ci->i_ceph_lock);
ci->i_inline_version = CEPH_INLINE_NONE; ci->i_inline_version = CEPH_INLINE_NONE;
dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR); dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR,
&prealloc_cf);
spin_unlock(&ci->i_ceph_lock); spin_unlock(&ci->i_ceph_lock);
if (dirty) if (dirty)
__mark_inode_dirty(inode, dirty); __mark_inode_dirty(inode, dirty);
...@@ -1074,6 +1080,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) ...@@ -1074,6 +1080,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from)
out: out:
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
out_unlocked: out_unlocked:
ceph_free_cap_flush(prealloc_cf);
current->backing_dev_info = NULL; current->backing_dev_info = NULL;
return written ? written : err; return written ? written : err;
} }
...@@ -1270,6 +1277,7 @@ static long ceph_fallocate(struct file *file, int mode, ...@@ -1270,6 +1277,7 @@ static long ceph_fallocate(struct file *file, int mode,
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_osd_client *osdc = struct ceph_osd_client *osdc =
&ceph_inode_to_client(inode)->client->osdc; &ceph_inode_to_client(inode)->client->osdc;
struct ceph_cap_flush *prealloc_cf;
int want, got = 0; int want, got = 0;
int dirty; int dirty;
int ret = 0; int ret = 0;
...@@ -1282,6 +1290,10 @@ static long ceph_fallocate(struct file *file, int mode, ...@@ -1282,6 +1290,10 @@ static long ceph_fallocate(struct file *file, int mode,
if (!S_ISREG(inode->i_mode)) if (!S_ISREG(inode->i_mode))
return -EOPNOTSUPP; return -EOPNOTSUPP;
prealloc_cf = ceph_alloc_cap_flush();
if (!prealloc_cf)
return -ENOMEM;
mutex_lock(&inode->i_mutex); mutex_lock(&inode->i_mutex);
if (ceph_snap(inode) != CEPH_NOSNAP) { if (ceph_snap(inode) != CEPH_NOSNAP) {
...@@ -1328,7 +1340,8 @@ static long ceph_fallocate(struct file *file, int mode, ...@@ -1328,7 +1340,8 @@ static long ceph_fallocate(struct file *file, int mode,
if (!ret) { if (!ret) {
spin_lock(&ci->i_ceph_lock); spin_lock(&ci->i_ceph_lock);
ci->i_inline_version = CEPH_INLINE_NONE; ci->i_inline_version = CEPH_INLINE_NONE;
dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR); dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR,
&prealloc_cf);
spin_unlock(&ci->i_ceph_lock); spin_unlock(&ci->i_ceph_lock);
if (dirty) if (dirty)
__mark_inode_dirty(inode, dirty); __mark_inode_dirty(inode, dirty);
...@@ -1337,6 +1350,7 @@ static long ceph_fallocate(struct file *file, int mode, ...@@ -1337,6 +1350,7 @@ static long ceph_fallocate(struct file *file, int mode,
ceph_put_cap_refs(ci, got); ceph_put_cap_refs(ci, got);
unlock: unlock:
mutex_unlock(&inode->i_mutex); mutex_unlock(&inode->i_mutex);
ceph_free_cap_flush(prealloc_cf);
return ret; return ret;
} }
......
...@@ -416,6 +416,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb) ...@@ -416,6 +416,7 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
ci->i_flushing_caps = 0; ci->i_flushing_caps = 0;
INIT_LIST_HEAD(&ci->i_dirty_item); INIT_LIST_HEAD(&ci->i_dirty_item);
INIT_LIST_HEAD(&ci->i_flushing_item); INIT_LIST_HEAD(&ci->i_flushing_item);
ci->i_prealloc_cap_flush = NULL;
ci->i_cap_flush_tree = RB_ROOT; ci->i_cap_flush_tree = RB_ROOT;
init_waitqueue_head(&ci->i_cap_wq); init_waitqueue_head(&ci->i_cap_wq);
ci->i_hold_caps_min = 0; ci->i_hold_caps_min = 0;
...@@ -1720,6 +1721,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -1720,6 +1721,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
const unsigned int ia_valid = attr->ia_valid; const unsigned int ia_valid = attr->ia_valid;
struct ceph_mds_request *req; struct ceph_mds_request *req;
struct ceph_mds_client *mdsc = ceph_sb_to_client(dentry->d_sb)->mdsc; struct ceph_mds_client *mdsc = ceph_sb_to_client(dentry->d_sb)->mdsc;
struct ceph_cap_flush *prealloc_cf;
int issued; int issued;
int release = 0, dirtied = 0; int release = 0, dirtied = 0;
int mask = 0; int mask = 0;
...@@ -1734,10 +1736,16 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -1734,10 +1736,16 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
if (err != 0) if (err != 0)
return err; return err;
prealloc_cf = ceph_alloc_cap_flush();
if (!prealloc_cf)
return -ENOMEM;
req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETATTR, req = ceph_mdsc_create_request(mdsc, CEPH_MDS_OP_SETATTR,
USE_AUTH_MDS); USE_AUTH_MDS);
if (IS_ERR(req)) if (IS_ERR(req)) {
ceph_free_cap_flush(prealloc_cf);
return PTR_ERR(req); return PTR_ERR(req);
}
spin_lock(&ci->i_ceph_lock); spin_lock(&ci->i_ceph_lock);
issued = __ceph_caps_issued(ci, NULL); issued = __ceph_caps_issued(ci, NULL);
...@@ -1895,7 +1903,8 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -1895,7 +1903,8 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
dout("setattr %p ATTR_FILE ... hrm!\n", inode); dout("setattr %p ATTR_FILE ... hrm!\n", inode);
if (dirtied) { if (dirtied) {
inode_dirty_flags = __ceph_mark_dirty_caps(ci, dirtied); inode_dirty_flags = __ceph_mark_dirty_caps(ci, dirtied,
&prealloc_cf);
inode->i_ctime = CURRENT_TIME; inode->i_ctime = CURRENT_TIME;
} }
...@@ -1927,9 +1936,11 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr) ...@@ -1927,9 +1936,11 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
ceph_mdsc_put_request(req); ceph_mdsc_put_request(req);
if (mask & CEPH_SETATTR_SIZE) if (mask & CEPH_SETATTR_SIZE)
__ceph_do_pending_vmtruncate(inode); __ceph_do_pending_vmtruncate(inode);
ceph_free_cap_flush(prealloc_cf);
return err; return err;
out_put: out_put:
ceph_mdsc_put_request(req); ceph_mdsc_put_request(req);
ceph_free_cap_flush(prealloc_cf);
return err; return err;
} }
......
...@@ -1189,6 +1189,10 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, ...@@ -1189,6 +1189,10 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
} }
spin_unlock(&mdsc->cap_dirty_lock); spin_unlock(&mdsc->cap_dirty_lock);
if (!ci->i_dirty_caps && ci->i_prealloc_cap_flush) {
list_add(&ci->i_prealloc_cap_flush->list, &to_remove);
ci->i_prealloc_cap_flush = NULL;
}
} }
spin_unlock(&ci->i_ceph_lock); spin_unlock(&ci->i_ceph_lock);
while (!list_empty(&to_remove)) { while (!list_empty(&to_remove)) {
...@@ -1196,7 +1200,7 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap, ...@@ -1196,7 +1200,7 @@ static int remove_session_caps_cb(struct inode *inode, struct ceph_cap *cap,
cf = list_first_entry(&to_remove, cf = list_first_entry(&to_remove,
struct ceph_cap_flush, list); struct ceph_cap_flush, list);
list_del(&cf->list); list_del(&cf->list);
kfree(cf); ceph_free_cap_flush(cf);
} }
while (drop--) while (drop--)
iput(inode); iput(inode);
......
...@@ -622,6 +622,7 @@ static void destroy_fs_client(struct ceph_fs_client *fsc) ...@@ -622,6 +622,7 @@ static void destroy_fs_client(struct ceph_fs_client *fsc)
*/ */
struct kmem_cache *ceph_inode_cachep; struct kmem_cache *ceph_inode_cachep;
struct kmem_cache *ceph_cap_cachep; struct kmem_cache *ceph_cap_cachep;
struct kmem_cache *ceph_cap_flush_cachep;
struct kmem_cache *ceph_dentry_cachep; struct kmem_cache *ceph_dentry_cachep;
struct kmem_cache *ceph_file_cachep; struct kmem_cache *ceph_file_cachep;
...@@ -647,6 +648,10 @@ static int __init init_caches(void) ...@@ -647,6 +648,10 @@ static int __init init_caches(void)
SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD); SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
if (ceph_cap_cachep == NULL) if (ceph_cap_cachep == NULL)
goto bad_cap; goto bad_cap;
ceph_cap_flush_cachep = KMEM_CACHE(ceph_cap_flush,
SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
if (ceph_cap_flush_cachep == NULL)
goto bad_cap_flush;
ceph_dentry_cachep = KMEM_CACHE(ceph_dentry_info, ceph_dentry_cachep = KMEM_CACHE(ceph_dentry_info,
SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD); SLAB_RECLAIM_ACCOUNT|SLAB_MEM_SPREAD);
...@@ -665,6 +670,8 @@ static int __init init_caches(void) ...@@ -665,6 +670,8 @@ static int __init init_caches(void)
bad_file: bad_file:
kmem_cache_destroy(ceph_dentry_cachep); kmem_cache_destroy(ceph_dentry_cachep);
bad_dentry: bad_dentry:
kmem_cache_destroy(ceph_cap_flush_cachep);
bad_cap_flush:
kmem_cache_destroy(ceph_cap_cachep); kmem_cache_destroy(ceph_cap_cachep);
bad_cap: bad_cap:
kmem_cache_destroy(ceph_inode_cachep); kmem_cache_destroy(ceph_inode_cachep);
...@@ -681,6 +688,7 @@ static void destroy_caches(void) ...@@ -681,6 +688,7 @@ static void destroy_caches(void)
kmem_cache_destroy(ceph_inode_cachep); kmem_cache_destroy(ceph_inode_cachep);
kmem_cache_destroy(ceph_cap_cachep); kmem_cache_destroy(ceph_cap_cachep);
kmem_cache_destroy(ceph_cap_flush_cachep);
kmem_cache_destroy(ceph_dentry_cachep); kmem_cache_destroy(ceph_dentry_cachep);
kmem_cache_destroy(ceph_file_cachep); kmem_cache_destroy(ceph_file_cachep);
......
...@@ -309,6 +309,7 @@ struct ceph_inode_info { ...@@ -309,6 +309,7 @@ struct ceph_inode_info {
/* we need to track cap writeback on a per-cap-bit basis, to allow /* we need to track cap writeback on a per-cap-bit basis, to allow
* overlapping, pipelined cap flushes to the mds. we can probably * overlapping, pipelined cap flushes to the mds. we can probably
* reduce the tid to 8 bits if we're concerned about inode size. */ * reduce the tid to 8 bits if we're concerned about inode size. */
struct ceph_cap_flush *i_prealloc_cap_flush;
struct rb_root i_cap_flush_tree; struct rb_root i_cap_flush_tree;
wait_queue_head_t i_cap_wq; /* threads waiting on a capability */ wait_queue_head_t i_cap_wq; /* threads waiting on a capability */
unsigned long i_hold_caps_min; /* jiffies */ unsigned long i_hold_caps_min; /* jiffies */
...@@ -578,7 +579,10 @@ static inline int __ceph_caps_dirty(struct ceph_inode_info *ci) ...@@ -578,7 +579,10 @@ static inline int __ceph_caps_dirty(struct ceph_inode_info *ci)
{ {
return ci->i_dirty_caps | ci->i_flushing_caps; return ci->i_dirty_caps | ci->i_flushing_caps;
} }
extern int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask); extern struct ceph_cap_flush *ceph_alloc_cap_flush(void);
extern void ceph_free_cap_flush(struct ceph_cap_flush *cf);
extern int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask,
struct ceph_cap_flush **pcf);
extern int __ceph_caps_revoking_other(struct ceph_inode_info *ci, extern int __ceph_caps_revoking_other(struct ceph_inode_info *ci,
struct ceph_cap *ocap, int mask); struct ceph_cap *ocap, int mask);
......
...@@ -912,6 +912,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name, ...@@ -912,6 +912,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name,
struct ceph_vxattr *vxattr; struct ceph_vxattr *vxattr;
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_mds_client *mdsc = ceph_sb_to_client(dentry->d_sb)->mdsc; struct ceph_mds_client *mdsc = ceph_sb_to_client(dentry->d_sb)->mdsc;
struct ceph_cap_flush *prealloc_cf = NULL;
int issued; int issued;
int err; int err;
int dirty = 0; int dirty = 0;
...@@ -950,6 +951,10 @@ int __ceph_setxattr(struct dentry *dentry, const char *name, ...@@ -950,6 +951,10 @@ int __ceph_setxattr(struct dentry *dentry, const char *name,
if (!xattr) if (!xattr)
goto out; goto out;
prealloc_cf = ceph_alloc_cap_flush();
if (!prealloc_cf)
goto out;
spin_lock(&ci->i_ceph_lock); spin_lock(&ci->i_ceph_lock);
retry: retry:
issued = __ceph_caps_issued(ci, NULL); issued = __ceph_caps_issued(ci, NULL);
...@@ -991,7 +996,8 @@ int __ceph_setxattr(struct dentry *dentry, const char *name, ...@@ -991,7 +996,8 @@ int __ceph_setxattr(struct dentry *dentry, const char *name,
flags, value ? 1 : -1, &xattr); flags, value ? 1 : -1, &xattr);
if (!err) { if (!err) {
dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL,
&prealloc_cf);
ci->i_xattrs.dirty = true; ci->i_xattrs.dirty = true;
inode->i_ctime = CURRENT_TIME; inode->i_ctime = CURRENT_TIME;
} }
...@@ -1001,6 +1007,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name, ...@@ -1001,6 +1007,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name,
up_read(&mdsc->snap_rwsem); up_read(&mdsc->snap_rwsem);
if (dirty) if (dirty)
__mark_inode_dirty(inode, dirty); __mark_inode_dirty(inode, dirty);
ceph_free_cap_flush(prealloc_cf);
return err; return err;
do_sync: do_sync:
...@@ -1010,6 +1017,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name, ...@@ -1010,6 +1017,7 @@ int __ceph_setxattr(struct dentry *dentry, const char *name,
up_read(&mdsc->snap_rwsem); up_read(&mdsc->snap_rwsem);
err = ceph_sync_setxattr(dentry, name, value, size, flags); err = ceph_sync_setxattr(dentry, name, value, size, flags);
out: out:
ceph_free_cap_flush(prealloc_cf);
kfree(newname); kfree(newname);
kfree(newval); kfree(newval);
kfree(xattr); kfree(xattr);
...@@ -1062,6 +1070,7 @@ int __ceph_removexattr(struct dentry *dentry, const char *name) ...@@ -1062,6 +1070,7 @@ int __ceph_removexattr(struct dentry *dentry, const char *name)
struct ceph_vxattr *vxattr; struct ceph_vxattr *vxattr;
struct ceph_inode_info *ci = ceph_inode(inode); struct ceph_inode_info *ci = ceph_inode(inode);
struct ceph_mds_client *mdsc = ceph_sb_to_client(dentry->d_sb)->mdsc; struct ceph_mds_client *mdsc = ceph_sb_to_client(dentry->d_sb)->mdsc;
struct ceph_cap_flush *prealloc_cf = NULL;
int issued; int issued;
int err; int err;
int required_blob_size; int required_blob_size;
...@@ -1079,6 +1088,10 @@ int __ceph_removexattr(struct dentry *dentry, const char *name) ...@@ -1079,6 +1088,10 @@ int __ceph_removexattr(struct dentry *dentry, const char *name)
if (!strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN)) if (!strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN))
goto do_sync_unlocked; goto do_sync_unlocked;
prealloc_cf = ceph_alloc_cap_flush();
if (!prealloc_cf)
return -ENOMEM;
err = -ENOMEM; err = -ENOMEM;
spin_lock(&ci->i_ceph_lock); spin_lock(&ci->i_ceph_lock);
retry: retry:
...@@ -1120,7 +1133,8 @@ int __ceph_removexattr(struct dentry *dentry, const char *name) ...@@ -1120,7 +1133,8 @@ int __ceph_removexattr(struct dentry *dentry, const char *name)
err = __remove_xattr_by_name(ceph_inode(inode), name); err = __remove_xattr_by_name(ceph_inode(inode), name);
dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL); dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_XATTR_EXCL,
&prealloc_cf);
ci->i_xattrs.dirty = true; ci->i_xattrs.dirty = true;
inode->i_ctime = CURRENT_TIME; inode->i_ctime = CURRENT_TIME;
spin_unlock(&ci->i_ceph_lock); spin_unlock(&ci->i_ceph_lock);
...@@ -1128,12 +1142,14 @@ int __ceph_removexattr(struct dentry *dentry, const char *name) ...@@ -1128,12 +1142,14 @@ int __ceph_removexattr(struct dentry *dentry, const char *name)
up_read(&mdsc->snap_rwsem); up_read(&mdsc->snap_rwsem);
if (dirty) if (dirty)
__mark_inode_dirty(inode, dirty); __mark_inode_dirty(inode, dirty);
ceph_free_cap_flush(prealloc_cf);
return err; return err;
do_sync: do_sync:
spin_unlock(&ci->i_ceph_lock); spin_unlock(&ci->i_ceph_lock);
do_sync_unlocked: do_sync_unlocked:
if (lock_snap_rwsem) if (lock_snap_rwsem)
up_read(&mdsc->snap_rwsem); up_read(&mdsc->snap_rwsem);
ceph_free_cap_flush(prealloc_cf);
err = ceph_send_removexattr(dentry, name); err = ceph_send_removexattr(dentry, name);
return err; return err;
} }
......
...@@ -174,6 +174,7 @@ static inline int calc_pages_for(u64 off, u64 len) ...@@ -174,6 +174,7 @@ static inline int calc_pages_for(u64 off, u64 len)
extern struct kmem_cache *ceph_inode_cachep; extern struct kmem_cache *ceph_inode_cachep;
extern struct kmem_cache *ceph_cap_cachep; extern struct kmem_cache *ceph_cap_cachep;
extern struct kmem_cache *ceph_cap_flush_cachep;
extern struct kmem_cache *ceph_dentry_cachep; extern struct kmem_cache *ceph_dentry_cachep;
extern struct kmem_cache *ceph_file_cachep; extern struct kmem_cache *ceph_file_cachep;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment