commit 2f859fa3db412d0ce1f6dab9f3fac171d2c744ec
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date: Fri Feb 16 17:12:53 2007 -0500
added purge dir cache which truncates the dir's contents file
(but still kept in the mtime checks)
moved read/write dirents code to their own odf functions
diff --git a/fs/unionfs/dirfops.c b/fs/unionfs/dirfops.c
index 0780aae..e2ee58f 100644
--- a/fs/unionfs/dirfops.c
+++ b/fs/unionfs/dirfops.c
@@ -25,14 +25,11 @@ static int unionfs_readdir(struct file *file, void *dirent,
filldir_t filldir)
struct inode *inode = NULL;
struct odf_dentry_info *odi = NULL;
loff_t size;
- mm_segment_t oldfs;
/* dirent */
u64 ino;
char *name = NULL;
- int namelen, magic;
+ int namelen;
unsigned int d_type;
- __le32 le32;
- __le64 le64;
if ((err = unionfs_file_revalidate(file, 0)))
goto out;
@@ -44,8 +41,24 @@ static int unionfs_readdir(struct file *file, void *dirent,
filldir_t filldir)
odi = odf_ic_dir(file->f_dentry);
if (IS_ERR(odi)){
err = PTR_ERR(odi);
+ odi = NULL;
goto out;
}
+
+ /* check if cached dir does not exist */
+ if (!odi->dentry->d_inode || !odi->dentry->d_inode->i_size) {
+ err = odf_cache_dir(file->f_dentry, odi->dentry);
+ if (err)
+ goto out;
+
+ /* Reset file position, since an operation like rm *
+ * will rm the 1st entry, purge and then try to
+ * readdir again after the 1st entry's pos and will
+ * resulting in error reading dirents or skipping files
+ */
+ file->f_pos = 0;
+ }
+
dget(odi->dentry);
mntget(UNIONFS_SB(file->f_dentry->d_sb)->odf->mnt);
odf_file = dentry_open(odi->dentry,
@@ -56,7 +69,7 @@ static int unionfs_readdir(struct file *file, void *dirent,
filldir_t filldir)
odf_file = NULL;
goto out;
}
-
+
/* check EOF */
size = odi->dentry->d_inode->i_size;
if (file->f_pos >= size)
@@ -65,62 +78,9 @@ static int unionfs_readdir(struct file *file, void *dirent,
filldir_t filldir)
odf_file->f_pos = file->f_pos;
/* read the next dirent */
- oldfs = get_fs();
- set_fs(KERNEL_DS);
-
- err = odf_file->f_op->read(odf_file, (char*)&le32,
- sizeof(__le32), &odf_file->f_pos);
- if (err != sizeof(__le32)) {
- err = -EIO;
- goto out;
- }
- magic = le32_to_cpu(le32);
- /* check if we're reading at the correct offset */
- if (magic != ODF_DIRENT_MAGIC) {
- err = -EFAULT;
- goto out;
- }
-
- err = odf_file->f_op->read(odf_file, (char*)&le32,
- sizeof(__le32), &odf_file->f_pos);
- if (err != sizeof(__le32)) {
- err = -EIO;
- goto out;
- }
- namelen = le32_to_cpu(le32);
- if (namelen <= 0) {
- err = -EFAULT;
+ err = odf_read_dirent(odf_file, &name, &namelen, &ino, &d_type);
+ if (err)
goto out;
- }
-
- name = kmalloc(namelen, GFP_KERNEL);
- if (!name) {
- err = -ENOMEM;
- goto out;
- }
- err = odf_file->f_op->read(odf_file, (char*)name,
- namelen, &odf_file->f_pos);
- if (err != namelen) {
- err = -EIO;
- goto out;
- }
-
- err = odf_file->f_op->read(odf_file, (char*)&le64,
- sizeof(__le64), &odf_file->f_pos);
- if (err != sizeof(__le64)) {
- err = -EIO;
- goto out;
- }
- ino = le64_to_cpu(le64);
- err = odf_file->f_op->read(odf_file, (char*)&le32,
- sizeof(__le32), &odf_file->f_pos);
- if (err != sizeof(__le32)) {
- err = -EIO;
- goto out;
- }
- d_type = le32_to_cpu(le32);
-
- set_fs(oldfs);
/* filldir */
err = filldir(dirent, name, namelen, odf_file->f_pos, ino, d_type);
diff --git a/fs/unionfs/dirhelper.c b/fs/unionfs/dirhelper.c
index b668fdd..0123f8f 100644
--- a/fs/unionfs/dirhelper.c
+++ b/fs/unionfs/dirhelper.c
@@ -37,12 +37,15 @@ static int readdir_util_callback(void *dirent, const char
*name, int namelen,
{
int err = 0;
struct unionfs_rdutil_callback *buf = dirent;
- int whiteout = 0, magic = ODF_DIRENT_MAGIC;
+ int whiteout = 0;
struct filldir_node *found;
struct odf_dentry_info *odi = NULL;
- __le32 le32;
- __le64 le64;
- mm_segment_t oldfs;
+
+ /* FIXME: do we want to create(assign inode/nos) on reeddirs?
+ * or do we want to do it on interpose? (if we do it on
+ * interpose lsing a fresh union will not assign inos to dirs
+ */
+ int create_flag = d_type == DT_DIR ? ODF_LOOKUP_DIR : ODF_LOOKUP_FILE;
if (buf->mode == RD_CHECK_EMPTY)
buf->filldir_called = 1;
@@ -50,12 +53,15 @@ static int readdir_util_callback(void *dirent, const char
*name, int namelen,
buf->filldir_called++;
if (name[0] == '.' &&
- (namelen == 1 || (name[1] == '.' && namelen == 2)) &&
- buf->mode == RD_CHECK_EMPTY)
- goto out;
-
+ (namelen == 1 || (name[1] == '.' && namelen == 2))){
+ if (buf->mode == RD_CHECK_EMPTY)
+ goto out;
+ else
+ create_flag = 0;
+ }
+
/* check odf */
- odi = __odf_lookup(UNIONFS_D(buf->dir)->odf_info, name, namelen, 0, 0);
+ odi = __odf_lookup(UNIONFS_D(buf->dir)->odf_info, name, namelen,
create_flag, 0);
if (IS_ERR(odi)){
odi = NULL;
goto out;
@@ -78,38 +84,8 @@ static int readdir_util_callback(void *dirent, const char
*name, int namelen,
if (err || buf->mode != RD_CACHE_ODF || !buf->filp || whiteout)
goto out;
- oldfs = get_fs();
- set_fs(KERNEL_DS);
- le32 = cpu_to_le32(magic);
- err = buf->filp->f_op->write(buf->filp, (char*)&le32,
- sizeof(__le32), &buf->filp->f_pos);
- if (err != sizeof(__le32))
- goto out;
- le32 = cpu_to_le32(namelen);
- err = buf->filp->f_op->write(buf->filp, (char*)&le32,
- sizeof(__le32), &buf->filp->f_pos);
- if (err != sizeof(__le32))
- goto out;
- err = buf->filp->f_op->write(buf->filp, (char*)name,
- namelen, &buf->filp->f_pos);
- if (err != namelen)
- goto out;
- le64 = cpu_to_le64(ino);
- err = buf->filp->f_op->write(buf->filp, (char*)&le64,
- sizeof(__le64), &buf->filp->f_pos);
- if (err != sizeof(__le64))
- goto out;
- le32 = cpu_to_le32(d_type);
- err =buf->filp->f_op->write(buf->filp, (char*)&le32,
- sizeof(__le32), &buf->filp->f_pos);
- if (err != sizeof(__le32))
- goto out;
- set_fs(oldfs);
- err = 0;
+ err = odf_write_dirent(buf->filp, name, namelen, ino, d_type);
out:
- if (err > 0)
- err = -EIO;
-
odf_put_info(odi);
buf->err = err;
return err;
@@ -228,7 +204,7 @@ int odf_cache_dir(struct dentry *d_upper, struct dentry
*d_odf)
struct iattr attr;
sb = d_upper->d_sb;
-
+
unionfs_read_lock(sb);
BUG_ON(!S_ISDIR(d_upper->d_inode->i_mode));
@@ -239,16 +215,17 @@ int odf_cache_dir(struct dentry *d_upper, struct dentry
*d_odf)
i_odf = d_odf->d_inode;
/* compare mtimes, do not proceed if equal */
- if (i_odf && timespec_equal(&i_odf->i_mtime,
+ if (i_odf && i_odf->i_size) {
+ if( timespec_equal(&i_odf->i_mtime,
&d_upper->d_inode->i_mtime))
- goto out;
-
+ goto out;
+
+ }
dget(d_odf);
mntget(UNIONFS_SB(sb)->odf->mnt);
/* force truncate if file exists */
if (i_odf) {
- truncate_inode_pages(i_odf->i_mapping, 0);
attr.ia_size = 0;
attr.ia_valid = ATTR_SIZE | ATTR_FORCE;
err = notify_change(d_odf, &attr);
diff --git a/fs/unionfs/lookup.c b/fs/unionfs/lookup.c
index cbdf976..4716e62 100644
--- a/fs/unionfs/lookup.c
+++ b/fs/unionfs/lookup.c
@@ -35,8 +35,6 @@ struct dentry *unionfs_lookup_backend(struct dentry *dentry,
struct nameidata *n
int locked_parent = 0;
int locked_child = 0;
int allocated_new_info = 0;
-
- int opaque;
const char *name;
int namelen;
diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c
index 45cc965..9cc90d7 100644
--- a/fs/unionfs/odf.c
+++ b/fs/unionfs/odf.c
@@ -315,6 +315,10 @@ out:
return odi;
}
+/*
+ * Returns odf_dentry_info pointing to the location in the odf
+ * for the given directory's cached contents
+ */
struct odf_dentry_info *odf_ic_dir(struct dentry *dir)
{
struct odf_dentry_info *odi_dir, *odis[4], *odi_ic, *odi_ret = NULL;
@@ -374,6 +378,158 @@ out:
return ERR_PTR(err);
return odi_ret;
}
+/*
+ * Write a dirent to the given file
+ * FIXME: Instead of a file we should give the position
+ * in the odf
+ */
+int odf_write_dirent(struct file *filp, const char *name, int namelen,
+ u64 ino, unsigned int d_type)
+{
+ int err = 0;
+ __le32 le32;
+ __le64 le64;
+ mm_segment_t oldfs;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ le32 = cpu_to_le32(ODF_DIRENT_MAGIC);
+ err = filp->f_op->write(filp, (char*)&le32,
+ sizeof(__le32), &filp->f_pos);
+ if (err != sizeof(__le32))
+ goto out;
+
+ le32 = cpu_to_le32(namelen);
+ err = filp->f_op->write(filp, (char*)&le32,
+ sizeof(__le32), &filp->f_pos);
+ if (err != sizeof(__le32))
+ goto out;
+
+ err = filp->f_op->write(filp, (char*)name,
+ namelen, &filp->f_pos);
+ if (err != namelen)
+ goto out;
+
+ le64 = cpu_to_le64(ino);
+ err = filp->f_op->write(filp, (char*)&le64,
+ sizeof(__le64), &filp->f_pos);
+ if (err != sizeof(__le64))
+ goto out;
+
+ le32 = cpu_to_le32(d_type);
+ err =filp->f_op->write(filp, (char*)&le32,
+ sizeof(__le32), &filp->f_pos);
+ if (err != sizeof(__le32))
+ goto out;
+
+ err = 0;
+out:
+ set_fs(oldfs);
+ if (err > 0)
+ err = -EIO;
+
+ return err;
+}
+/*
+ * Reads the next dirent from the given file
+ */
+int odf_read_dirent(struct file *filp, char **name, int *namelen,
+ u64 *ino, unsigned int *d_type)
+{
+ int err = 0;
+ mm_segment_t oldfs;
+ __le32 le32;
+ __le64 le64;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ err = filp->f_op->read(filp, (char*)&le32,
+ sizeof(__le32), &filp->f_pos);
+ if (err != sizeof(__le32)) {
+ err = -EIO;
+ goto out;
+ }
+
+ /* check if we're reading at the correct offset */
+ if (le32_to_cpu(le32) != ODF_DIRENT_MAGIC) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ err = filp->f_op->read(filp, (char*)&le32,
+ sizeof(__le32), &filp->f_pos);
+ if (err != sizeof(__le32)) {
+ err = -EIO;
+ goto out;
+ }
+ *namelen = le32_to_cpu(le32);
+ if (*namelen <= 0) {
+ err = -EFAULT;
+ goto out;
+ }
+
+ *name = kmalloc(*namelen, GFP_KERNEL);
+ if (!(*name)) {
+ err = -ENOMEM;
+ goto out;
+ }
+ err = filp->f_op->read(filp, (char*)(*name),
+ *namelen, &filp->f_pos);
+ if (err != *namelen) {
+ err = -EIO;
+ goto out;
+ }
+
+ err = filp->f_op->read(filp, (char*)&le64,
+ sizeof(__le64), &filp->f_pos);
+ if (err != sizeof(__le64)) {
+ err = -EIO;
+ goto out;
+ }
+ *ino = le64_to_cpu(le64);
+ err = filp->f_op->read(filp, (char*)&le32,
+ sizeof(__le32), &filp->f_pos);
+ if (err != sizeof(__le32)) {
+ err = -EIO;
+ goto out;
+ }
+ *d_type = le32_to_cpu(le32);
+
+ err = 0;
+out:
+ set_fs(oldfs);
+ return err;
+}
+
+/*
+ * For now this just truncate the dir's content file
+ */
+int odf_purge_dir_cache(struct dentry *dentry)
+{
+ int err = 0;
+ struct iattr attr;
+ struct odf_dentry_info *odi = NULL;
+
+ odi = odf_ic_dir(dentry);
+ if (IS_ERR(odi)){
+ err = PTR_ERR(odi);
+ odi = NULL;
+ goto out;
+ }
+
+ /* truncate */
+ if (dentry->d_inode) {
+ attr.ia_size = 0;
+ attr.ia_valid = ATTR_SIZE | ATTR_FORCE;
+ err = notify_change(odi->dentry, &attr);
+ }
+out:
+ odf_put_info(odi);
+ return err;
+}
+
/*
* Unlinks the file from odf if exist, creates a new file with
@@ -452,11 +608,9 @@ int odf_remove(struct dentry *dentry, int flags)
/* remove */
if (S_ISDIR(odi->dentry->d_inode->i_mode))
err = odf_reclaim(odi->dentry);
- else {
+ else
err = vfs_unlink(odi->dentry->d_parent->d_inode, odi->dentry);
- if (!err)
-;// odi->dentry = NULL; /*so we dont dput*/
- }
+
if (err)
goto out_unlock;
diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h
index 5299a59..24e1f4b 100644
--- a/fs/unionfs/odf.h
+++ b/fs/unionfs/odf.h
@@ -44,13 +44,18 @@ int odf_putoptions(struct super_block* sb_union, struct
unionfs_dentry_info *hid
/* lookup */
int odf_lookup(struct dentry *parent, struct dentry *dentry, int flags);
struct odf_dentry_info *__odf_lookup(struct odf_dentry_info *parent, const
char *name, int len, int flags, struct odf_dentry_info *old_odi);
-struct odf_dentry_info *odf_ic_dir(struct dentry *dir);
struct odf_dentry_info *odf_getpath(char *path);
struct odf_dentry_info *odf_fill_info(struct odf_dentry_info *odi, struct
dentry *odf_dentry);
struct odf_dentry_info *odf_alloc_info(struct dentry *odf_dentry);
void odf_put_info(struct odf_dentry_info *odi);
+/* dirents & dir cache */
+struct odf_dentry_info *odf_ic_dir(struct dentry *dir);
+int odf_write_dirent(struct file *filp, const char *name, int namelen, u64
ino, unsigned int d_type);
+int odf_read_dirent(struct file *filp, char **name, int *namelen, u64 *ino,
unsigned int *d_type);
+int odf_purge_dir_cache(struct dentry *dentry);
+
int odf_rename(struct dentry *old_dentry, struct dentry *new_dentry);
/* unlink */
diff --git a/fs/unionfs/unlink.c b/fs/unionfs/unlink.c
index b46fdba..7305fd5 100644
--- a/fs/unionfs/unlink.c
+++ b/fs/unionfs/unlink.c
@@ -66,6 +66,7 @@ static int unionfs_do_unlink(struct inode *dir, struct dentry
*dentry)
* the mtime of that branch has not changed, so the
* mtime of the upper file is not updated
*/
+ odf_purge_dir_cache(dentry->d_parent);
attr.ia_mtime = current_kernel_time();
attr.ia_valid = ATTR_MTIME | ATTR_MTIME_SET | ATTR_FORCE;
err = notify_change(dentry->d_parent, &attr);
@@ -148,7 +149,7 @@ static int unionfs_do_rmdir(struct inode *dir, struct
dentry *dentry)
if (err || dbopaque(dentry) != 1) {
if (err == -EIO)
printk(KERN_WARNING
- "unionfs_unlink: IO error unlinking from branch
%d\n",
+ "unionfs_rmdir: IO error removing from branch
%d\n",
bindex);
err = odf_create_wh(dentry);
if (err)
@@ -158,6 +159,7 @@ static int unionfs_do_rmdir(struct inode *dir, struct
dentry *dentry)
* the mtime of that branch has not changed, so the
* mtime of the upper file is not updated
*/
+ odf_purge_dir_cache(dentry->d_parent);
attr.ia_mtime = current_kernel_time();
attr.ia_valid = ATTR_MTIME | ATTR_MTIME_SET | ATTR_FORCE;
err = notify_change(dentry->d_parent, &attr);
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs