#include "super.h"
/*
- * Directory operations: lookup, create, link, unlink, rename, etc.
+ * Directory operations: readdir, lookup, create, link, unlink,
+ * rename, etc.
*/
/*
const struct file_operations ceph_dir_fops;
struct dentry_operations ceph_dentry_ops;
-static int ceph_dentry_revalidate(struct dentry *dentry, struct nameidata *nd);
-
/*
* for readdir, we encode the directory frag and offset within that
* frag into f_pos.
if (fi->at_end)
return 0;
+ /* always start with . and .. */
if (filp->f_pos == 0) {
- /* note dir version at start of readdir */
+ /* note dir version at start of readdir so we can tell
+ * if any dentries get dropped */
fi->dir_release_count = ci->i_release_count;
dout("readdir off 0 -> '.'\n");
fi->dentry = NULL;
}
+ /* proceed with a normal readdir */
+
more:
/* do we have the correct frag content buffered? */
if (fi->frag != frag || fi->last_readdir == NULL) {
if (!req->r_did_prepopulate) {
dout("readdir !did_prepopulate");
- fi->dir_release_count--;
+ fi->dir_release_count--; /* preclude I_COMPLETE */
}
+ /*
+ * make note of the last dentry we read, so we can
+ * continue at the same lexicographical point,
+ * regardless of what dir changes take place on the
+ * server. and choose the next offset to
+ * readdir from.
+ */
fi->offset = fi->next_offset;
kfree(fi->last_name);
fi->last_name = NULL;
-
if (req->r_reply_info.dir_end) {
fi->next_offset = 0;
} else {
mutex_lock(&inode->i_mutex);
switch (origin) {
case SEEK_END:
- offset += inode->i_size;
+ offset += inode->i_size + 2; /* FIXME */
break;
case SEEK_CUR:
offset += file->f_pos;
}
static int ceph_create(struct inode *dir, struct dentry *dentry, int mode,
- struct nameidata *nd)
+ struct nameidata *nd)
{
dout("create in dir %p dentry %p name '%.*s'\n",
dir, dentry, dentry->d_name.len, dentry->d_name.name);
/*
* Check if dentry lease is valid. If not, delete the lease. Try to
- * renew if appropriate.
+ * renew if the least is more than half up.
*/
static int dentry_lease_is_valid(struct dentry *dentry)
{
/*
* Check if cached dentry can be trusted.
*/
-static int ceph_dentry_revalidate(struct dentry *dentry, struct nameidata *nd)
+static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd)
{
struct inode *dir = dentry->d_parent->d_inode;
if (dentry->d_inode && ceph_snap(dentry->d_inode) == CEPH_SNAPDIR)
goto out_touch;
- if (dentry_lease_is_valid(dentry))
+ if (dentry_lease_is_valid(dentry) ||
+ dir_lease_is_valid(dir, dentry))
goto out_touch;
- if (dir_lease_is_valid(dir, dentry))
- goto out_touch;
-
- dout("dentry_revalidate %p invalid\n", dentry);
+ dout("d_revalidate %p invalid\n", dentry);
d_drop(dentry);
return 0;
out_touch:
}
/*
- * When a dentry is released, only clear the dir I_COMPLETE if it was
- * part of the current dir version.
+ * When a dentry is released, clear the dir I_COMPLETE if it was part
+ * of the current dir gen.
*/
static void ceph_dentry_release(struct dentry *dentry)
{
}
}
-static int ceph_snapdir_dentry_revalidate(struct dentry *dentry,
+static int ceph_snapdir_d_revalidate(struct dentry *dentry,
struct nameidata *nd)
{
/*
* Eventually, we'll want to revalidate snapped metadata
- * too... probably.
+ * too... probably...
*/
return 1;
}
return ret;
}
+/*
+ * We maintain a private dentry LRU.
+ *
+ * FIXME: this needs to be changed to a per-mds lru to be useful.
+ */
void ceph_dentry_lru_add(struct dentry *dn)
{
struct ceph_dentry_info *di = ceph_dentry(dn);
};
struct dentry_operations ceph_dentry_ops = {
- .d_revalidate = ceph_dentry_revalidate,
+ .d_revalidate = ceph_d_revalidate,
.d_release = ceph_dentry_release,
};
struct dentry_operations ceph_snapdir_dentry_ops = {
- .d_revalidate = ceph_snapdir_dentry_revalidate,
+ .d_revalidate = ceph_snapdir_d_revalidate,
};
struct dentry_operations ceph_snap_dentry_ops = {