From e65b8dcad1d8b71d5dda6c29bc174dc5e069438f Mon Sep 17 00:00:00 2001 From: Patrick Donnelly Date: Mon, 11 Jan 2021 13:39:27 -0800 Subject: [PATCH] client: wire up alternate_name Here we're exposing a public Client::walk (aka path_walk) so that the user can inspect dentries (not something normally possible in POSIX). We're going to skip exposing such an interface in libcephfs since there's no reason to do that (who would use it?) except for testing. Instead, a follow-up PR will add Client tests (for the first time, yay!) that will exercise this code. Also, ideally we'd also expose alternate_name via readdir results but that is a bit more complicated since dirents do not normally refer to external memory. So, just rely on Client::walk for testing for now. Signed-off-by: Patrick Donnelly --- src/client/Client.cc | 114 +++++++++++++++++++++++----------- src/client/Client.h | 51 +++++++++------ src/client/MetaRequest.h | 2 + src/messages/MClientRequest.h | 2 +- 4 files changed, 113 insertions(+), 56 deletions(-) diff --git a/src/client/Client.cc b/src/client/Client.cc index 01e130037a256..0695ea2400fff 100644 --- a/src/client/Client.cc +++ b/src/client/Client.cc @@ -1061,7 +1061,6 @@ Dentry *Client::insert_dentry_inode(Dir *dir, const string& dname, LeaseStat *dl } update_dentry_lease(dn, dlease, from, session); - dn->alternate_name = std::move(dlease->alternate_name); return dn; } @@ -1069,6 +1068,8 @@ void Client::update_dentry_lease(Dentry *dn, LeaseStat *dlease, utime_t from, Me { utime_t dttl = from; dttl += (float)dlease->duration_ms / 1000.0; + + ldout(cct, 15) << __func__ << " " << *dn << " " << *dlease << " from " << from << dendl; ceph_assert(dn); @@ -1085,6 +1086,7 @@ void Client::update_dentry_lease(Dentry *dn, LeaseStat *dlease, utime_t from, Me dn->cap_shared_gen = dn->dir->parent_inode->shared_gen; if (dlease->mask & CEPH_LEASE_PRIMARY_LINK) dn->mark_primary(); + dn->alternate_name = std::move(dlease->alternate_name); } @@ -1281,7 +1283,7 @@ void Client::insert_readdir_results(MetaRequest *request, MetaSession *session, dirp->cache_index++; } // add to cached result list - dirp->buffer.push_back(dir_result_t::dentry(dn->offset, dname, in)); + dirp->buffer.push_back(dir_result_t::dentry(dn->offset, dname, dn->alternate_name, in)); ldout(cct, 15) << __func__ << " " << hex << dn->offset << dec << ": '" << dname << "' -> " << in->ino << dendl; } @@ -2371,6 +2373,7 @@ ref_t Client::build_client_request(MetaRequest *request) } req->set_filepath(request->get_filepath()); req->set_filepath2(request->get_filepath2()); + req->set_alternate_name(request->alternate_name); req->set_data(request->data); req->set_retry_attempt(request->retry_attempt++); req->head.num_fwd = request->num_fwd; @@ -6697,10 +6700,11 @@ bool Client::_dentry_valid(const Dentry *dn) } int Client::_lookup(Inode *dir, const string& dname, int mask, InodeRef *target, - const UserPerm& perms) + const UserPerm& perms, std::string* alternate_name) { int r = 0; Dentry *dn = NULL; + bool did_lookup_request = false; // can only request shared caps mask &= CEPH_CAP_ANY_SHARED | CEPH_STAT_RSTAT; @@ -6746,13 +6750,13 @@ int Client::_lookup(Inode *dir, const string& dname, int mask, InodeRef *target, goto done; } +relookup: if (dir->dir && dir->dir->dentries.count(dname)) { dn = dir->dir->dentries[dname]; - ldout(cct, 20) << __func__ << " have dn " << dname << " mds." << dn->lease_mds << " ttl " << dn->lease_ttl - << " seq " << dn->lease_seq - << dendl; + ldout(cct, 20) << __func__ << " have " << *dn << " from mds." << dn->lease_mds + << " ttl " << dn->lease_ttl << " seq " << dn->lease_seq << dendl; if (!dn->inode || dn->inode->caps_issued_mask(mask, true)) { if (_dentry_valid(dn)) { @@ -6784,16 +6788,29 @@ int Client::_lookup(Inode *dir, const string& dname, int mask, InodeRef *target, } } + if (did_lookup_request) { + r = 0; + goto done; + } r = _do_lookup(dir, dname, mask, target, perms); - goto done; + did_lookup_request = true; + if (r == 0) { + /* complete lookup to get dentry for alternate_name */ + goto relookup; + } else { + goto done; + } hit_dn: if (dn->inode) { *target = dn->inode; + if (alternate_name) + *alternate_name = dn->alternate_name; } else { r = -ENOENT; } touch_dn(dn); + goto done; done: if (r < 0) @@ -6825,11 +6842,33 @@ int Client::get_or_create(Inode *dir, const char* name, return 0; } +int Client::walk(std::string_view path, walk_dentry_result* wdr, const UserPerm& perms, bool followsym) +{ + RWRef_t mref_reader(mount_state, CLIENT_MOUNTING); + if (!mref_reader.is_state_satisfied()) + return -ENOTCONN; + + ldout(cct, 10) << __func__ << ": " << path << dendl; + + std::scoped_lock lock(client_lock); + + return path_walk(path, wdr, perms, followsym); +} + int Client::path_walk(const filepath& origpath, InodeRef *end, const UserPerm& perms, bool followsym, int mask) +{ + walk_dentry_result wdr; + int rc = path_walk(origpath, &wdr, perms, followsym, mask); + *end = std::move(wdr.in); + return rc; +} + +int Client::path_walk(const filepath& origpath, walk_dentry_result* result, const UserPerm& perms, bool followsym, int mask) { filepath path = origpath; InodeRef cur; + std::string alternate_name; if (origpath.absolute()) cur = root; else @@ -6857,7 +6896,7 @@ int Client::path_walk(const filepath& origpath, InodeRef *end, /* Get extra requested caps on the last component */ if (i == (path.depth() - 1)) caps |= mask; - int r = _lookup(cur.get(), dname, caps, &next, perms); + int r = _lookup(cur.get(), dname, caps, &next, perms, &alternate_name); if (r < 0) return r; // only follow trailing symlink if followsym. always follow @@ -6902,15 +6941,17 @@ int Client::path_walk(const filepath& origpath, InodeRef *end, } if (!cur) return -ENOENT; - if (end) - end->swap(cur); + if (result) { + result->in = std::move(cur); + result->alternate_name = std::move(alternate_name); + } return 0; } // namespace ops -int Client::link(const char *relexisting, const char *relpath, const UserPerm& perm) +int Client::link(const char *relexisting, const char *relpath, const UserPerm& perm, std::string alternate_name) { RWRef_t mref_reader(mount_state, CLIENT_MOUNTING); if (!mref_reader.is_state_satisfied()) @@ -6951,7 +6992,7 @@ int Client::link(const char *relexisting, const char *relpath, const UserPerm& p if (r < 0) return r; } - r = _link(in.get(), dir.get(), name.c_str(), perm); + r = _link(in.get(), dir.get(), name.c_str(), perm, std::move(alternate_name)); return r; } @@ -6984,7 +7025,7 @@ int Client::unlink(const char *relpath, const UserPerm& perm) return _unlink(dir.get(), name.c_str(), perm); } -int Client::rename(const char *relfrom, const char *relto, const UserPerm& perm) +int Client::rename(const char *relfrom, const char *relto, const UserPerm& perm, std::string alternate_name) { RWRef_t mref_reader(mount_state, CLIENT_MOUNTING); if (!mref_reader.is_state_satisfied()) @@ -7022,14 +7063,14 @@ int Client::rename(const char *relfrom, const char *relto, const UserPerm& perm) if (r < 0 && r != -ENOENT) return r; } - r = _rename(fromdir.get(), fromname.c_str(), todir.get(), toname.c_str(), perm); + r = _rename(fromdir.get(), fromname.c_str(), todir.get(), toname.c_str(), perm, std::move(alternate_name)); out: return r; } // dirs -int Client::mkdir(const char *relpath, mode_t mode, const UserPerm& perm) +int Client::mkdir(const char *relpath, mode_t mode, const UserPerm& perm, std::string alternate_name) { RWRef_t mref_reader(mount_state, CLIENT_MOUNTING); if (!mref_reader.is_state_satisfied()) @@ -7057,7 +7098,7 @@ int Client::mkdir(const char *relpath, mode_t mode, const UserPerm& perm) if (r < 0) return r; } - return _mkdir(dir.get(), name.c_str(), mode, perm); + return _mkdir(dir.get(), name.c_str(), mode, perm, 0, {}, std::move(alternate_name)); } int Client::mkdirs(const char *relpath, mode_t mode, const UserPerm& perms) @@ -7179,7 +7220,7 @@ int Client::mknod(const char *relpath, mode_t mode, const UserPerm& perms, dev_t // symlinks -int Client::symlink(const char *target, const char *relpath, const UserPerm& perms) +int Client::symlink(const char *target, const char *relpath, const UserPerm& perms, std::string alternate_name) { RWRef_t mref_reader(mount_state, CLIENT_MOUNTING); if (!mref_reader.is_state_satisfied()) @@ -7206,7 +7247,7 @@ int Client::symlink(const char *target, const char *relpath, const UserPerm& per if (r < 0) return r; } - return _symlink(dir.get(), name.c_str(), target, perms); + return _symlink(dir.get(), name.c_str(), target, perms, std::move(alternate_name)); } int Client::readlink(const char *relpath, char *buf, loff_t size, const UserPerm& perms) @@ -8916,7 +8957,7 @@ int Client::getdir(const char *relpath, list& contents, /****** file i/o **********/ int Client::open(const char *relpath, int flags, const UserPerm& perms, mode_t mode, int stripe_unit, int stripe_count, - int object_size, const char *data_pool) + int object_size, const char *data_pool, std::string alternate_name) { RWRef_t mref_reader(mount_state, CLIENT_MOUNTING); if (!mref_reader.is_state_satisfied()) @@ -8974,7 +9015,8 @@ int Client::open(const char *relpath, int flags, const UserPerm& perms, goto out; } r = _create(dir.get(), dname.c_str(), flags, mode, &in, &fh, stripe_unit, - stripe_count, object_size, data_pool, &created, perms); + stripe_count, object_size, data_pool, &created, perms, + std::move(alternate_name)); } if (r < 0) goto out; @@ -9004,12 +9046,6 @@ int Client::open(const char *relpath, int flags, const UserPerm& perms, return r; } -int Client::open(const char *relpath, int flags, const UserPerm& perms, mode_t mode) -{ - /* Use default file striping parameters */ - return open(relpath, flags, perms, mode, 0, 0, 0, NULL); -} - int Client::lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name, const UserPerm& perms) { @@ -12781,7 +12817,7 @@ int Client::ll_mknodx(Inode *parent, const char *name, mode_t mode, int Client::_create(Inode *dir, const char *name, int flags, mode_t mode, InodeRef *inp, Fh **fhp, int stripe_unit, int stripe_count, int object_size, const char *data_pool, bool *created, - const UserPerm& perms) + const UserPerm& perms, std::string alternate_name) { ldout(cct, 8) << "_create(" << dir->ino << " " << name << ", 0" << oct << mode << dec << ")" << dendl; @@ -12818,6 +12854,7 @@ int Client::_create(Inode *dir, const char *name, int flags, mode_t mode, dir->make_nosnap_relative_path(path); path.push_dentry(name); req->set_filepath(path); + req->set_alternate_name(std::move(alternate_name)); req->set_inode(dir); req->head.args.open.flags = cflags | CEPH_O_CREAT; @@ -12874,7 +12911,8 @@ int Client::_create(Inode *dir, const char *name, int flags, mode_t mode, } int Client::_mkdir(Inode *dir, const char *name, mode_t mode, const UserPerm& perm, - InodeRef *inp, const std::map &metadata) + InodeRef *inp, const std::map &metadata, + std::string alternate_name) { ldout(cct, 8) << "_mkdir(" << dir->ino << " " << name << ", 0" << oct << mode << dec << ", uid " << perm.uid() @@ -12901,6 +12939,7 @@ int Client::_mkdir(Inode *dir, const char *name, mode_t mode, const UserPerm& pe req->set_inode(dir); req->dentry_drop = CEPH_CAP_FILE_SHARED; req->dentry_unless = CEPH_CAP_FILE_EXCL; + req->set_alternate_name(std::move(alternate_name)); mode |= S_IFDIR; bufferlist bl; @@ -13018,7 +13057,7 @@ int Client::ll_mkdirx(Inode *parent, const char *name, mode_t mode, Inode **out, } int Client::_symlink(Inode *dir, const char *name, const char *target, - const UserPerm& perms, InodeRef *inp) + const UserPerm& perms, std::string alternate_name, InodeRef *inp) { ldout(cct, 8) << "_symlink(" << dir->ino << " " << name << ", " << target << ", uid " << perms.uid() << ", gid " << perms.gid() << ")" @@ -13040,6 +13079,7 @@ int Client::_symlink(Inode *dir, const char *name, const char *target, dir->make_nosnap_relative_path(path); path.push_dentry(name); req->set_filepath(path); + req->set_alternate_name(std::move(alternate_name)); req->set_inode(dir); req->set_string2(target); req->dentry_drop = CEPH_CAP_FILE_SHARED; @@ -13088,7 +13128,7 @@ int Client::ll_symlink(Inode *parent, const char *name, const char *value, } InodeRef in; - int r = _symlink(parent, name, value, perms, &in); + int r = _symlink(parent, name, value, perms, "", &in); if (r == 0) { fill_stat(in, attr); _ll_get(in.get()); @@ -13126,7 +13166,7 @@ int Client::ll_symlinkx(Inode *parent, const char *name, const char *value, } InodeRef in; - int r = _symlink(parent, name, value, perms, &in); + int r = _symlink(parent, name, value, perms, "", &in); if (r == 0) { fill_statx(in, statx_to_mask(flags, want), stx); _ll_get(in.get()); @@ -13288,7 +13328,7 @@ int Client::ll_rmdir(Inode *in, const char *name, const UserPerm& perms) return _rmdir(in, name, perms); } -int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const char *toname, const UserPerm& perm) +int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const char *toname, const UserPerm& perm, std::string alternate_name) { ldout(cct, 8) << "_rename(" << fromdir->ino << " " << fromname << " to " << todir->ino << " " << toname @@ -13326,6 +13366,7 @@ int Client::_rename(Inode *fromdir, const char *fromname, Inode *todir, const ch to.push_dentry(toname); req->set_filepath(to); req->set_filepath2(from); + req->set_alternate_name(std::move(alternate_name)); Dentry *oldde; int res = get_or_create(fromdir, fromname, &oldde); @@ -13424,10 +13465,10 @@ int Client::ll_rename(Inode *parent, const char *name, Inode *newparent, return r; } - return _rename(parent, name, newparent, newname, perm); + return _rename(parent, name, newparent, newname, perm, ""); } -int Client::_link(Inode *in, Inode *dir, const char *newname, const UserPerm& perm, InodeRef *inp) +int Client::_link(Inode *in, Inode *dir, const char *newname, const UserPerm& perm, std::string alternate_name, InodeRef *inp) { ldout(cct, 8) << "_link(" << in->ino << " to " << dir->ino << " " << newname << " uid " << perm.uid() << " gid " << perm.gid() << ")" << dendl; @@ -13447,6 +13488,7 @@ int Client::_link(Inode *in, Inode *dir, const char *newname, const UserPerm& pe filepath path(newname, dir->ino); req->set_filepath(path); + req->set_alternate_name(std::move(alternate_name)); filepath existing(in->ino); req->set_filepath2(existing); @@ -13506,7 +13548,7 @@ int Client::ll_link(Inode *in, Inode *newparent, const char *newname, return r; } - return _link(in, newparent, newname, perm, &target); + return _link(in, newparent, newname, perm, "", &target); } int Client::ll_num_osds(void) @@ -13734,7 +13776,7 @@ int Client::_ll_create(Inode *parent, const char *name, mode_t mode, goto out; } r = _create(parent, name, flags, mode, in, fhp, 0, 0, 0, NULL, &created, - perms); + perms, ""); if (r < 0) goto out; } diff --git a/src/client/Client.h b/src/client/Client.h index 5278fd78b941f..84e49e4f37270 100644 --- a/src/client/Client.h +++ b/src/client/Client.h @@ -136,11 +136,12 @@ struct dir_result_t { struct dentry { int64_t offset; - string name; + std::string name; + std::string alternate_name; InodeRef inode; explicit dentry(int64_t o) : offset(o) {} - dentry(int64_t o, const string& n, const InodeRef& in) : - offset(o), name(n), inode(in) {} + dentry(int64_t o, std::string n, std::string an, InodeRef in) : + offset(o), name(std::move(n)), alternate_name(std::move(an)), inode(std::move(in)) {} }; struct dentry_off_lt { bool operator()(const dentry& d, int64_t off) const { @@ -248,6 +249,11 @@ public: typedef int (*add_dirent_cb_t)(void *p, struct dirent *de, struct ceph_statx *stx, off_t off, Inode *in); + struct walk_dentry_result { + InodeRef in; + std::string alternate_name; + }; + class CommandHook : public AdminSocketHook { public: explicit CommandHook(Client *client); @@ -363,19 +369,22 @@ public: loff_t telldir(dir_result_t *dirp); void seekdir(dir_result_t *dirp, loff_t offset); - int link(const char *existing, const char *newname, const UserPerm& perm); + int link(const char *existing, const char *newname, const UserPerm& perm, std::string alternate_name=""); int unlink(const char *path, const UserPerm& perm); - int rename(const char *from, const char *to, const UserPerm& perm); + int rename(const char *from, const char *to, const UserPerm& perm, std::string alternate_name=""); // dirs - int mkdir(const char *path, mode_t mode, const UserPerm& perm); + int mkdir(const char *path, mode_t mode, const UserPerm& perm, std::string alternate_name=""); int mkdirs(const char *path, mode_t mode, const UserPerm& perms); int rmdir(const char *path, const UserPerm& perms); // symlinks int readlink(const char *path, char *buf, loff_t size, const UserPerm& perms); - int symlink(const char *existing, const char *newname, const UserPerm& perms); + int symlink(const char *existing, const char *newname, const UserPerm& perms, std::string alternate_name=""); + + // path traversal for high-level interface + int walk(std::string_view path, struct walk_dentry_result* result, const UserPerm& perms, bool followsym=true); // inode stuff unsigned statx_to_mask(unsigned int flags, unsigned int want); @@ -413,10 +422,12 @@ public: // file ops int mknod(const char *path, mode_t mode, const UserPerm& perms, dev_t rdev=0); - int open(const char *path, int flags, const UserPerm& perms, mode_t mode=0); + int open(const char *path, int flags, const UserPerm& perms, mode_t mode=0, std::string alternate_name="") { + return open(path, flags, perms, mode, 0, 0, 0, NULL, alternate_name); + } int open(const char *path, int flags, const UserPerm& perms, mode_t mode, int stripe_unit, int stripe_count, int object_size, - const char *data_pool); + const char *data_pool, std::string alternate_name=""); int lookup_hash(inodeno_t ino, inodeno_t dirino, const char *name, const UserPerm& perms); int lookup_ino(inodeno_t ino, const UserPerm& perms, Inode **inode=NULL); @@ -867,6 +878,10 @@ protected: void handle_client_reply(const MConstRef& reply); bool is_dir_operation(MetaRequest *request); + int path_walk(const filepath& fp, struct walk_dentry_result* result, const UserPerm& perms, bool followsym=true, int mask=0); + int path_walk(const filepath& fp, InodeRef *end, const UserPerm& perms, + bool followsym=true, int mask=0); + // fake inode number for 32-bits ino_t void _assign_faked_ino(Inode *in); void _assign_faked_root(Inode *in); @@ -936,10 +951,6 @@ protected: Dentry* link(Dir *dir, const string& name, Inode *in, Dentry *dn); void unlink(Dentry *dn, bool keepdir, bool keepdentry); - // path traversal for high-level interface - int path_walk(const filepath& fp, InodeRef *end, const UserPerm& perms, - bool followsym=true, int mask=0); - int fill_stat(Inode *in, struct stat *st, frag_info_t *dirstat=0, nest_info_t *rstat=0); int fill_stat(InodeRef& in, struct stat *st, frag_info_t *dirstat=0, nest_info_t *rstat=0) { return fill_stat(in.get(), st, dirstat, rstat); @@ -1217,17 +1228,18 @@ private: const UserPerm& perms); int _lookup(Inode *dir, const string& dname, int mask, InodeRef *target, - const UserPerm& perm); + const UserPerm& perm, std::string* alternate_name=nullptr); - int _link(Inode *in, Inode *dir, const char *name, const UserPerm& perm, + int _link(Inode *in, Inode *dir, const char *name, const UserPerm& perm, std::string alternate_name, InodeRef *inp = 0); int _unlink(Inode *dir, const char *name, const UserPerm& perm); - int _rename(Inode *olddir, const char *oname, Inode *ndir, const char *nname, const UserPerm& perm); + int _rename(Inode *olddir, const char *oname, Inode *ndir, const char *nname, const UserPerm& perm, std::string alternate_name); int _mkdir(Inode *dir, const char *name, mode_t mode, const UserPerm& perm, - InodeRef *inp = 0, const std::map &metadata={}); + InodeRef *inp = 0, const std::map &metadata={}, + std::string alternate_name=""); int _rmdir(Inode *dir, const char *name, const UserPerm& perms); int _symlink(Inode *dir, const char *name, const char *target, - const UserPerm& perms, InodeRef *inp = 0); + const UserPerm& perms, std::string alternate_name, InodeRef *inp = 0); int _mknod(Inode *dir, const char *name, mode_t mode, dev_t rdev, const UserPerm& perms, InodeRef *inp = 0); int _do_setattr(Inode *in, struct ceph_statx *stx, int mask, @@ -1266,7 +1278,8 @@ private: int _renew_caps(Inode *in); int _create(Inode *in, const char *name, int flags, mode_t mode, InodeRef *inp, Fh **fhp, int stripe_unit, int stripe_count, int object_size, - const char *data_pool, bool *created, const UserPerm &perms); + const char *data_pool, bool *created, const UserPerm &perms, + std::string alternate_name); loff_t _lseek(Fh *fh, loff_t offset, int whence); int64_t _read(Fh *fh, int64_t offset, uint64_t size, bufferlist *bl); diff --git a/src/client/MetaRequest.h b/src/client/MetaRequest.h index 4d0f37273a471..db134a705832c 100644 --- a/src/client/MetaRequest.h +++ b/src/client/MetaRequest.h @@ -29,6 +29,7 @@ public: utime_t op_stamp; ceph_mds_request_head head; filepath path, path2; + std::string alternate_name; bufferlist data; int inode_drop; //the inode caps this operation will drop int inode_unless; //unless we have these caps already @@ -169,6 +170,7 @@ public: void set_retry_attempt(int a) { head.num_retry = a; } void set_filepath(const filepath& fp) { path = fp; } void set_filepath2(const filepath& fp) { path2 = fp; } + void set_alternate_name(std::string an) { alternate_name = an; } void set_string2(const char *s) { path2.set_path(std::string_view(s), 0); } void set_caller_perms(const UserPerm& _perms) { perms.shallow_copy(_perms); diff --git a/src/messages/MClientRequest.h b/src/messages/MClientRequest.h index a02572367c069..c51f1149e0cd9 100644 --- a/src/messages/MClientRequest.h +++ b/src/messages/MClientRequest.h @@ -180,7 +180,7 @@ public: head.flags = head.flags | CEPH_MDS_FLAG_ASYNC; } - void set_alternate_name(std::string&& _alternate_name) { + void set_alternate_name(std::string _alternate_name) { alternate_name = std::move(_alternate_name); } void set_alternate_name(bufferptr&& cipher) { -- 2.39.5