diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2013-12-17 14:46:51 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-12-17 14:46:51 -0500 |
commit | a5905a9205164023191e47f62ef9b3929ddcc48e (patch) | |
tree | accc5e91974a96b653f2da3530b806a09076e22a /fs | |
parent | 4ddebaf42dcddd4a3004b59a44fc8da6bce0aa6c (diff) | |
parent | 56f91aad69444d650237295f68c195b74d888d95 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client
Pull two Ceph fixes from Sage Weil:
"One of these is fixing a regression from the d_flags file type patch
that went into -rc1 that broke instantiation of inodes and dentries
(we were doing dentries first). The other is just an off-by-one
corner case"
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client:
ceph: Avoid data inconsistency due to d-cache aliasing in readpage()
ceph: initialize inode before instantiating dentry
Diffstat (limited to 'fs')
-rw-r--r-- | fs/ceph/addr.c | 8 | ||||
-rw-r--r-- | fs/ceph/inode.c | 136 |
2 files changed, 64 insertions, 80 deletions
diff --git a/fs/ceph/addr.c b/fs/ceph/addr.c index 1e561c059539..ec3ba43b9faa 100644 --- a/fs/ceph/addr.c +++ b/fs/ceph/addr.c | |||
@@ -210,9 +210,13 @@ static int readpage_nounlock(struct file *filp, struct page *page) | |||
210 | if (err < 0) { | 210 | if (err < 0) { |
211 | SetPageError(page); | 211 | SetPageError(page); |
212 | goto out; | 212 | goto out; |
213 | } else if (err < PAGE_CACHE_SIZE) { | 213 | } else { |
214 | if (err < PAGE_CACHE_SIZE) { | ||
214 | /* zero fill remainder of page */ | 215 | /* zero fill remainder of page */ |
215 | zero_user_segment(page, err, PAGE_CACHE_SIZE); | 216 | zero_user_segment(page, err, PAGE_CACHE_SIZE); |
217 | } else { | ||
218 | flush_dcache_page(page); | ||
219 | } | ||
216 | } | 220 | } |
217 | SetPageUptodate(page); | 221 | SetPageUptodate(page); |
218 | 222 | ||
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 9a8e396aed89..278fd2891288 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -978,7 +978,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
978 | struct ceph_mds_reply_inode *ininfo; | 978 | struct ceph_mds_reply_inode *ininfo; |
979 | struct ceph_vino vino; | 979 | struct ceph_vino vino; |
980 | struct ceph_fs_client *fsc = ceph_sb_to_client(sb); | 980 | struct ceph_fs_client *fsc = ceph_sb_to_client(sb); |
981 | int i = 0; | ||
982 | int err = 0; | 981 | int err = 0; |
983 | 982 | ||
984 | dout("fill_trace %p is_dentry %d is_target %d\n", req, | 983 | dout("fill_trace %p is_dentry %d is_target %d\n", req, |
@@ -1039,6 +1038,29 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
1039 | } | 1038 | } |
1040 | } | 1039 | } |
1041 | 1040 | ||
1041 | if (rinfo->head->is_target) { | ||
1042 | vino.ino = le64_to_cpu(rinfo->targeti.in->ino); | ||
1043 | vino.snap = le64_to_cpu(rinfo->targeti.in->snapid); | ||
1044 | |||
1045 | in = ceph_get_inode(sb, vino); | ||
1046 | if (IS_ERR(in)) { | ||
1047 | err = PTR_ERR(in); | ||
1048 | goto done; | ||
1049 | } | ||
1050 | req->r_target_inode = in; | ||
1051 | |||
1052 | err = fill_inode(in, &rinfo->targeti, NULL, | ||
1053 | session, req->r_request_started, | ||
1054 | (le32_to_cpu(rinfo->head->result) == 0) ? | ||
1055 | req->r_fmode : -1, | ||
1056 | &req->r_caps_reservation); | ||
1057 | if (err < 0) { | ||
1058 | pr_err("fill_inode badness %p %llx.%llx\n", | ||
1059 | in, ceph_vinop(in)); | ||
1060 | goto done; | ||
1061 | } | ||
1062 | } | ||
1063 | |||
1042 | /* | 1064 | /* |
1043 | * ignore null lease/binding on snapdir ENOENT, or else we | 1065 | * ignore null lease/binding on snapdir ENOENT, or else we |
1044 | * will have trouble splicing in the virtual snapdir later | 1066 | * will have trouble splicing in the virtual snapdir later |
@@ -1108,7 +1130,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
1108 | ceph_dentry(req->r_old_dentry)->offset); | 1130 | ceph_dentry(req->r_old_dentry)->offset); |
1109 | 1131 | ||
1110 | dn = req->r_old_dentry; /* use old_dentry */ | 1132 | dn = req->r_old_dentry; /* use old_dentry */ |
1111 | in = dn->d_inode; | ||
1112 | } | 1133 | } |
1113 | 1134 | ||
1114 | /* null dentry? */ | 1135 | /* null dentry? */ |
@@ -1130,44 +1151,28 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
1130 | } | 1151 | } |
1131 | 1152 | ||
1132 | /* attach proper inode */ | 1153 | /* attach proper inode */ |
1133 | ininfo = rinfo->targeti.in; | 1154 | if (!dn->d_inode) { |
1134 | vino.ino = le64_to_cpu(ininfo->ino); | 1155 | ihold(in); |
1135 | vino.snap = le64_to_cpu(ininfo->snapid); | ||
1136 | in = dn->d_inode; | ||
1137 | if (!in) { | ||
1138 | in = ceph_get_inode(sb, vino); | ||
1139 | if (IS_ERR(in)) { | ||
1140 | pr_err("fill_trace bad get_inode " | ||
1141 | "%llx.%llx\n", vino.ino, vino.snap); | ||
1142 | err = PTR_ERR(in); | ||
1143 | d_drop(dn); | ||
1144 | goto done; | ||
1145 | } | ||
1146 | dn = splice_dentry(dn, in, &have_lease, true); | 1156 | dn = splice_dentry(dn, in, &have_lease, true); |
1147 | if (IS_ERR(dn)) { | 1157 | if (IS_ERR(dn)) { |
1148 | err = PTR_ERR(dn); | 1158 | err = PTR_ERR(dn); |
1149 | goto done; | 1159 | goto done; |
1150 | } | 1160 | } |
1151 | req->r_dentry = dn; /* may have spliced */ | 1161 | req->r_dentry = dn; /* may have spliced */ |
1152 | ihold(in); | 1162 | } else if (dn->d_inode && dn->d_inode != in) { |
1153 | } else if (ceph_ino(in) == vino.ino && | ||
1154 | ceph_snap(in) == vino.snap) { | ||
1155 | ihold(in); | ||
1156 | } else { | ||
1157 | dout(" %p links to %p %llx.%llx, not %llx.%llx\n", | 1163 | dout(" %p links to %p %llx.%llx, not %llx.%llx\n", |
1158 | dn, in, ceph_ino(in), ceph_snap(in), | 1164 | dn, dn->d_inode, ceph_vinop(dn->d_inode), |
1159 | vino.ino, vino.snap); | 1165 | ceph_vinop(in)); |
1160 | have_lease = false; | 1166 | have_lease = false; |
1161 | in = NULL; | ||
1162 | } | 1167 | } |
1163 | 1168 | ||
1164 | if (have_lease) | 1169 | if (have_lease) |
1165 | update_dentry_lease(dn, rinfo->dlease, session, | 1170 | update_dentry_lease(dn, rinfo->dlease, session, |
1166 | req->r_request_started); | 1171 | req->r_request_started); |
1167 | dout(" final dn %p\n", dn); | 1172 | dout(" final dn %p\n", dn); |
1168 | i++; | 1173 | } else if (!req->r_aborted && |
1169 | } else if ((req->r_op == CEPH_MDS_OP_LOOKUPSNAP || | 1174 | (req->r_op == CEPH_MDS_OP_LOOKUPSNAP || |
1170 | req->r_op == CEPH_MDS_OP_MKSNAP) && !req->r_aborted) { | 1175 | req->r_op == CEPH_MDS_OP_MKSNAP)) { |
1171 | struct dentry *dn = req->r_dentry; | 1176 | struct dentry *dn = req->r_dentry; |
1172 | 1177 | ||
1173 | /* fill out a snapdir LOOKUPSNAP dentry */ | 1178 | /* fill out a snapdir LOOKUPSNAP dentry */ |
@@ -1177,52 +1182,15 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
1177 | ininfo = rinfo->targeti.in; | 1182 | ininfo = rinfo->targeti.in; |
1178 | vino.ino = le64_to_cpu(ininfo->ino); | 1183 | vino.ino = le64_to_cpu(ininfo->ino); |
1179 | vino.snap = le64_to_cpu(ininfo->snapid); | 1184 | vino.snap = le64_to_cpu(ininfo->snapid); |
1180 | in = ceph_get_inode(sb, vino); | ||
1181 | if (IS_ERR(in)) { | ||
1182 | pr_err("fill_inode get_inode badness %llx.%llx\n", | ||
1183 | vino.ino, vino.snap); | ||
1184 | err = PTR_ERR(in); | ||
1185 | d_delete(dn); | ||
1186 | goto done; | ||
1187 | } | ||
1188 | dout(" linking snapped dir %p to dn %p\n", in, dn); | 1185 | dout(" linking snapped dir %p to dn %p\n", in, dn); |
1186 | ihold(in); | ||
1189 | dn = splice_dentry(dn, in, NULL, true); | 1187 | dn = splice_dentry(dn, in, NULL, true); |
1190 | if (IS_ERR(dn)) { | 1188 | if (IS_ERR(dn)) { |
1191 | err = PTR_ERR(dn); | 1189 | err = PTR_ERR(dn); |
1192 | goto done; | 1190 | goto done; |
1193 | } | 1191 | } |
1194 | req->r_dentry = dn; /* may have spliced */ | 1192 | req->r_dentry = dn; /* may have spliced */ |
1195 | ihold(in); | ||
1196 | rinfo->head->is_dentry = 1; /* fool notrace handlers */ | ||
1197 | } | ||
1198 | |||
1199 | if (rinfo->head->is_target) { | ||
1200 | vino.ino = le64_to_cpu(rinfo->targeti.in->ino); | ||
1201 | vino.snap = le64_to_cpu(rinfo->targeti.in->snapid); | ||
1202 | |||
1203 | if (in == NULL || ceph_ino(in) != vino.ino || | ||
1204 | ceph_snap(in) != vino.snap) { | ||
1205 | in = ceph_get_inode(sb, vino); | ||
1206 | if (IS_ERR(in)) { | ||
1207 | err = PTR_ERR(in); | ||
1208 | goto done; | ||
1209 | } | ||
1210 | } | ||
1211 | req->r_target_inode = in; | ||
1212 | |||
1213 | err = fill_inode(in, | ||
1214 | &rinfo->targeti, NULL, | ||
1215 | session, req->r_request_started, | ||
1216 | (le32_to_cpu(rinfo->head->result) == 0) ? | ||
1217 | req->r_fmode : -1, | ||
1218 | &req->r_caps_reservation); | ||
1219 | if (err < 0) { | ||
1220 | pr_err("fill_inode badness %p %llx.%llx\n", | ||
1221 | in, ceph_vinop(in)); | ||
1222 | goto done; | ||
1223 | } | ||
1224 | } | 1193 | } |
1225 | |||
1226 | done: | 1194 | done: |
1227 | dout("fill_trace done err=%d\n", err); | 1195 | dout("fill_trace done err=%d\n", err); |
1228 | return err; | 1196 | return err; |
@@ -1272,7 +1240,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, | |||
1272 | struct qstr dname; | 1240 | struct qstr dname; |
1273 | struct dentry *dn; | 1241 | struct dentry *dn; |
1274 | struct inode *in; | 1242 | struct inode *in; |
1275 | int err = 0, i; | 1243 | int err = 0, ret, i; |
1276 | struct inode *snapdir = NULL; | 1244 | struct inode *snapdir = NULL; |
1277 | struct ceph_mds_request_head *rhead = req->r_request->front.iov_base; | 1245 | struct ceph_mds_request_head *rhead = req->r_request->front.iov_base; |
1278 | struct ceph_dentry_info *di; | 1246 | struct ceph_dentry_info *di; |
@@ -1305,6 +1273,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, | |||
1305 | ceph_fill_dirfrag(parent->d_inode, rinfo->dir_dir); | 1273 | ceph_fill_dirfrag(parent->d_inode, rinfo->dir_dir); |
1306 | } | 1274 | } |
1307 | 1275 | ||
1276 | /* FIXME: release caps/leases if error occurs */ | ||
1308 | for (i = 0; i < rinfo->dir_nr; i++) { | 1277 | for (i = 0; i < rinfo->dir_nr; i++) { |
1309 | struct ceph_vino vino; | 1278 | struct ceph_vino vino; |
1310 | 1279 | ||
@@ -1329,9 +1298,10 @@ retry_lookup: | |||
1329 | err = -ENOMEM; | 1298 | err = -ENOMEM; |
1330 | goto out; | 1299 | goto out; |
1331 | } | 1300 | } |
1332 | err = ceph_init_dentry(dn); | 1301 | ret = ceph_init_dentry(dn); |
1333 | if (err < 0) { | 1302 | if (ret < 0) { |
1334 | dput(dn); | 1303 | dput(dn); |
1304 | err = ret; | ||
1335 | goto out; | 1305 | goto out; |
1336 | } | 1306 | } |
1337 | } else if (dn->d_inode && | 1307 | } else if (dn->d_inode && |
@@ -1351,9 +1321,6 @@ retry_lookup: | |||
1351 | spin_unlock(&parent->d_lock); | 1321 | spin_unlock(&parent->d_lock); |
1352 | } | 1322 | } |
1353 | 1323 | ||
1354 | di = dn->d_fsdata; | ||
1355 | di->offset = ceph_make_fpos(frag, i + r_readdir_offset); | ||
1356 | |||
1357 | /* inode */ | 1324 | /* inode */ |
1358 | if (dn->d_inode) { | 1325 | if (dn->d_inode) { |
1359 | in = dn->d_inode; | 1326 | in = dn->d_inode; |
@@ -1366,26 +1333,39 @@ retry_lookup: | |||
1366 | err = PTR_ERR(in); | 1333 | err = PTR_ERR(in); |
1367 | goto out; | 1334 | goto out; |
1368 | } | 1335 | } |
1369 | dn = splice_dentry(dn, in, NULL, false); | ||
1370 | if (IS_ERR(dn)) | ||
1371 | dn = NULL; | ||
1372 | } | 1336 | } |
1373 | 1337 | ||
1374 | if (fill_inode(in, &rinfo->dir_in[i], NULL, session, | 1338 | if (fill_inode(in, &rinfo->dir_in[i], NULL, session, |
1375 | req->r_request_started, -1, | 1339 | req->r_request_started, -1, |
1376 | &req->r_caps_reservation) < 0) { | 1340 | &req->r_caps_reservation) < 0) { |
1377 | pr_err("fill_inode badness on %p\n", in); | 1341 | pr_err("fill_inode badness on %p\n", in); |
1342 | if (!dn->d_inode) | ||
1343 | iput(in); | ||
1344 | d_drop(dn); | ||
1378 | goto next_item; | 1345 | goto next_item; |
1379 | } | 1346 | } |
1380 | if (dn) | 1347 | |
1381 | update_dentry_lease(dn, rinfo->dir_dlease[i], | 1348 | if (!dn->d_inode) { |
1382 | req->r_session, | 1349 | dn = splice_dentry(dn, in, NULL, false); |
1383 | req->r_request_started); | 1350 | if (IS_ERR(dn)) { |
1351 | err = PTR_ERR(dn); | ||
1352 | dn = NULL; | ||
1353 | goto next_item; | ||
1354 | } | ||
1355 | } | ||
1356 | |||
1357 | di = dn->d_fsdata; | ||
1358 | di->offset = ceph_make_fpos(frag, i + r_readdir_offset); | ||
1359 | |||
1360 | update_dentry_lease(dn, rinfo->dir_dlease[i], | ||
1361 | req->r_session, | ||
1362 | req->r_request_started); | ||
1384 | next_item: | 1363 | next_item: |
1385 | if (dn) | 1364 | if (dn) |
1386 | dput(dn); | 1365 | dput(dn); |
1387 | } | 1366 | } |
1388 | req->r_did_prepopulate = true; | 1367 | if (err == 0) |
1368 | req->r_did_prepopulate = true; | ||
1389 | 1369 | ||
1390 | out: | 1370 | out: |
1391 | if (snapdir) { | 1371 | if (snapdir) { |