diff options
author | Yan, Zheng <zyan@redhat.com> | 2015-05-26 23:19:34 -0400 |
---|---|---|
committer | Ilya Dryomov <idryomov@gmail.com> | 2015-06-25 04:49:30 -0400 |
commit | da819c8150c5b6e6a6a21ee41135b88f6cd18c3e (patch) | |
tree | 83937b095cd94cd7f7da025db3360f9ce5a7c0e8 /fs/ceph | |
parent | 89b52fe14de4d703ba837a7418bb4cd286dcc87f (diff) |
ceph: fix directory fsync
fsync() on directory should flush dirty caps and wait for any
uncommitted directory opertions to commit. But ceph_dir_fsync()
only waits for uncommitted directory opertions.
Signed-off-by: Yan, Zheng <zyan@redhat.com>
Diffstat (limited to 'fs/ceph')
-rw-r--r-- | fs/ceph/caps.c | 73 | ||||
-rw-r--r-- | fs/ceph/dir.c | 56 |
2 files changed, 65 insertions, 64 deletions
diff --git a/fs/ceph/caps.c b/fs/ceph/caps.c index e9b03b51b874..dc988337f841 100644 --- a/fs/ceph/caps.c +++ b/fs/ceph/caps.c | |||
@@ -1838,13 +1838,16 @@ static void sync_write_wait(struct inode *inode) | |||
1838 | struct ceph_osd_request *req; | 1838 | struct ceph_osd_request *req; |
1839 | u64 last_tid; | 1839 | u64 last_tid; |
1840 | 1840 | ||
1841 | if (!S_ISREG(inode->i_mode)) | ||
1842 | return; | ||
1843 | |||
1841 | spin_lock(&ci->i_unsafe_lock); | 1844 | spin_lock(&ci->i_unsafe_lock); |
1842 | if (list_empty(head)) | 1845 | if (list_empty(head)) |
1843 | goto out; | 1846 | goto out; |
1844 | 1847 | ||
1845 | /* set upper bound as _last_ entry in chain */ | 1848 | /* set upper bound as _last_ entry in chain */ |
1846 | req = list_entry(head->prev, struct ceph_osd_request, | 1849 | req = list_last_entry(head, struct ceph_osd_request, |
1847 | r_unsafe_item); | 1850 | r_unsafe_item); |
1848 | last_tid = req->r_tid; | 1851 | last_tid = req->r_tid; |
1849 | 1852 | ||
1850 | do { | 1853 | do { |
@@ -1862,13 +1865,59 @@ static void sync_write_wait(struct inode *inode) | |||
1862 | */ | 1865 | */ |
1863 | if (list_empty(head)) | 1866 | if (list_empty(head)) |
1864 | break; | 1867 | break; |
1865 | req = list_entry(head->next, struct ceph_osd_request, | 1868 | req = list_first_entry(head, struct ceph_osd_request, |
1866 | r_unsafe_item); | 1869 | r_unsafe_item); |
1867 | } while (req->r_tid < last_tid); | 1870 | } while (req->r_tid < last_tid); |
1868 | out: | 1871 | out: |
1869 | spin_unlock(&ci->i_unsafe_lock); | 1872 | spin_unlock(&ci->i_unsafe_lock); |
1870 | } | 1873 | } |
1871 | 1874 | ||
1875 | /* | ||
1876 | * wait for any uncommitted directory operations to commit. | ||
1877 | */ | ||
1878 | static int unsafe_dirop_wait(struct inode *inode) | ||
1879 | { | ||
1880 | struct ceph_inode_info *ci = ceph_inode(inode); | ||
1881 | struct list_head *head = &ci->i_unsafe_dirops; | ||
1882 | struct ceph_mds_request *req; | ||
1883 | u64 last_tid; | ||
1884 | int ret = 0; | ||
1885 | |||
1886 | if (!S_ISDIR(inode->i_mode)) | ||
1887 | return 0; | ||
1888 | |||
1889 | spin_lock(&ci->i_unsafe_lock); | ||
1890 | if (list_empty(head)) | ||
1891 | goto out; | ||
1892 | |||
1893 | req = list_last_entry(head, struct ceph_mds_request, | ||
1894 | r_unsafe_dir_item); | ||
1895 | last_tid = req->r_tid; | ||
1896 | |||
1897 | do { | ||
1898 | ceph_mdsc_get_request(req); | ||
1899 | spin_unlock(&ci->i_unsafe_lock); | ||
1900 | |||
1901 | dout("unsafe_dirop_wait %p wait on tid %llu (until %llu)\n", | ||
1902 | inode, req->r_tid, last_tid); | ||
1903 | ret = !wait_for_completion_timeout(&req->r_safe_completion, | ||
1904 | ceph_timeout_jiffies(req->r_timeout)); | ||
1905 | if (ret) | ||
1906 | ret = -EIO; /* timed out */ | ||
1907 | |||
1908 | ceph_mdsc_put_request(req); | ||
1909 | |||
1910 | spin_lock(&ci->i_unsafe_lock); | ||
1911 | if (ret || list_empty(head)) | ||
1912 | break; | ||
1913 | req = list_first_entry(head, struct ceph_mds_request, | ||
1914 | r_unsafe_dir_item); | ||
1915 | } while (req->r_tid < last_tid); | ||
1916 | out: | ||
1917 | spin_unlock(&ci->i_unsafe_lock); | ||
1918 | return ret; | ||
1919 | } | ||
1920 | |||
1872 | int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) | 1921 | int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
1873 | { | 1922 | { |
1874 | struct inode *inode = file->f_mapping->host; | 1923 | struct inode *inode = file->f_mapping->host; |
@@ -1882,24 +1931,30 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) | |||
1882 | 1931 | ||
1883 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | 1932 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); |
1884 | if (ret < 0) | 1933 | if (ret < 0) |
1885 | return ret; | 1934 | goto out; |
1935 | |||
1936 | if (datasync) | ||
1937 | goto out; | ||
1938 | |||
1886 | mutex_lock(&inode->i_mutex); | 1939 | mutex_lock(&inode->i_mutex); |
1887 | 1940 | ||
1888 | dirty = try_flush_caps(inode, flush_tid); | 1941 | dirty = try_flush_caps(inode, flush_tid); |
1889 | dout("fsync dirty caps are %s\n", ceph_cap_string(dirty)); | 1942 | dout("fsync dirty caps are %s\n", ceph_cap_string(dirty)); |
1890 | 1943 | ||
1944 | ret = unsafe_dirop_wait(inode); | ||
1945 | |||
1891 | /* | 1946 | /* |
1892 | * only wait on non-file metadata writeback (the mds | 1947 | * only wait on non-file metadata writeback (the mds |
1893 | * can recover size and mtime, so we don't need to | 1948 | * can recover size and mtime, so we don't need to |
1894 | * wait for that) | 1949 | * wait for that) |
1895 | */ | 1950 | */ |
1896 | if (!datasync && (dirty & ~CEPH_CAP_ANY_FILE_WR)) { | 1951 | if (!ret && (dirty & ~CEPH_CAP_ANY_FILE_WR)) { |
1897 | ret = wait_event_interruptible(ci->i_cap_wq, | 1952 | ret = wait_event_interruptible(ci->i_cap_wq, |
1898 | caps_are_flushed(inode, flush_tid)); | 1953 | caps_are_flushed(inode, flush_tid)); |
1899 | } | 1954 | } |
1900 | |||
1901 | dout("fsync %p%s done\n", inode, datasync ? " datasync" : ""); | ||
1902 | mutex_unlock(&inode->i_mutex); | 1955 | mutex_unlock(&inode->i_mutex); |
1956 | out: | ||
1957 | dout("fsync %p%s result=%d\n", inode, datasync ? " datasync" : "", ret); | ||
1903 | return ret; | 1958 | return ret; |
1904 | } | 1959 | } |
1905 | 1960 | ||
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c index 3dec27e36417..424e23138c59 100644 --- a/fs/ceph/dir.c +++ b/fs/ceph/dir.c | |||
@@ -1224,60 +1224,6 @@ static ssize_t ceph_read_dir(struct file *file, char __user *buf, size_t size, | |||
1224 | } | 1224 | } |
1225 | 1225 | ||
1226 | /* | 1226 | /* |
1227 | * an fsync() on a dir will wait for any uncommitted directory | ||
1228 | * operations to commit. | ||
1229 | */ | ||
1230 | static int ceph_dir_fsync(struct file *file, loff_t start, loff_t end, | ||
1231 | int datasync) | ||
1232 | { | ||
1233 | struct inode *inode = file_inode(file); | ||
1234 | struct ceph_inode_info *ci = ceph_inode(inode); | ||
1235 | struct list_head *head = &ci->i_unsafe_dirops; | ||
1236 | struct ceph_mds_request *req; | ||
1237 | u64 last_tid; | ||
1238 | int ret = 0; | ||
1239 | |||
1240 | dout("dir_fsync %p\n", inode); | ||
1241 | ret = filemap_write_and_wait_range(inode->i_mapping, start, end); | ||
1242 | if (ret) | ||
1243 | return ret; | ||
1244 | mutex_lock(&inode->i_mutex); | ||
1245 | |||
1246 | spin_lock(&ci->i_unsafe_lock); | ||
1247 | if (list_empty(head)) | ||
1248 | goto out; | ||
1249 | |||
1250 | req = list_entry(head->prev, | ||
1251 | struct ceph_mds_request, r_unsafe_dir_item); | ||
1252 | last_tid = req->r_tid; | ||
1253 | |||
1254 | do { | ||
1255 | ceph_mdsc_get_request(req); | ||
1256 | spin_unlock(&ci->i_unsafe_lock); | ||
1257 | |||
1258 | dout("dir_fsync %p wait on tid %llu (until %llu)\n", | ||
1259 | inode, req->r_tid, last_tid); | ||
1260 | ret = !wait_for_completion_timeout(&req->r_safe_completion, | ||
1261 | ceph_timeout_jiffies(req->r_timeout)); | ||
1262 | if (ret) | ||
1263 | ret = -EIO; /* timed out */ | ||
1264 | |||
1265 | ceph_mdsc_put_request(req); | ||
1266 | |||
1267 | spin_lock(&ci->i_unsafe_lock); | ||
1268 | if (ret || list_empty(head)) | ||
1269 | break; | ||
1270 | req = list_entry(head->next, | ||
1271 | struct ceph_mds_request, r_unsafe_dir_item); | ||
1272 | } while (req->r_tid < last_tid); | ||
1273 | out: | ||
1274 | spin_unlock(&ci->i_unsafe_lock); | ||
1275 | mutex_unlock(&inode->i_mutex); | ||
1276 | |||
1277 | return ret; | ||
1278 | } | ||
1279 | |||
1280 | /* | ||
1281 | * We maintain a private dentry LRU. | 1227 | * We maintain a private dentry LRU. |
1282 | * | 1228 | * |
1283 | * FIXME: this needs to be changed to a per-mds lru to be useful. | 1229 | * FIXME: this needs to be changed to a per-mds lru to be useful. |
@@ -1347,7 +1293,7 @@ const struct file_operations ceph_dir_fops = { | |||
1347 | .open = ceph_open, | 1293 | .open = ceph_open, |
1348 | .release = ceph_release, | 1294 | .release = ceph_release, |
1349 | .unlocked_ioctl = ceph_ioctl, | 1295 | .unlocked_ioctl = ceph_ioctl, |
1350 | .fsync = ceph_dir_fsync, | 1296 | .fsync = ceph_fsync, |
1351 | }; | 1297 | }; |
1352 | 1298 | ||
1353 | const struct file_operations ceph_snapdir_fops = { | 1299 | const struct file_operations ceph_snapdir_fops = { |