Skip to content

Commit 3f67d1f

Browse files
authored
Merge pull request ceph#61937 from vshankar/wip-file-block-diff
mds/client: file blockdiff support
2 parents d3b1a69 + bb3be44 commit 3f67d1f

File tree

16 files changed

+1041
-5
lines changed

16 files changed

+1041
-5
lines changed

src/client/Client.cc

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
988110019
int Client::readdir_snapdiff(dir_result_t* d1, snapid_t snap2,
988210020
struct dirent* out_de,
988310021
snapid_t* out_snap)

src/client/Client.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,12 @@ class ceph_lock_state_t;
147147
// ========================================================
148148
// client interface
149149

150+
struct scan_state_t {
151+
int fd1;
152+
int fd2;
153+
uint64_t index;
154+
};
155+
150156
struct dir_result_t {
151157
static const int SHIFT = 28;
152158
static const int64_t MASK = (1 << SHIFT) - 1;
@@ -368,6 +374,12 @@ class Client : public Dispatcher, public md_config_obs_t {
368374
int readdir_r(dir_result_t *dirp, struct dirent *de);
369375
int readdirplus_r(dir_result_t *dirp, struct dirent *de, struct ceph_statx *stx, unsigned want, unsigned flags, Inode **out);
370376

377+
int file_blockdiff_init_state(const char *path1, const char *path2,
378+
const UserPerm &perms, struct scan_state_t **state);
379+
int file_blockdiff(struct scan_state_t *state, const UserPerm &perms,
380+
std::vector<std::pair<uint64_t,uint64_t>> *blocks);
381+
int file_blockdiff_finish(struct scan_state_t *state);
382+
371383
/*
372384
* Get the next snapshot delta entry.
373385
*

src/common/ceph_strings.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ const char *ceph_mds_op_name(int op)
328328
case CEPH_MDS_OP_QUIESCE_INODE: return "quiesce_inode";
329329
case CEPH_MDS_OP_LOCK_PATH: return "lock_path";
330330
case CEPH_MDS_OP_UNINLINE_DATA: return "uninline_data";
331+
case CEPH_MDS_OP_FILE_BLOCKDIFF: return "blockdiff";
331332
}
332333
return "???";
333334
}

src/common/options/mds-client.yaml.in

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -589,3 +589,12 @@ options:
589589
- mds_client
590590
flags:
591591
- runtime
592+
- name: client_file_blockdiff_max_concurrent_object_scans
593+
type: uint
594+
level: advanced
595+
desc: maximum number of concurrent object scans
596+
long_desc: Maximum number of concurrent listsnaps operations sent to RADOS.
597+
default: 16
598+
services:
599+
- mds_client
600+
min: 1

src/common/options/mds.yaml.in

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,3 +1754,12 @@ options:
17541754
services:
17551755
- mds
17561756
min: 4
1757+
- name: mds_file_blockdiff_max_concurrent_object_scans
1758+
type: uint
1759+
level: advanced
1760+
desc: maximum number of concurrent object scans
1761+
long_desc: Maximum number of concurrent listsnaps operations sent to RADOS.
1762+
default: 16
1763+
services:
1764+
- mds
1765+
min: 1

src/include/ceph_fs.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -429,6 +429,7 @@ enum {
429429
CEPH_MDS_OP_LSSNAP = 0x00402,
430430
CEPH_MDS_OP_RENAMESNAP = 0x01403,
431431
CEPH_MDS_OP_READDIR_SNAPDIFF = 0x01404,
432+
CEPH_MDS_OP_FILE_BLOCKDIFF = 0x01405,
432433

433434
// internal op
434435
CEPH_MDS_OP_FRAGMENTDIR= 0x01500,
@@ -651,6 +652,12 @@ union ceph_mds_request_args {
651652
__le32 offset_hash;
652653
__le64 snap_other;
653654
} __attribute__ ((packed)) snapdiff;
655+
struct {
656+
// latest scan "pointer"
657+
__le64 scan_idx;
658+
// how many data objects to scan in one invocation (capped by the mds).
659+
__le64 max_objects;
660+
} __attribute__ ((packed)) blockdiff;
654661
} __attribute__ ((packed));
655662

656663
#define CEPH_MDS_REQUEST_HEAD_VERSION 3

src/include/cephfs/libcephfs.h

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -648,6 +648,71 @@ struct ceph_snapdiff_info
648648
// doesn't exist in the second snapshot
649649
};
650650

651+
struct ceph_file_blockdiff_result;
652+
653+
// blockdiff stream handle
654+
struct ceph_file_blockdiff_info
655+
{
656+
struct ceph_mount_info* cmount;
657+
struct ceph_file_blockdiff_result* blockp;
658+
};
659+
660+
// set of file block diff's
661+
struct cblock
662+
{
663+
uint64_t offset;
664+
uint64_t len;
665+
};
666+
struct ceph_file_blockdiff_changedblocks
667+
{
668+
uint64_t num_blocks;
669+
struct cblock *b;
670+
};
671+
672+
/**
673+
* Initialize blockdiff stream to get file block deltas.
674+
*
675+
* @param cmount the ceph mount handle to use for snapdiff retrieval.
676+
* @param root_path root path for snapshots-in-question
677+
* @param rel_path subpath under the root to build delta for
678+
* @param snap1 the first snapshot name
679+
* @param snap2 the second snapshot name
680+
* @param out_info resulting blockdiff stream handle to be used for blokdiff results
681+
retrieval via ceph_file_blockdiff().
682+
* @returns 0 on success and negative error code otherwise
683+
*/
684+
int ceph_file_blockdiff_init(struct ceph_mount_info* cmount,
685+
const char* root_path,
686+
const char* rel_path,
687+
const char* snap1,
688+
const char* snap2,
689+
struct ceph_file_blockdiff_info* out_info);
690+
691+
/**
692+
* Get a set of file blockdiff's
693+
*
694+
* @param info blockdiff stream handle
695+
* @param blocks next set of file blockdiff's (offset, length)
696+
* @returns 0 or 1 on success and negative error code otherwise
697+
*/
698+
int ceph_file_blockdiff(struct ceph_file_blockdiff_info* info,
699+
struct ceph_file_blockdiff_changedblocks* blocks);
700+
/**
701+
* Free blockdiff buffer
702+
*
703+
* @param blocks file block diff's from ceph_file_blockdiff()
704+
* @returns None
705+
*/
706+
void ceph_free_file_blockdiff_buffer(struct ceph_file_blockdiff_changedblocks* blocks);
707+
708+
/**
709+
* Close blockdiff stream
710+
*
711+
* @param info blockdiff stream handle
712+
* @returns 0 on success and negative error code otherwise
713+
*/
714+
int ceph_file_blockdiff_finish(struct ceph_file_blockdiff_info* info);
715+
651716
/**
652717
* Opens snapdiff stream to get snapshots delta (aka snapdiff).
653718
*

0 commit comments

Comments
 (0)