diff options
Diffstat (limited to 'fs/ceph/inode.c')
-rw-r--r-- | fs/ceph/inode.c | 183 |
1 files changed, 100 insertions, 83 deletions
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c index 8549a48115f7..278fd2891288 100644 --- a/fs/ceph/inode.c +++ b/fs/ceph/inode.c | |||
@@ -577,6 +577,8 @@ static int fill_inode(struct inode *inode, | |||
577 | int issued = 0, implemented; | 577 | int issued = 0, implemented; |
578 | struct timespec mtime, atime, ctime; | 578 | struct timespec mtime, atime, ctime; |
579 | u32 nsplits; | 579 | u32 nsplits; |
580 | struct ceph_inode_frag *frag; | ||
581 | struct rb_node *rb_node; | ||
580 | struct ceph_buffer *xattr_blob = NULL; | 582 | struct ceph_buffer *xattr_blob = NULL; |
581 | int err = 0; | 583 | int err = 0; |
582 | int queue_trunc = 0; | 584 | int queue_trunc = 0; |
@@ -751,15 +753,38 @@ no_change: | |||
751 | /* FIXME: move me up, if/when version reflects fragtree changes */ | 753 | /* FIXME: move me up, if/when version reflects fragtree changes */ |
752 | nsplits = le32_to_cpu(info->fragtree.nsplits); | 754 | nsplits = le32_to_cpu(info->fragtree.nsplits); |
753 | mutex_lock(&ci->i_fragtree_mutex); | 755 | mutex_lock(&ci->i_fragtree_mutex); |
756 | rb_node = rb_first(&ci->i_fragtree); | ||
754 | for (i = 0; i < nsplits; i++) { | 757 | for (i = 0; i < nsplits; i++) { |
755 | u32 id = le32_to_cpu(info->fragtree.splits[i].frag); | 758 | u32 id = le32_to_cpu(info->fragtree.splits[i].frag); |
756 | struct ceph_inode_frag *frag = __get_or_create_frag(ci, id); | 759 | frag = NULL; |
757 | 760 | while (rb_node) { | |
758 | if (IS_ERR(frag)) | 761 | frag = rb_entry(rb_node, struct ceph_inode_frag, node); |
759 | continue; | 762 | if (ceph_frag_compare(frag->frag, id) >= 0) { |
763 | if (frag->frag != id) | ||
764 | frag = NULL; | ||
765 | else | ||
766 | rb_node = rb_next(rb_node); | ||
767 | break; | ||
768 | } | ||
769 | rb_node = rb_next(rb_node); | ||
770 | rb_erase(&frag->node, &ci->i_fragtree); | ||
771 | kfree(frag); | ||
772 | frag = NULL; | ||
773 | } | ||
774 | if (!frag) { | ||
775 | frag = __get_or_create_frag(ci, id); | ||
776 | if (IS_ERR(frag)) | ||
777 | continue; | ||
778 | } | ||
760 | frag->split_by = le32_to_cpu(info->fragtree.splits[i].by); | 779 | frag->split_by = le32_to_cpu(info->fragtree.splits[i].by); |
761 | dout(" frag %x split by %d\n", frag->frag, frag->split_by); | 780 | dout(" frag %x split by %d\n", frag->frag, frag->split_by); |
762 | } | 781 | } |
782 | while (rb_node) { | ||
783 | frag = rb_entry(rb_node, struct ceph_inode_frag, node); | ||
784 | rb_node = rb_next(rb_node); | ||
785 | rb_erase(&frag->node, &ci->i_fragtree); | ||
786 | kfree(frag); | ||
787 | } | ||
763 | mutex_unlock(&ci->i_fragtree_mutex); | 788 | mutex_unlock(&ci->i_fragtree_mutex); |
764 | 789 | ||
765 | /* were we issued a capability? */ | 790 | /* were we issued a capability? */ |
@@ -953,7 +978,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
953 | struct ceph_mds_reply_inode *ininfo; | 978 | struct ceph_mds_reply_inode *ininfo; |
954 | struct ceph_vino vino; | 979 | struct ceph_vino vino; |
955 | struct ceph_fs_client *fsc = ceph_sb_to_client(sb); | 980 | struct ceph_fs_client *fsc = ceph_sb_to_client(sb); |
956 | int i = 0; | ||
957 | int err = 0; | 981 | int err = 0; |
958 | 982 | ||
959 | 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, |
@@ -1014,6 +1038,29 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
1014 | } | 1038 | } |
1015 | } | 1039 | } |
1016 | 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 | |||
1017 | /* | 1064 | /* |
1018 | * ignore null lease/binding on snapdir ENOENT, or else we | 1065 | * ignore null lease/binding on snapdir ENOENT, or else we |
1019 | * will have trouble splicing in the virtual snapdir later | 1066 | * will have trouble splicing in the virtual snapdir later |
@@ -1083,7 +1130,6 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
1083 | ceph_dentry(req->r_old_dentry)->offset); | 1130 | ceph_dentry(req->r_old_dentry)->offset); |
1084 | 1131 | ||
1085 | dn = req->r_old_dentry; /* use old_dentry */ | 1132 | dn = req->r_old_dentry; /* use old_dentry */ |
1086 | in = dn->d_inode; | ||
1087 | } | 1133 | } |
1088 | 1134 | ||
1089 | /* null dentry? */ | 1135 | /* null dentry? */ |
@@ -1105,44 +1151,28 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
1105 | } | 1151 | } |
1106 | 1152 | ||
1107 | /* attach proper inode */ | 1153 | /* attach proper inode */ |
1108 | ininfo = rinfo->targeti.in; | 1154 | if (!dn->d_inode) { |
1109 | vino.ino = le64_to_cpu(ininfo->ino); | 1155 | ihold(in); |
1110 | vino.snap = le64_to_cpu(ininfo->snapid); | ||
1111 | in = dn->d_inode; | ||
1112 | if (!in) { | ||
1113 | in = ceph_get_inode(sb, vino); | ||
1114 | if (IS_ERR(in)) { | ||
1115 | pr_err("fill_trace bad get_inode " | ||
1116 | "%llx.%llx\n", vino.ino, vino.snap); | ||
1117 | err = PTR_ERR(in); | ||
1118 | d_drop(dn); | ||
1119 | goto done; | ||
1120 | } | ||
1121 | dn = splice_dentry(dn, in, &have_lease, true); | 1156 | dn = splice_dentry(dn, in, &have_lease, true); |
1122 | if (IS_ERR(dn)) { | 1157 | if (IS_ERR(dn)) { |
1123 | err = PTR_ERR(dn); | 1158 | err = PTR_ERR(dn); |
1124 | goto done; | 1159 | goto done; |
1125 | } | 1160 | } |
1126 | req->r_dentry = dn; /* may have spliced */ | 1161 | req->r_dentry = dn; /* may have spliced */ |
1127 | ihold(in); | 1162 | } else if (dn->d_inode && dn->d_inode != in) { |
1128 | } else if (ceph_ino(in) == vino.ino && | ||
1129 | ceph_snap(in) == vino.snap) { | ||
1130 | ihold(in); | ||
1131 | } else { | ||
1132 | dout(" %p links to %p %llx.%llx, not %llx.%llx\n", | 1163 | dout(" %p links to %p %llx.%llx, not %llx.%llx\n", |
1133 | dn, in, ceph_ino(in), ceph_snap(in), | 1164 | dn, dn->d_inode, ceph_vinop(dn->d_inode), |
1134 | vino.ino, vino.snap); | 1165 | ceph_vinop(in)); |
1135 | have_lease = false; | 1166 | have_lease = false; |
1136 | in = NULL; | ||
1137 | } | 1167 | } |
1138 | 1168 | ||
1139 | if (have_lease) | 1169 | if (have_lease) |
1140 | update_dentry_lease(dn, rinfo->dlease, session, | 1170 | update_dentry_lease(dn, rinfo->dlease, session, |
1141 | req->r_request_started); | 1171 | req->r_request_started); |
1142 | dout(" final dn %p\n", dn); | 1172 | dout(" final dn %p\n", dn); |
1143 | i++; | 1173 | } else if (!req->r_aborted && |
1144 | } else if ((req->r_op == CEPH_MDS_OP_LOOKUPSNAP || | 1174 | (req->r_op == CEPH_MDS_OP_LOOKUPSNAP || |
1145 | req->r_op == CEPH_MDS_OP_MKSNAP) && !req->r_aborted) { | 1175 | req->r_op == CEPH_MDS_OP_MKSNAP)) { |
1146 | struct dentry *dn = req->r_dentry; | 1176 | struct dentry *dn = req->r_dentry; |
1147 | 1177 | ||
1148 | /* fill out a snapdir LOOKUPSNAP dentry */ | 1178 | /* fill out a snapdir LOOKUPSNAP dentry */ |
@@ -1152,52 +1182,15 @@ int ceph_fill_trace(struct super_block *sb, struct ceph_mds_request *req, | |||
1152 | ininfo = rinfo->targeti.in; | 1182 | ininfo = rinfo->targeti.in; |
1153 | vino.ino = le64_to_cpu(ininfo->ino); | 1183 | vino.ino = le64_to_cpu(ininfo->ino); |
1154 | vino.snap = le64_to_cpu(ininfo->snapid); | 1184 | vino.snap = le64_to_cpu(ininfo->snapid); |
1155 | in = ceph_get_inode(sb, vino); | ||
1156 | if (IS_ERR(in)) { | ||
1157 | pr_err("fill_inode get_inode badness %llx.%llx\n", | ||
1158 | vino.ino, vino.snap); | ||
1159 | err = PTR_ERR(in); | ||
1160 | d_delete(dn); | ||
1161 | goto done; | ||
1162 | } | ||
1163 | 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); | ||
1164 | dn = splice_dentry(dn, in, NULL, true); | 1187 | dn = splice_dentry(dn, in, NULL, true); |
1165 | if (IS_ERR(dn)) { | 1188 | if (IS_ERR(dn)) { |
1166 | err = PTR_ERR(dn); | 1189 | err = PTR_ERR(dn); |
1167 | goto done; | 1190 | goto done; |
1168 | } | 1191 | } |
1169 | req->r_dentry = dn; /* may have spliced */ | 1192 | req->r_dentry = dn; /* may have spliced */ |
1170 | ihold(in); | ||
1171 | rinfo->head->is_dentry = 1; /* fool notrace handlers */ | ||
1172 | } | ||
1173 | |||
1174 | if (rinfo->head->is_target) { | ||
1175 | vino.ino = le64_to_cpu(rinfo->targeti.in->ino); | ||
1176 | vino.snap = le64_to_cpu(rinfo->targeti.in->snapid); | ||
1177 | |||
1178 | if (in == NULL || ceph_ino(in) != vino.ino || | ||
1179 | ceph_snap(in) != vino.snap) { | ||
1180 | in = ceph_get_inode(sb, vino); | ||
1181 | if (IS_ERR(in)) { | ||
1182 | err = PTR_ERR(in); | ||
1183 | goto done; | ||
1184 | } | ||
1185 | } | ||
1186 | req->r_target_inode = in; | ||
1187 | |||
1188 | err = fill_inode(in, | ||
1189 | &rinfo->targeti, NULL, | ||
1190 | session, req->r_request_started, | ||
1191 | (le32_to_cpu(rinfo->head->result) == 0) ? | ||
1192 | req->r_fmode : -1, | ||
1193 | &req->r_caps_reservation); | ||
1194 | if (err < 0) { | ||
1195 | pr_err("fill_inode badness %p %llx.%llx\n", | ||
1196 | in, ceph_vinop(in)); | ||
1197 | goto done; | ||
1198 | } | ||
1199 | } | 1193 | } |
1200 | |||
1201 | done: | 1194 | done: |
1202 | dout("fill_trace done err=%d\n", err); | 1195 | dout("fill_trace done err=%d\n", err); |
1203 | return err; | 1196 | return err; |
@@ -1247,11 +1240,23 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, | |||
1247 | struct qstr dname; | 1240 | struct qstr dname; |
1248 | struct dentry *dn; | 1241 | struct dentry *dn; |
1249 | struct inode *in; | 1242 | struct inode *in; |
1250 | int err = 0, i; | 1243 | int err = 0, ret, i; |
1251 | struct inode *snapdir = NULL; | 1244 | struct inode *snapdir = NULL; |
1252 | 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; |
1253 | u64 frag = le32_to_cpu(rhead->args.readdir.frag); | ||
1254 | struct ceph_dentry_info *di; | 1246 | struct ceph_dentry_info *di; |
1247 | u64 r_readdir_offset = req->r_readdir_offset; | ||
1248 | u32 frag = le32_to_cpu(rhead->args.readdir.frag); | ||
1249 | |||
1250 | if (rinfo->dir_dir && | ||
1251 | le32_to_cpu(rinfo->dir_dir->frag) != frag) { | ||
1252 | dout("readdir_prepopulate got new frag %x -> %x\n", | ||
1253 | frag, le32_to_cpu(rinfo->dir_dir->frag)); | ||
1254 | frag = le32_to_cpu(rinfo->dir_dir->frag); | ||
1255 | if (ceph_frag_is_leftmost(frag)) | ||
1256 | r_readdir_offset = 2; | ||
1257 | else | ||
1258 | r_readdir_offset = 0; | ||
1259 | } | ||
1255 | 1260 | ||
1256 | if (req->r_aborted) | 1261 | if (req->r_aborted) |
1257 | return readdir_prepopulate_inodes_only(req, session); | 1262 | return readdir_prepopulate_inodes_only(req, session); |
@@ -1268,6 +1273,7 @@ int ceph_readdir_prepopulate(struct ceph_mds_request *req, | |||
1268 | ceph_fill_dirfrag(parent->d_inode, rinfo->dir_dir); | 1273 | ceph_fill_dirfrag(parent->d_inode, rinfo->dir_dir); |
1269 | } | 1274 | } |
1270 | 1275 | ||
1276 | /* FIXME: release caps/leases if error occurs */ | ||
1271 | for (i = 0; i < rinfo->dir_nr; i++) { | 1277 | for (i = 0; i < rinfo->dir_nr; i++) { |
1272 | struct ceph_vino vino; | 1278 | struct ceph_vino vino; |
1273 | 1279 | ||
@@ -1292,9 +1298,10 @@ retry_lookup: | |||
1292 | err = -ENOMEM; | 1298 | err = -ENOMEM; |
1293 | goto out; | 1299 | goto out; |
1294 | } | 1300 | } |
1295 | err = ceph_init_dentry(dn); | 1301 | ret = ceph_init_dentry(dn); |
1296 | if (err < 0) { | 1302 | if (ret < 0) { |
1297 | dput(dn); | 1303 | dput(dn); |
1304 | err = ret; | ||
1298 | goto out; | 1305 | goto out; |
1299 | } | 1306 | } |
1300 | } else if (dn->d_inode && | 1307 | } else if (dn->d_inode && |
@@ -1314,9 +1321,6 @@ retry_lookup: | |||
1314 | spin_unlock(&parent->d_lock); | 1321 | spin_unlock(&parent->d_lock); |
1315 | } | 1322 | } |
1316 | 1323 | ||
1317 | di = dn->d_fsdata; | ||
1318 | di->offset = ceph_make_fpos(frag, i + req->r_readdir_offset); | ||
1319 | |||
1320 | /* inode */ | 1324 | /* inode */ |
1321 | if (dn->d_inode) { | 1325 | if (dn->d_inode) { |
1322 | in = dn->d_inode; | 1326 | in = dn->d_inode; |
@@ -1329,26 +1333,39 @@ retry_lookup: | |||
1329 | err = PTR_ERR(in); | 1333 | err = PTR_ERR(in); |
1330 | goto out; | 1334 | goto out; |
1331 | } | 1335 | } |
1332 | dn = splice_dentry(dn, in, NULL, false); | ||
1333 | if (IS_ERR(dn)) | ||
1334 | dn = NULL; | ||
1335 | } | 1336 | } |
1336 | 1337 | ||
1337 | if (fill_inode(in, &rinfo->dir_in[i], NULL, session, | 1338 | if (fill_inode(in, &rinfo->dir_in[i], NULL, session, |
1338 | req->r_request_started, -1, | 1339 | req->r_request_started, -1, |
1339 | &req->r_caps_reservation) < 0) { | 1340 | &req->r_caps_reservation) < 0) { |
1340 | 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); | ||
1341 | goto next_item; | 1345 | goto next_item; |
1342 | } | 1346 | } |
1343 | if (dn) | 1347 | |
1344 | update_dentry_lease(dn, rinfo->dir_dlease[i], | 1348 | if (!dn->d_inode) { |
1345 | req->r_session, | 1349 | dn = splice_dentry(dn, in, NULL, false); |
1346 | 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); | ||
1347 | next_item: | 1363 | next_item: |
1348 | if (dn) | 1364 | if (dn) |
1349 | dput(dn); | 1365 | dput(dn); |
1350 | } | 1366 | } |
1351 | req->r_did_prepopulate = true; | 1367 | if (err == 0) |
1368 | req->r_did_prepopulate = true; | ||
1352 | 1369 | ||
1353 | out: | 1370 | out: |
1354 | if (snapdir) { | 1371 | if (snapdir) { |