}
};
-int Client::_readdir_cache_cb(dir_result_t *dirp, add_dirent_cb_t cb, void *p, int caps)
+int Client::_readdir_cache_cb(dir_result_t *dirp, add_dirent_cb_t cb, void *p,
+ int caps, bool getref)
{
assert(client_lock.is_locked());
ldout(cct, 10) << "_readdir_cache_cb " << dirp << " on " << dirp->inode->ino
if (pd == dir->readdir_cache.end())
next_off = dir_result_t::END;
+ Inode *in = NULL;
fill_dirent(&de, dn->name.c_str(), stx.stx_mode, stx.stx_ino, next_off);
+ if (getref) {
+ in = dn->inode.get();
+ _ll_get(in);
+ }
dn_name = dn->name; // fill in name while we have lock
client_lock.Unlock();
- r = cb(p, &de, &stx, next_off); // _next_ offset
+ r = cb(p, &de, &stx, next_off, in); // _next_ offset
client_lock.Lock();
ldout(cct, 15) << " de " << de.d_name << " off " << hex << dn->offset << dec
<< " = " << r << dendl;
}
int Client::readdir_r_cb(dir_result_t *d, add_dirent_cb_t cb, void *p,
- unsigned want, unsigned flags)
+ unsigned want, unsigned flags, bool getref)
{
int caps = statx_to_mask(flags, want);
fill_statx(diri, caps, &stx);
fill_dirent(&de, ".", S_IFDIR, stx.stx_ino, next_off);
+ Inode *inode = NULL;
+ if (getref) {
+ inode = diri.get();
+ _ll_get(inode);
+ }
+
client_lock.Unlock();
- r = cb(p, &de, &stx, next_off);
+ r = cb(p, &de, &stx, next_off, inode);
client_lock.Lock();
if (r < 0)
return r;
fill_statx(in, caps, &stx);
fill_dirent(&de, "..", S_IFDIR, stx.stx_ino, next_off);
+ Inode *inode = NULL;
+ if (getref) {
+ inode = in.get();
+ _ll_get(inode);
+ }
+
client_lock.Unlock();
- r = cb(p, &de, &stx, next_off);
+ r = cb(p, &de, &stx, next_off, inode);
client_lock.Lock();
if (r < 0)
return r;
if (dirp->inode->snapid != CEPH_SNAPDIR &&
dirp->inode->is_complete_and_ordered() &&
dirp->inode->caps_issued_mask(CEPH_CAP_FILE_SHARED)) {
- int err = _readdir_cache_cb(dirp, cb, p, caps);
+ int err = _readdir_cache_cb(dirp, cb, p, caps, getref);
if (err != -EAGAIN)
return err;
}
fill_statx(entry.inode, caps, &stx);
fill_dirent(&de, entry.name.c_str(), stx.stx_mode, stx.stx_ino, next_off);
+ Inode *inode = NULL;
+ if (getref) {
+ inode = entry.inode.get();
+ _ll_get(inode);
+ }
+
client_lock.Unlock();
- r = cb(p, &de, &stx, next_off); // _next_ offset
+ r = cb(p, &de, &stx, next_off, inode); // _next_ offset
client_lock.Lock();
ldout(cct, 15) << " de " << de.d_name << " off " << hex << next_off - 1 << dec
int Client::readdir_r(dir_result_t *d, struct dirent *de)
{
- return readdirplus_r(d, de, 0, 0, 0);
+ return readdirplus_r(d, de, 0, 0, 0, NULL);
}
/*
struct single_readdir {
struct dirent *de;
struct ceph_statx *stx;
+ Inode *inode;
bool full;
};
static int _readdir_single_dirent_cb(void *p, struct dirent *de,
- struct ceph_statx *stx, off_t off)
+ struct ceph_statx *stx, off_t off,
+ Inode *in)
{
single_readdir *c = static_cast<single_readdir *>(p);
*c->de = *de;
if (c->stx)
*c->stx = *stx;
+ c->inode = in;
c->full = true;
return 1;
}
single_readdir sr;
sr.de = &de;
sr.stx = NULL;
+ sr.inode = NULL;
sr.full = false;
// our callback fills the dirent and sets sr.full=true on first
int Client::readdirplus_r(dir_result_t *d, struct dirent *de,
struct ceph_statx *stx, unsigned want,
- unsigned flags)
+ unsigned flags, Inode **out)
{
single_readdir sr;
sr.de = de;
sr.stx = stx;
+ sr.inode = NULL;
sr.full = false;
// our callback fills the dirent and sets sr.full=true on first
// call, and returns -1 the second time around.
- int r = readdir_r_cb(d, _readdir_single_dirent_cb, (void *)&sr, want, flags);
+ int r = readdir_r_cb(d, _readdir_single_dirent_cb, (void *)&sr, want, flags, out);
if (r < -1)
return r;
+ if (out)
+ *out = sr.inode;
if (sr.full)
return 1;
return 0;
};
static int _readdir_getdent_cb(void *p, struct dirent *de,
- struct ceph_statx *stx, off_t off)
+ struct ceph_statx *stx, off_t off, Inode *in)
{
struct getdents_result *c = static_cast<getdents_result *>(p);
int num;
};
-static int _getdir_cb(void *p, struct dirent *de, struct ceph_statx *stx, off_t off)
+static int _getdir_cb(void *p, struct dirent *de, struct ceph_statx *stx, off_t off, Inode *in)
{
getdir_result *r = static_cast<getdir_result *>(p);
void fill_dirent(struct dirent *de, const char *name, int type, uint64_t ino, loff_t next_off);
// some readdir helpers
- typedef int (*add_dirent_cb_t)(void *p, struct dirent *de, struct ceph_statx *stx, off_t off);
+ typedef int (*add_dirent_cb_t)(void *p, struct dirent *de, struct ceph_statx *stx, off_t off, Inode *in);
int _opendir(Inode *in, dir_result_t **dirpp, const UserPerm& perms);
void _readdir_drop_dirp_buffer(dir_result_t *dirp);
void _readdir_next_frag(dir_result_t *dirp);
void _readdir_rechoose_frag(dir_result_t *dirp);
int _readdir_get_frag(dir_result_t *dirp);
- int _readdir_cache_cb(dir_result_t *dirp, add_dirent_cb_t cb, void *p, int caps);
+ int _readdir_cache_cb(dir_result_t *dirp, add_dirent_cb_t cb, void *p, int caps, bool getref);
void _closedir(dir_result_t *dirp);
// other helpers
* If @a cb returns a negative error code, stop and return that.
*/
int readdir_r_cb(dir_result_t *dirp, add_dirent_cb_t cb, void *p,
- unsigned want=0, unsigned flags=AT_NO_ATTR_SYNC);
+ unsigned want=0, unsigned flags=AT_NO_ATTR_SYNC,
+ bool getref=false);
struct dirent * readdir(dir_result_t *d);
int readdir_r(dir_result_t *dirp, struct dirent *de);
- int readdirplus_r(dir_result_t *dirp, struct dirent *de, struct ceph_statx *stx, unsigned want, unsigned flags);
+ int readdirplus_r(dir_result_t *dirp, struct dirent *de, struct ceph_statx *stx, unsigned want, unsigned flags, Inode **out);
int getdir(const char *relpath, list<string>& names,
const UserPerm& perms); // get the whole dir at once.
* return 0 on success, -1 if out of space
*/
static int fuse_ll_add_dirent(void *p, struct dirent *de,
- struct ceph_statx *stx, off_t next_off)
+ struct ceph_statx *stx, off_t next_off,
+ Inode *in)
{
struct readdir_context *c = (struct readdir_context *)p;
CephFuse::Handle *cfuse = (CephFuse::Handle *)fuse_req_userdata(c->req);
int r;
if ((r = ceph_opendir(cmount, directory, &dirp)) < 0)
return r; //failed to open
- while ((r = ceph_readdirplus_r(cmount, dirp, &de, &stx, CEPH_STATX_INO, AT_NO_ATTR_SYNC)) > 0) {
+ while ((r = ceph_readdirplus_r(cmount, dirp, &de, &stx, CEPH_STATX_INO, AT_NO_ATTR_SYNC, NULL)) > 0) {
String new_dir = de.d_name;
if(!(new_dir.compare(".")==0 || new_dir.compare("..")==0)) {
new_dir = directory;
* @param stx the stats of the file/directory of the entry returned
* @param want mask showing desired inode attrs for returned entry
* @param flags bitmask of flags to use when filling out attributes
+ * @param out optional returned Inode argument. If non-NULL, then a reference will be taken on
+ * the inode and the pointer set on success.
* @returns 1 if the next entry was filled in, 0 if the end of the directory stream was reached,
* and a negative error code on failure.
*/
int ceph_readdirplus_r(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp, struct dirent *de,
- struct ceph_statx *stx, unsigned want, unsigned flags);
+ struct ceph_statx *stx, unsigned want, unsigned flags, struct Inode **out);
/**
* Gets multiple directory entries.
extern "C" int ceph_readdirplus_r(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp,
struct dirent *de, struct ceph_statx *stx, unsigned want,
- unsigned flags)
+ unsigned flags, struct Inode **out)
{
if (!cmount->is_mounted())
return -ENOTCONN;
- return cmount->get_client()->readdirplus_r(reinterpret_cast<dir_result_t*>(dirp), de, stx, want, flags);
+ return cmount->get_client()->readdirplus_r(reinterpret_cast<dir_result_t*>(dirp), de, stx, want, flags, out);
}
extern "C" int ceph_getdents(struct ceph_mount_info *cmount, struct ceph_dir_result *dirp,
struct dirent rdent;
struct ceph_statx stx;
int len = ceph_readdirplus_r(cmount, ls_dir, &rdent, &stx,
- CEPH_STATX_SIZE, AT_NO_ATTR_SYNC);
+ CEPH_STATX_SIZE, AT_NO_ATTR_SYNC, NULL);
if (len == 0)
break;
ASSERT_EQ(len, 1);
EXPECT_EQ(-ENOTCONN, ceph_readdir_r(cmount, dirp, &rdent));
struct ceph_statx stx;
- EXPECT_EQ(-ENOTCONN, ceph_readdirplus_r(cmount, dirp, &rdent, &stx, 0, 0));
+ EXPECT_EQ(-ENOTCONN, ceph_readdirplus_r(cmount, dirp, &rdent, &stx, 0, 0, NULL));
EXPECT_EQ(-ENOTCONN, ceph_getdents(cmount, dirp, NULL, 0));
EXPECT_EQ(-ENOTCONN, ceph_getdnames(cmount, dirp, NULL, 0));
EXPECT_EQ(-ENOTCONN, ceph_telldir(cmount, dirp));