return size - left;
}
-static int ceph_dir_fsync(struct file *file, struct dentry *dentry, int datasync)
+static int ceph_dir_fsync(struct file *file, struct dentry *dentry,
+ int datasync)
{
struct inode *inode = dentry->d_inode;
struct ceph_inode_info *ci = ceph_inode(inode);
- int ret, err;
- struct list_head *p, *n, *head;
+ struct list_head *head = &ci->i_unsafe_dirops;
struct ceph_mds_request *req;
u64 last_tid;
+ int ret = 0;
- ret = 0;
- dout(10, "sync on directory\n");
-
- head = &ci->i_listener_list;
-
- spin_lock(&ci->i_listener_lock);
-
+ dout(10, "dir_fsync %p\n", inode);
+ spin_lock(&ci->i_unsafe_lock);
if (list_empty(head))
goto out;
req = list_entry(head->prev,
- struct ceph_mds_request, r_listener_item);
+ struct ceph_mds_request, r_unsafe_dir_item);
last_tid = req->r_tid;
- list_for_each_safe(p, n, head) {
- req = list_entry(p, struct ceph_mds_request, r_listener_item);
-
- /* avoid starvation */
- if (req->r_tid > last_tid)
- goto out;
-
+ do {
ceph_mdsc_get_request(req);
- spin_unlock(&ci->i_listener_lock);
+ spin_unlock(&ci->i_unsafe_lock);
+ dout(10, "dir_fsync %p wait on tid %llu (until %llu)\n",
+ inode, req->r_tid, last_tid);
if (req->r_timeout) {
- err = wait_for_completion_timeout(&req->r_safe_completion,
- req->r_timeout);
- if (err == 0)
+ ret = wait_for_completion_timeout(&req->r_safe_completion,
+ req->r_timeout);
+ if (ret > 0)
+ ret = 0;
+ else if (ret == 0)
ret = -EIO; /* timed out */
} else {
wait_for_completion(&req->r_safe_completion);
}
- spin_lock(&ci->i_listener_lock);
-
+ spin_lock(&ci->i_unsafe_lock);
ceph_mdsc_put_request(req);
- }
+
+ if (ret || list_empty(head))
+ break;
+ req = list_entry(head->next,
+ struct ceph_mds_request, r_unsafe_dir_item);
+ } while (req->r_tid < last_tid);
out:
- spin_unlock(&ci->i_listener_lock);
+ spin_unlock(&ci->i_unsafe_lock);
return ret;
}
struct ceph_inode_info *ci = ceph_inode(req->r_inode);
dout(10, "sync_write_commit %p tid %llu\n", req, req->r_tid);
- spin_lock(&ci->i_listener_lock);
+ spin_lock(&ci->i_unsafe_lock);
list_del_init(&req->r_unsafe_item);
- spin_unlock(&ci->i_listener_lock);
+ spin_unlock(&ci->i_unsafe_lock);
ceph_put_cap_refs(ci, CEPH_CAP_FILE_WR);
}
struct ceph_osd_request *req;
u64 last_tid;
- spin_lock(&ci->i_listener_lock);
+ spin_lock(&ci->i_unsafe_lock);
if (list_empty(head))
goto out;
do {
ceph_osdc_get_request(req);
- spin_unlock(&ci->i_listener_lock);
+ spin_unlock(&ci->i_unsafe_lock);
dout(10, "sync_write_wait on tid %llu (until %llu)\n",
req->r_tid, last_tid);
wait_for_completion(&req->r_safe_completion);
- spin_lock(&ci->i_listener_lock);
+ spin_lock(&ci->i_unsafe_lock);
ceph_osdc_put_request(req);
/*
* from here on look at first entry in chain, since we
* only want to wait for anything older than last_tid
*/
+ if (list_empty(head))
+ break;
req = list_entry(head->next, struct ceph_osd_request,
r_unsafe_item);
- } while (req->r_tid <= last_tid);
+ } while (req->r_tid < last_tid);
out:
- spin_unlock(&ci->i_listener_lock);
+ spin_unlock(&ci->i_unsafe_lock);
}
/*
* Add to inode unsafe list only after we
* start_request so that a tid has been assigned.
*/
- spin_lock(&ci->i_listener_lock);
+ spin_lock(&ci->i_unsafe_lock);
list_add(&ci->i_unsafe_writes, &req->r_unsafe_item);
- spin_unlock(&ci->i_listener_lock);
+ spin_unlock(&ci->i_unsafe_lock);
ceph_get_more_cap_refs(ci, CEPH_CAP_FILE_WR);
}
ret = ceph_osdc_wait_request(&client->osdc, req);
struct inode *inode = dentry->d_inode;
int ret;
- dout(10, "fsync on inode %p\n", inode);
+ dout(10, "fsync %p\n", inode);
sync_write_wait(inode);
ret = filemap_write_and_wait(inode->i_mapping);
ci->i_wrbuffer_ref_head = 0;
ci->i_rdcache_gen = 0;
ci->i_rdcache_revoking = 0;
+
INIT_LIST_HEAD(&ci->i_unsafe_writes);
+ INIT_LIST_HEAD(&ci->i_unsafe_dirops);
+ spin_lock_init(&ci->i_unsafe_lock);
ci->i_snap_realm = NULL;
INIT_LIST_HEAD(&ci->i_snap_realm_item);
INIT_WORK(&ci->i_vmtruncate_work, ceph_vmtruncate_work);
- INIT_LIST_HEAD(&ci->i_listener_list);
- spin_lock_init(&ci->i_listener_lock);
-
return &ci->vfs_inode;
}
if (listener) {
struct ceph_inode_info *ci = ceph_inode(listener);
- spin_lock(&ci->i_listener_lock);
- req->r_listener = listener;
- list_add_tail(&req->r_listener_item, &ci->i_listener_list);
- spin_unlock(&ci->i_listener_lock);
+ spin_lock(&ci->i_unsafe_lock);
+ req->r_unsafe_dir = listener;
+ list_add_tail(&req->r_unsafe_dir_item, &ci->i_unsafe_dirops);
+ spin_unlock(&ci->i_unsafe_lock);
}
ceph_sysfs_mds_req_init(mdsc, req);
radix_tree_delete(&mdsc->request_tree, req->r_tid);
ceph_mdsc_put_request(req);
- if (req->r_listener) {
- struct ceph_inode_info *ci = ceph_inode(req->r_listener);
+ if (req->r_unsafe_dir) {
+ struct ceph_inode_info *ci = ceph_inode(req->r_unsafe_dir);
- spin_lock(&ci->i_listener_lock);
- list_del_init(&req->r_listener_item);
- spin_unlock(&ci->i_listener_lock);
+ spin_lock(&ci->i_unsafe_lock);
+ list_del_init(&req->r_unsafe_dir_item);
+ spin_unlock(&ci->i_unsafe_lock);
}
ceph_sysfs_mds_req_cleanup(req);
return ERR_PTR(-ENOMEM);
req->r_started = jiffies;
req->r_resend_mds = -1;
- INIT_LIST_HEAD(&req->r_listener_item);
+ INIT_LIST_HEAD(&req->r_unsafe_dir_item);
req->r_fmode = -1;
atomic_set(&req->r_ref, 1); /* one for request_tree, one for caller */
INIT_LIST_HEAD(&req->r_wait);
u32 r_direct_hash; /* choose dir frag based on this dentry hash */
bool r_direct_is_hash; /* true if r_direct_hash is valid */
- struct inode *r_listener;
- struct list_head r_listener_item;
+ struct inode *r_unsafe_dir;
+ struct list_head r_unsafe_dir_item;
/* references to the trailing dentry and inode from parsing the
* mds response. also used to feed a VFS-provided dentry into
If it's non-zero, we _may_ have cached
pages. */
u32 i_rdcache_revoking; /* RDCACHE gen to async invalidate, if any */
+
struct list_head i_unsafe_writes; /* uncommitted sync writes */
+ struct list_head i_unsafe_dirops; /* uncommitted mds dir ops */
+ spinlock_t i_unsafe_lock;
struct ceph_snap_realm *i_snap_realm; /* snap realm (if caps) */
struct list_head i_snap_realm_item;
struct work_struct i_vmtruncate_work;
- struct list_head i_listener_list; /* requests we pend on */
- spinlock_t i_listener_lock;
-
struct inode vfs_inode; /* at end */
};