@@ -9878,6 +9878,144 @@ int Client::readdirplus_r(dir_result_t *d, struct dirent *de,
98789878 return 0 ;
98799879}
98809880
9881+ static void cleanup_state (Client *client, struct scan_state_t *sst)
9882+ {
9883+ if (sst->fd1 != -1 ) {
9884+ client->_close (sst->fd1 );
9885+ }
9886+ if (sst->fd2 != -1 ) {
9887+ client->_close (sst->fd2 );
9888+ }
9889+ delete sst;
9890+ }
9891+
9892+ int Client::file_blockdiff_init_state (const char * path1, const char * path2,
9893+ const UserPerm &perms, struct scan_state_t **state)
9894+ {
9895+ ldout (cct, 20 ) << __func__ << dendl;
9896+
9897+ InodeRef inode1, inode2;
9898+ scan_state_t *sst = new scan_state_t ();
9899+ sst->fd1 = sst->fd2 = -1 ;
9900+
9901+ /*
9902+ * lets have a constraint that both snapshot paths should be
9903+ * present - otherwise the caller should do a full copy or a
9904+ * delete on the path.
9905+ */
9906+ int r = open (path1, O_RDONLY, perms, 0 );
9907+ if (r < 0 ) {
9908+ return r;
9909+ }
9910+ sst->fd1 = r;
9911+
9912+ r = open (path2, O_RDONLY, perms, 0 );
9913+ if (r < 0 ) {
9914+ cleanup_state (this , sst);
9915+ return r;
9916+ }
9917+ sst->fd2 = r;
9918+
9919+ std::unique_lock lock (client_lock);
9920+ r = get_fd_inode (sst->fd1 , &inode1);
9921+ if (r < 0 ) {
9922+ cleanup_state (this , sst);
9923+ return r;
9924+ }
9925+ r = get_fd_inode (sst->fd2 , &inode2);
9926+ if (r < 0 ) {
9927+ cleanup_state (this , sst);
9928+ return r;
9929+ }
9930+
9931+ ldout (cct, 20 ) << __func__ << " : (snapid1, ino1, size)=(" << inode1->snapid
9932+ << " ," << std::hex << inode1->ino << std::dec << " ,"
9933+ << inode1->size <<" )" << " (snapid2, ino2, size)=("
9934+ << inode2->snapid << " ," << std::hex << inode2->ino << std::dec
9935+ << " ," << inode2->size << " )" << dendl;
9936+ if (inode1->ino != inode2->ino ) {
9937+ cleanup_state (this , sst);
9938+ return -EINVAL;
9939+ }
9940+
9941+ sst->index = 0 ;
9942+ *state = sst;
9943+ return 0 ;
9944+ }
9945+
9946+ int Client::file_blockdiff_finish (struct scan_state_t *state)
9947+ {
9948+ std::unique_lock lock (client_lock);
9949+
9950+ _close (state->fd1 );
9951+ _close (state->fd2 );
9952+ delete state;
9953+ return 0 ;
9954+ }
9955+
9956+ int Client::file_blockdiff (struct scan_state_t *state, const UserPerm &perms,
9957+ std::vector<std::pair<uint64_t ,uint64_t >> *blocks)
9958+ {
9959+ RWRef_t mref_reader (mount_state, CLIENT_MOUNTING);
9960+ if (!mref_reader.is_state_satisfied ()) {
9961+ return -ENOTCONN;
9962+ }
9963+
9964+ ldout (cct, 20 ) << __func__ << dendl;
9965+
9966+ InodeRef inode1;
9967+ InodeRef inode2;
9968+
9969+ std::unique_lock lock (client_lock);
9970+
9971+ int r = get_fd_inode (state->fd1 , &inode1);
9972+ if (r < 0 ) {
9973+ return r;
9974+ }
9975+ r = get_fd_inode (state->fd2 , &inode2);
9976+ if (r < 0 ) {
9977+ return r;
9978+ }
9979+
9980+ ceph_assert (inode1->ino == inode2->ino );
9981+
9982+ MetaRequest *req = new MetaRequest (CEPH_MDS_OP_FILE_BLOCKDIFF);
9983+
9984+ filepath path1, path2;
9985+ inode1->make_nosnap_relative_path (path1);
9986+ req->set_filepath (path1);
9987+
9988+ inode2->make_nosnap_relative_path (path2);
9989+ req->set_filepath2 (path2);
9990+ req->set_inode (inode2.get ());
9991+
9992+ req->head .args .blockdiff .scan_idx = state->index ;
9993+ req->head .args .blockdiff .max_objects =
9994+ cct->_conf .get_val <uint64_t >(" client_file_blockdiff_max_concurrent_object_scans" );
9995+
9996+ bufferlist bl;
9997+ r = make_request (req, perms, nullptr , nullptr , -1 , &bl);
9998+ ldout (cct, 10 ) << __func__ << " : result=" << r << dendl;
9999+
10000+ if (r < 0 ) {
10001+ return r;
10002+ }
10003+
10004+ BlockDiff block_diff;
10005+ auto p = bl.cbegin ();
10006+ decode (block_diff, p);
10007+
10008+ ldout (cct, 10 ) << __func__ << " : block_diff=" << block_diff << dendl;
10009+ if (!block_diff.blocks .empty ()) {
10010+ for (auto &block : block_diff.blocks ) {
10011+ blocks->emplace_back (std::make_pair (block.first , block.second ));
10012+ }
10013+ }
10014+
10015+ state->index = block_diff.scan_idx ;
10016+ return block_diff.rval ;
10017+ }
10018+
988110019int Client::readdir_snapdiff (dir_result_t * d1, snapid_t snap2,
988210020 struct dirent * out_de,
988310021 snapid_t * out_snap)
0 commit comments