diff options
author | Yan, Zheng <zyan@redhat.com> | 2016-06-15 04:29:18 -0400 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2016-07-27 20:55:40 -0400 |
commit | 9a5530c63889ac928a45c4645ab0bc23b4fbfcb8 (patch) | |
tree | 6c3d76c198fd3b26c6fe9e5c7f922ad62cbafdc7 /fs/ceph/caps.c | |
parent | fc8c3892f30c39f28fdb835f7c8598ac4cf5ed1e (diff) |
ceph: wait unsafe sync writes for evicting inode
Otherwise ceph_sync_write_unsafe() may access/modify freed inode.
Signed-off-by: Yan, Zheng <zyan@redhat.com>
Diffstat (limited to 'fs/ceph/caps.c')
-rw-r--r-- | fs/ceph/caps.c | 50 |
1 files changed, 2 insertions, 48 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index a08d245f16f5..1e48377f18a7 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
@@ -1928,53 +1928,6 @@ static int caps_are_flushed(struct inode *inode, u64 flush_tid) | |||
1928 | } | 1928 | } |
1929 | 1929 | ||
1930 | /* | 1930 | /* |
1931 | * Wait on any unsafe replies for the given inode. First wait on the | ||
1932 | * newest request, and make that the upper bound. Then, if there are | ||
1933 | * more requests, keep waiting on the oldest as long as it is still older | ||
1934 | * than the original request. | ||
1935 | */ | ||
1936 | static void sync_write_wait(struct inode *inode) | ||
1937 | { | ||
1938 | struct ceph_inode_info *ci = ceph_inode(inode); | ||
1939 | struct list_head *head = &ci->i_unsafe_writes; | ||
1940 | struct ceph_osd_request *req; | ||
1941 | u64 last_tid; | ||
1942 | |||
1943 | if (!S_ISREG(inode->i_mode)) | ||
1944 | return; | ||
1945 | |||
1946 | spin_lock(&ci->i_unsafe_lock); | ||
1947 | if (list_empty(head)) | ||
1948 | goto out; | ||
1949 | |||
1950 | /* set upper bound as _last_ entry in chain */ | ||
1951 | req = list_last_entry(head, struct ceph_osd_request, | ||
1952 | r_unsafe_item); | ||
1953 | last_tid = req->r_tid; | ||
1954 | |||
1955 | do { | ||
1956 | ceph_osdc_get_request(req); | ||
1957 | spin_unlock(&ci->i_unsafe_lock); | ||
1958 | dout("sync_write_wait on tid %llu (until %llu)\n", | ||
1959 | req->r_tid, last_tid); | ||
1960 | wait_for_completion(&req->r_safe_completion); | ||
1961 | spin_lock(&ci->i_unsafe_lock); | ||
1962 | ceph_osdc_put_request(req); | ||
1963 | |||
1964 | /* | ||
1965 | * from here on look at first entry in chain, since we | ||
1966 | * only want to wait for anything older than last_tid | ||
1967 | */ | ||
1968 | if (list_empty(head)) | ||
1969 | break; | ||
1970 | req = list_first_entry(head, struct ceph_osd_request, | ||
1971 | r_unsafe_item); | ||
1972 | } while (req->r_tid < last_tid); | ||
1973 | out: | ||
1974 | spin_unlock(&ci->i_unsafe_lock); | ||
1975 | } | ||
1976 | |||
1977 | /* | ||
1978 | * wait for any unsafe requests to complete. | 1931 | * wait for any unsafe requests to complete. |
1979 | */ | 1932 | */ |
1980 | static int unsafe_request_wait(struct inode *inode) | 1933 | static int unsafe_request_wait(struct inode *inode) |
@@ -2026,7 +1979,8 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) | |||
2026 | int dirty; | 1979 | int dirty; |
2027 | 1980 | ||
2028 | dout("fsync %p%s\n", inode, datasync ? " datasync" : ""); | 1981 | dout("fsync %p%s\n", inode, datasync ? " datasync" : ""); |
2029 | sync_write_wait(inode); | 1982 | |
1983 | ceph_sync_write_wait(inode); | ||
2030 | 1984 | ||
2031 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | 1985 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); |
2032 | if (ret < 0) | 1986 | if (ret < 0) |