aboutsummaryrefslogtreecommitdiffstats
path: root/fs/ceph
diff options
context:
space:
mode:
authorYan, Zheng <zyan@redhat.com>2015-05-26 23:19:34 -0400
committerIlya Dryomov <idryomov@gmail.com>2015-06-25 04:49:30 -0400
commitda819c8150c5b6e6a6a21ee41135b88f6cd18c3e (patch)
tree83937b095cd94cd7f7da025db3360f9ce5a7c0e8 /fs/ceph
parent89b52fe14de4d703ba837a7418bb4cd286dcc87f (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.c73
-rw-r--r--fs/ceph/dir.c56
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);
1868out: 1871out:
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 */
1878static 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);
1916out:
1917 spin_unlock(&ci->i_unsafe_lock);
1918 return ret;
1919}
1920
1872int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync) 1921int 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);
1956out:
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 */
1230static 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);
1273out:
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
1353const struct file_operations ceph_snapdir_fops = { 1299const struct file_operations ceph_snapdir_fops = {