diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-10 11:42:33 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-10 11:42:33 -0400 |
commit | 26c5eaa1326e9703effd01e7cc3cc0d4ad4b3c19 (patch) | |
tree | 070c518340ae308dce62695a06a118a1df78be15 /fs/ceph/file.c | |
parent | 1176032cb12bb89ad558a3e57e82f2f25b817eff (diff) | |
parent | eeca958dce0a9231d1969f86196653eb50fcc9b3 (diff) |
Merge tag 'ceph-for-4.12-rc1' of git://github.com/ceph/ceph-client
Pull ceph updates from Ilya Dryomov:
"The two main items are support for disabling automatic rbd exclusive
lock transfers from myself and the long awaited -ENOSPC handling
series from Jeff.
The former will allow rbd users to take advantage of exclusive lock's
built-in blacklist/break-lock functionality while staying in control
of who owns the lock. With the latter in place, we will abort
filesystem writes on -ENOSPC instead of having them block
indefinitely.
Beyond that we've got the usual pile of filesystem fixes from Zheng,
some refcount_t conversion patches from Elena and a patch for an
ancient open() flags handling bug from Alexander"
* tag 'ceph-for-4.12-rc1' of git://github.com/ceph/ceph-client: (31 commits)
ceph: fix memory leak in __ceph_setxattr()
ceph: fix file open flags on ppc64
ceph: choose readdir frag based on previous readdir reply
rbd: exclusive map option
rbd: return ResponseMessage result from rbd_handle_request_lock()
rbd: kill rbd_is_lock_supported()
rbd: support updating the lock cookie without releasing the lock
rbd: store lock cookie
rbd: ignore unlock errors
rbd: fix error handling around rbd_init_disk()
rbd: move rbd_unregister_watch() call into rbd_dev_image_release()
rbd: move rbd_dev_destroy() call out of rbd_dev_image_release()
ceph: when seeing write errors on an inode, switch to sync writes
Revert "ceph: SetPageError() for writeback pages if writepages fails"
ceph: handle epoch barriers in cap messages
libceph: add an epoch_barrier field to struct ceph_osd_client
libceph: abort already submitted but abortable requests when map or pool goes full
libceph: allow requests to return immediately on full conditions if caller wishes
libceph: remove req->r_replay_version
ceph: make seeky readdir more efficient
...
Diffstat (limited to 'fs/ceph/file.c')
-rw-r--r-- | fs/ceph/file.c | 68 |
1 files changed, 53 insertions, 15 deletions
diff --git a/fs/ceph/file.c b/fs/ceph/file.c index 18c045e2ead6..3fdde0b283c9 100644 --- a/fs/ceph/file.c +++ b/fs/ceph/file.c | |||
@@ -13,6 +13,38 @@ | |||
13 | #include "mds_client.h" | 13 | #include "mds_client.h" |
14 | #include "cache.h" | 14 | #include "cache.h" |
15 | 15 | ||
16 | static __le32 ceph_flags_sys2wire(u32 flags) | ||
17 | { | ||
18 | u32 wire_flags = 0; | ||
19 | |||
20 | switch (flags & O_ACCMODE) { | ||
21 | case O_RDONLY: | ||
22 | wire_flags |= CEPH_O_RDONLY; | ||
23 | break; | ||
24 | case O_WRONLY: | ||
25 | wire_flags |= CEPH_O_WRONLY; | ||
26 | break; | ||
27 | case O_RDWR: | ||
28 | wire_flags |= CEPH_O_RDWR; | ||
29 | break; | ||
30 | } | ||
31 | |||
32 | #define ceph_sys2wire(a) if (flags & a) { wire_flags |= CEPH_##a; flags &= ~a; } | ||
33 | |||
34 | ceph_sys2wire(O_CREAT); | ||
35 | ceph_sys2wire(O_EXCL); | ||
36 | ceph_sys2wire(O_TRUNC); | ||
37 | ceph_sys2wire(O_DIRECTORY); | ||
38 | ceph_sys2wire(O_NOFOLLOW); | ||
39 | |||
40 | #undef ceph_sys2wire | ||
41 | |||
42 | if (flags) | ||
43 | dout("unused open flags: %x", flags); | ||
44 | |||
45 | return cpu_to_le32(wire_flags); | ||
46 | } | ||
47 | |||
16 | /* | 48 | /* |
17 | * Ceph file operations | 49 | * Ceph file operations |
18 | * | 50 | * |
@@ -120,7 +152,7 @@ prepare_open_request(struct super_block *sb, int flags, int create_mode) | |||
120 | if (IS_ERR(req)) | 152 | if (IS_ERR(req)) |
121 | goto out; | 153 | goto out; |
122 | req->r_fmode = ceph_flags_to_mode(flags); | 154 | req->r_fmode = ceph_flags_to_mode(flags); |
123 | req->r_args.open.flags = cpu_to_le32(flags); | 155 | req->r_args.open.flags = ceph_flags_sys2wire(flags); |
124 | req->r_args.open.mode = cpu_to_le32(create_mode); | 156 | req->r_args.open.mode = cpu_to_le32(create_mode); |
125 | out: | 157 | out: |
126 | return req; | 158 | return req; |
@@ -189,7 +221,7 @@ int ceph_renew_caps(struct inode *inode) | |||
189 | spin_lock(&ci->i_ceph_lock); | 221 | spin_lock(&ci->i_ceph_lock); |
190 | wanted = __ceph_caps_file_wanted(ci); | 222 | wanted = __ceph_caps_file_wanted(ci); |
191 | if (__ceph_is_any_real_caps(ci) && | 223 | if (__ceph_is_any_real_caps(ci) && |
192 | (!(wanted & CEPH_CAP_ANY_WR) == 0 || ci->i_auth_cap)) { | 224 | (!(wanted & CEPH_CAP_ANY_WR) || ci->i_auth_cap)) { |
193 | int issued = __ceph_caps_issued(ci, NULL); | 225 | int issued = __ceph_caps_issued(ci, NULL); |
194 | spin_unlock(&ci->i_ceph_lock); | 226 | spin_unlock(&ci->i_ceph_lock); |
195 | dout("renew caps %p want %s issued %s updating mds_wanted\n", | 227 | dout("renew caps %p want %s issued %s updating mds_wanted\n", |
@@ -778,6 +810,7 @@ static void ceph_aio_retry_work(struct work_struct *work) | |||
778 | req->r_callback = ceph_aio_complete_req; | 810 | req->r_callback = ceph_aio_complete_req; |
779 | req->r_inode = inode; | 811 | req->r_inode = inode; |
780 | req->r_priv = aio_req; | 812 | req->r_priv = aio_req; |
813 | req->r_abort_on_full = true; | ||
781 | 814 | ||
782 | ret = ceph_osdc_start_request(req->r_osdc, req, false); | 815 | ret = ceph_osdc_start_request(req->r_osdc, req, false); |
783 | out: | 816 | out: |
@@ -1085,19 +1118,22 @@ ceph_sync_write(struct kiocb *iocb, struct iov_iter *from, loff_t pos, | |||
1085 | 1118 | ||
1086 | out: | 1119 | out: |
1087 | ceph_osdc_put_request(req); | 1120 | ceph_osdc_put_request(req); |
1088 | if (ret == 0) { | 1121 | if (ret != 0) { |
1089 | pos += len; | 1122 | ceph_set_error_write(ci); |
1090 | written += len; | ||
1091 | |||
1092 | if (pos > i_size_read(inode)) { | ||
1093 | check_caps = ceph_inode_set_size(inode, pos); | ||
1094 | if (check_caps) | ||
1095 | ceph_check_caps(ceph_inode(inode), | ||
1096 | CHECK_CAPS_AUTHONLY, | ||
1097 | NULL); | ||
1098 | } | ||
1099 | } else | ||
1100 | break; | 1123 | break; |
1124 | } | ||
1125 | |||
1126 | ceph_clear_error_write(ci); | ||
1127 | pos += len; | ||
1128 | written += len; | ||
1129 | if (pos > i_size_read(inode)) { | ||
1130 | check_caps = ceph_inode_set_size(inode, pos); | ||
1131 | if (check_caps) | ||
1132 | ceph_check_caps(ceph_inode(inode), | ||
1133 | CHECK_CAPS_AUTHONLY, | ||
1134 | NULL); | ||
1135 | } | ||
1136 | |||
1101 | } | 1137 | } |
1102 | 1138 | ||
1103 | if (ret != -EOLDSNAPC && written > 0) { | 1139 | if (ret != -EOLDSNAPC && written > 0) { |
@@ -1303,6 +1339,7 @@ static ssize_t ceph_write_iter(struct kiocb *iocb, struct iov_iter *from) | |||
1303 | } | 1339 | } |
1304 | 1340 | ||
1305 | retry_snap: | 1341 | retry_snap: |
1342 | /* FIXME: not complete since it doesn't account for being at quota */ | ||
1306 | if (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL)) { | 1343 | if (ceph_osdmap_flag(osdc, CEPH_OSDMAP_FULL)) { |
1307 | err = -ENOSPC; | 1344 | err = -ENOSPC; |
1308 | goto out; | 1345 | goto out; |
@@ -1324,7 +1361,8 @@ retry_snap: | |||
1324 | inode, ceph_vinop(inode), pos, count, ceph_cap_string(got)); | 1361 | inode, ceph_vinop(inode), pos, count, ceph_cap_string(got)); |
1325 | 1362 | ||
1326 | if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 || | 1363 | if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 || |
1327 | (iocb->ki_flags & IOCB_DIRECT) || (fi->flags & CEPH_F_SYNC)) { | 1364 | (iocb->ki_flags & IOCB_DIRECT) || (fi->flags & CEPH_F_SYNC) || |
1365 | (ci->i_ceph_flags & CEPH_I_ERROR_WRITE)) { | ||
1328 | struct ceph_snap_context *snapc; | 1366 | struct ceph_snap_context *snapc; |
1329 | struct iov_iter data; | 1367 | struct iov_iter data; |
1330 | inode_unlock(inode); | 1368 | inode_unlock(inode); |