commit c0367d499b36158ccf7e2a007a08f3e8a70dd0da
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date: Fri Apr 6 14:42:49 2007 -0400
holding off hardlinks until jeffs path_lookup modifications, removed all
nasty hardlink code
diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c
index 82571d2..ce67381 100644
--- a/fs/unionfs/copyup.c
+++ b/fs/unionfs/copyup.c
@@ -435,8 +435,7 @@ static int copyup_named_dentry(struct inode *dir, struct
dentry *dentry,
if (!d_deleted(dentry))
unionfs_reinterpose(dentry);
- err = odf_copyup_link(sb, old_hidden_dentry, new_hidden_dentry,
- old_bindex, new_bindex);
+ err = odf_copyup_link(sb, old_hidden_dentry, new_hidden_dentry,
old_bindex, new_bindex);
goto out_unlock;
/****/
diff --git a/fs/unionfs/fanout.h b/fs/unionfs/fanout.h
index a570c19..43c73e1 100644
--- a/fs/unionfs/fanout.h
+++ b/fs/unionfs/fanout.h
@@ -55,6 +55,16 @@ static inline void new_branch_id(struct super_block *sb, int
index)
set_branch_id(sb, index, ++UNIONFS_SB(sb)->high_branch_id);
}
+static inline int branch_id_to_idx(struct super_block *sb, int branch_id)
+{
+ int i;
+ for (i = 0; i < sbmax(sb); i++) {
+ if (UNIONFS_SB(sb)->data[i].branch_id == branch_id)
+ return i;
+ }
+ return -1;
+}
+
/* File to lower file. */
static inline struct file *unionfs_lower_file(const struct file *f)
{
diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c
index 01df833..2b8db07 100644
--- a/fs/unionfs/odf.c
+++ b/fs/unionfs/odf.c
@@ -377,6 +377,129 @@ out:
return err;
}
+/* Adds a dirent to the inode's hardlink info file if it doesn't exist.
+ * If the file was empty, fills in the copyup info (branch and inum) with 0's
+ * If the file was not empty returns the odf dentry of one of the links for the
+ * odf to link to it. (We might need to store the odf inum parent as well)
+ */
+struct dentry *__link_add_dirent(struct file *link_file, struct dentry *dentry)
+{
+ int err = 0, len;
+ char *name = NULL;
+ loff_t size;
+ u64 ino;
+ mm_segment_t oldfs;
+ __le64 le64;
+ __le32 le32;
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ size = i_size_read(link_file->f_dentry->d_inode);
+
+
+ if (size == 0) {
+ /* file is new, fill in copyup info with 0's */
+ link_file->f_pos = 0;
+ le32 = 0;
+ err = link_file->f_op->write(link_file, (char*)&le32,
+ sizeof(__le32), &link_file->f_pos);
+ if (err != sizeof(__le32)){
+ err = -EIO;
+ goto out;
+ }
+
+ le64 = 0;
+ err = link_file->f_op->write(link_file, (char*)&le64,
+ sizeof(__le64), &link_file->f_pos);
+ if (err != sizeof(__le64)){
+ err = -EIO;
+ goto out;
+ }
+ }
+ else {
+
+ /* check if our dirent is already in the file */
+ link_file->f_pos = sizeof(__le32) + sizeof(__le64);
+
+ while (link_file->f_pos < size) {
+
+ err = link_file->f_op->read(link_file, (char*)&le32,
+ sizeof(__le32), &link_file->f_pos);
+ if (err != sizeof(__le32)){
+ err = -EIO;
+ goto out;
+ }
+ len = le32_to_cpu(le32);
+
+ kfree(name);
+ name = kmalloc(len, GFP_KERNEL);
+ if (!name) {
+ err = -ENOMEM;
+ goto out;
+ }
+ err = link_file->f_op->read(link_file, name,
+ len, &link_file->f_pos);
+ if (err != sizeof(len)){
+ err = -EIO;
+ goto out;
+ }
+
+ err = link_file->f_op->read(link_file, (char*)&le64,
+ sizeof(__le64), &link_file->f_pos);
+ if (err != sizeof(__le64)){
+ err = -EIO;
+ goto out;
+ }
+ ino = le64_to_cpu(le64);
+
+ /* check if this is our dirent */
+ if (ino == dentry->d_parent->d_inode->i_ino &&
+ dentry->d_name.len == len &&
+ !strncmp(dentry->d_name.name, name, len)){
+ err = 0;
+ goto out;
+ }
+ }
+
+ }
+
+ /* write the dirent in the file */
+ le32 = cpu_to_le32(dentry->d_name.len);
+ err = link_file->f_op->write(link_file, (char*)&le32,
+ sizeof(__le32), &link_file->f_pos);
+ if (err != sizeof(__le32)){
+ err = -EIO;
+ goto out;
+ }
+
+ err = link_file->f_op->write(link_file, dentry->d_name.name,
+ dentry->d_name.len, &link_file->f_pos);
+ if (err != dentry->d_name.len){
+ err = -EIO;
+ goto out;
+ }
+
+ le64 = cpu_to_le64(dentry->d_parent->d_inode->i_ino);
+ err = link_file->f_op->write(link_file, (char*)&le64,
+ sizeof(__le64), &link_file->f_pos);
+ if (err != sizeof(__le64)){
+ err = -EIO;
+ goto out;
+ }
+ err = 0;
+out:
+ set_fs(oldfs);
+ kfree(name);
+ if (err)
+ return ERR_PTR(err);
+ return NULL;
+}
+
+/*
+ * Update the original inode's copyup info in the link file, and then for each
entry
+ * in the file, create parent hierarchies in the copied up branch and link to
the new_dentry
+ */
int odf_copyup_link(struct super_block *sb, struct dentry *old_dentry, struct
dentry *new_dentry,
int old_branch, int new_branch)
{
@@ -386,11 +509,11 @@ int odf_copyup_link(struct super_block *sb, struct dentry
*old_dentry, struct de
struct file *link_file = NULL;
mm_segment_t oldfs;
int err = 0;
- u64 ino;
__le64 le64;
__le32 le32;
BUG_ON(S_ISDIR(old_dentry->d_inode->i_mode));
+ /* do nothing if this has no links? or should we actually check if it
has a link file? */
if (old_dentry->d_inode->i_nlink <= 1)
return 0;
@@ -430,73 +553,38 @@ int odf_copyup_link(struct super_block *sb, struct dentry
*old_dentry, struct de
/* get the odf ino first */
link_file->f_pos = 0;
- err = link_file->f_op->read(link_file, (char*)&le64,
- sizeof(__le64), &link_file->f_pos);
- if (err < 0)
- goto out;
- BUG_ON(err != sizeof(__le64));
- ino = le64_to_cpu(le64);
/* write destination branch id*/
le32 = cpu_to_le32(branch_id(sb, new_branch));
err = link_file->f_op->write(link_file, (char*)&le32,
sizeof(__le32), &link_file->f_pos);
- BUG_ON(err != sizeof(__le32));
+ if (err != sizeof(__le32)) {
+ err = -EIO;
+ set_fs(oldfs);
+ goto out;
+ }
/* write destination lower inode ino */
le64 = cpu_to_le64(new_dentry->d_inode->i_ino);
err = link_file->f_op->write(link_file, (char*)&le64,
sizeof(__le64), &link_file->f_pos);
- BUG_ON(err != sizeof(__le64));
+ if (err != sizeof(__le64)) {
+ err = -EIO;
+ set_fs(oldfs);
+ goto out;
+ }
+ set_fs(oldfs);
+ err = 0;
odf_put_info(links);
links = NULL;
filp_close(link_file, NULL);
link_file = NULL;
- /* now update the destination link info file */
- uuid = odf_get_branch_uuid(osi, new_branch);
- sprintf(name,"%x%x%x%x", *(unsigned int *) uuid,
- *(unsigned int *) uuid + 4,
- *(unsigned int *) uuid + 8,
- *(unsigned int *) uuid + 12);
- links = odf_ic_dentry(osi, new_dentry->d_inode->i_ino, name,
strlen(name));
- if (IS_ERR(links)) {
- err = PTR_ERR(links);
- links = NULL;
- goto out;
- }
-
- /* open the file */
- dget(links->dentry);
- mntget(osi->mnt);
- link_file = dentry_open(links->dentry, osi->mnt, O_RDWR);
- if (IS_ERR(link_file)) {
- err = PTR_ERR(link_file);
- link_file = NULL;
- dput(links->dentry);
- mntput(osi->mnt);
- goto out;
- }
-
- link_file->f_pos = 0;
- le64 = cpu_to_le64(ino);
- err = link_file->f_op->write(link_file, (char*)&le64,
- sizeof(__le64), &link_file->f_pos);
- BUG_ON(err != sizeof(__le64));
-
- le32 = 0;
- err = link_file->f_op->write(link_file, (char*)&le32,
- sizeof(__le32), &link_file->f_pos);
- BUG_ON(err != sizeof(__le32));
-
- le64 = 0;
- err = link_file->f_op->write(link_file, (char*)&le64,
- sizeof(__le64), &link_file->f_pos);
- BUG_ON(err != sizeof(__le64));
+ /* XXX: create parent hierarchies in new_branch for all other links
+ * and link to the new_dentry
+ */
- err = 0;
- set_fs(oldfs);
out:
if (link_file)
filp_close(link_file, NULL);
@@ -505,41 +593,150 @@ out:
return err;
}
-int __check_link_copyup(struct file *link_file)
+/* Checks the link file if the hard link was copied up, and if yes tries to
link to the
+ * copied up inode in the copied up branch.
+ */
+int __check_link_copyup(struct file *link_file, struct dentry *dentry, int
branch_src)
{
- int err, bid;
+ struct dentry *lower_dentry;
+ int err, bid = -1;
+ int branch_dst, dst_ro = 0;
__le64 le64;
__le32 le32;
- u64 ino, cp_ino;
+ u64 ino = 0;
mm_segment_t oldfs;
oldfs = get_fs();
set_fs(KERNEL_DS);
link_file->f_pos = 0;
+ err = link_file->f_op->read(link_file, (char*)&le32,
+ sizeof(__le32), &link_file->f_pos);
+ if (err == sizeof(__le32))
+ bid = le32_to_cpu(le32);
+ else if (err == 0)
+ goto skip;
+ else {
+ err = -EIO;
+ goto out_fs;
+ }
+
err = link_file->f_op->read(link_file, (char*)&le64,
sizeof(__le64), &link_file->f_pos);
- if (err != sizeof(__le64))
- ino = 0;
- else
+ if (err == sizeof(__le64))
ino = le64_to_cpu(le64);
+ else if (err != 0) {
+ err = -EIO;
+ goto out_fs;
+ }
+skip:
+ set_fs(oldfs);
+ err = 0;
- err = link_file->f_op->read(link_file, (char*)&le32,
+ /* check if there was no coypup */
+ if (!ino)
+ goto out;
+
+ /* XXX: the copied up file might have been copied up again, so we
+ * need to check that too in order to find the final dst branch
+ */
+
+ /* get the branch numbers for cpd up branch and src branch */
+ BUG_ON(bid < 0);
+ branch_dst = branch_id_to_idx(dentry->d_sb, bid);
+ if (branch_dst >= 0)
+ dst_ro = is_robranch_super(dentry->d_sb, branch_dst);
+
+ odf_lock(UNIONFS_D(dentry->d_parent)->odf_info);
+
+ /* case 0:
+ * - dest branch id has changed because of remounts
+ * - do not copyup, remove copyup info from link info file
+ */
+ if (branch_dst == -1) {
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ link_file->f_pos = 0;
+ le32 = 0;
+ err = link_file->f_op->write(link_file, (char*)&le32,
sizeof(__le32), &link_file->f_pos);
- if (err != sizeof(__le32))
- bid = -1;
- else
- bid = le32_to_cpu(le32);
+ if (err != sizeof(__le32)){
+ set_fs(oldfs);
+ err = -EIO;
+ goto out_unlock;
+ }
- err = link_file->f_op->read(link_file, (char*)&le64,
+ le64 = 0;
+ err = link_file->f_op->write(link_file, (char*)&le64,
sizeof(__le64), &link_file->f_pos);
- if (err != sizeof(__le64))
- cp_ino = 0;
- else
- cp_ino = le64_to_cpu(le64);
+ if (err != sizeof(__le64)){
+ set_fs(oldfs);
+ err = -EIO;
+ goto out_unlock;
+ }
+
+ set_fs(oldfs);
+ err = 0;
+ }
+
+ /* case 1:
+ * - Normal case, dst to the left of src and not ro
+ * - create parent hierarchy and link in the dst branch
+ */
+ else if (branch_dst < branch_src && !dst_ro) {
+
+ /* create parent hierarchy, then link */
+ BUG_ON(unionfs_lower_dentry_idx(dentry, branch_dst));
+
+ verify_locked(dentry->d_parent);
+ unionfs_unlock_dentry(dentry->d_parent); /*XXX: this is VERY
nasty */
+ lower_dentry = create_parents(dentry->d_parent->d_inode,
+ dentry, branch_dst);
+ unionfs_lock_dentry(dentry->d_parent);
+
+ if (!lower_dentry || IS_ERR(lower_dentry)) {
+ if (IS_ERR(lower_dentry))
+ err = PTR_ERR(lower_dentry);
+ goto out_unlock;
+ }
+ /* now link */
+ }
+
+ /* case 2:
+ * - dst is the same as src branch and not ro
+ * - unlink old file and straight link with copied up
+ */
+ else if (branch_dst == branch_src && !dst_ro) {
+ ;
+ }
+ /* case 3:
+ * - dst to the right of src, because of moving branches, so if the
file was already
+ * copied up before the branch manip. it would now be hidden by the
old non-cpied up
+ * version of the file.
+ * - Do nothing!
+ */
+ else if (branch_dst < branch_src) {
+ ;
+ }
+
+ /* case 4:
+ * - dst branch is ro
+ * - copyup again!
+ */
+ else if (dst_ro) {
+ ;
+ }
+
+
+out_unlock:
+ odf_unlock(UNIONFS_D(dentry->d_parent)->odf_info);
+ goto out;
+out_fs:
set_fs(oldfs);
- return 0;
+out:
+ return err;
}
/*
@@ -566,9 +763,6 @@ int odf_lookup(struct dentry *parent, struct dentry
*dentry, int flags)
struct file *link_file = NULL;
char *name, *uuid;
int bstart, err = 0;
- __le64 le64;
- u64 ino = 0;
- mm_segment_t oldfs;
/* this might be called before interpose */
if (dbstart(dentry) == dbend(dentry) && dbstart(dentry) == 0) {
@@ -615,29 +809,14 @@ int odf_lookup(struct dentry *parent, struct dentry
*dentry, int flags)
mntput(osi->mnt);
goto out;
}
-
- oldfs = get_fs();
- set_fs(KERNEL_DS);
- link_file->f_pos = 0;
- err = link_file->f_op->read(link_file, (char*)&le64,
- sizeof(__le64), &link_file->f_pos);
- set_fs(oldfs);
- if (err < 0)
- goto out;
- if(err == sizeof(__le64))
- ino = le64_to_cpu(le64);
- else if (err == 0)
- ino = 0;
- else {
- err = -EIO;
- goto out;
- }
- err = 0;
/* check if link was copied up and act appropriately */
- if (ino)
- __check_link_copyup(link_file);
+
+ /* XXX: Leave this out until Jeff's modifications to
path_lookup
+ __check_link_copyup(link_file, dentry, bstart);
+ __link_add_dirent(link_file, dentry);
flags |= ODF_LOOKUP_LINK;
+ */
}
UNIONFS_D(dentry)->odf_info = __odf_lookup(
@@ -647,7 +826,7 @@ int odf_lookup(struct dentry *parent, struct dentry
*dentry, int flags)
dentry->d_name.len,
flags,
UNIONFS_D(dentry)->odf_info,
- ino);
+ NULL);
if (IS_ERR(UNIONFS_D(dentry)->odf_info)){
err = PTR_ERR(UNIONFS_D(dentry)->odf_info);
UNIONFS_D(dentry)->odf_info = NULL;
@@ -656,19 +835,6 @@ int odf_lookup(struct dentry *parent, struct dentry
*dentry, int flags)
else if (UNIONFS_D(dentry)->odf_info == NULL)
goto out;
- /* if link file did not have the ino, write it */
- if (link_file && !ino) {
- oldfs = get_fs();
- set_fs(KERNEL_DS);
- link_file->f_pos = 0;
- le64 =
cpu_to_le64(UNIONFS_D(dentry)->odf_info->dentry->d_inode->i_ino);
- err = link_file->f_op->write(link_file, (char*)&le64,
- sizeof(__le64), &link_file->f_pos);
- set_fs(oldfs); /* XXX check errors, and for -ENOSPC */
- BUG_ON(err != sizeof(__le64));
- err = 0;
- }
-
out:
odf_put_info(links);
if (link_file)
@@ -679,9 +845,9 @@ out:
struct odf_dentry_info *__odf_lookup(struct odf_sb_info *osi,
struct odf_dentry_info *parent,
const char *name, int len, int flags,
- struct odf_dentry_info *old_odi, u64 ino)
+ struct odf_dentry_info *old_odi,
+ struct dentry *link)
{
- struct inode *i;
struct dentry *odf_dentry;
struct odf_dentry_info *odi = old_odi;
struct inode *odf_i_dir = parent->dentry->d_inode;
@@ -733,12 +899,9 @@ retry:
else if (cleaned)
odf_lock(osi->odi_ic);
- if (ino && (flags & (ODF_LOOKUP_FILE | ODF_LOOKUP_LINK))) {
- /* if link ino was set in the file, link to that */
- i = iget(odf_dentry->d_sb, ino);
- BUG_ON(i == NULL || IS_ERR(i)); /*XXX: check for these
*/
- BUG_ON(S_ISDIR(i->i_mode)); /* and also make sure the
inode */
- d_add(odf_dentry, i); /* is not a new inode */
+ if (link && (flags & (ODF_LOOKUP_FILE | ODF_LOOKUP_LINK))) {
+ /* link to the given dentry */
+ vfs_link(link, parent->dentry->d_inode, odf_dentry);
}
else if (flags & ODF_LOOKUP_FILE || flags & ODF_LOOKUP_WH) {
current->fsuid = 0;
@@ -795,20 +958,8 @@ retry:
__odf_set_wh(odf_dentry->d_inode,whiteout);
}
else {
- /* handle hardlinks, 3 cases:
- * 1) ino in linkfile and odf_dentry are the same: all ok
- * 2) ino in linkfile is not set: set it to odf_dentry's ino
- * 3) ino in linkfile and odf_dentry are different: bad
- */
-
- /* case 3: unlink odf file and link to given ino */
- if ((flags & ODF_LOOKUP_LINK) && ino && ino !=
odf_dentry->d_inode->i_ino) {
- vfs_unlink(odf_dentry->d_parent->d_inode, odf_dentry);
- i = iget(odf_dentry->d_sb, ino);
- BUG_ON(i == NULL || IS_ERR(i)); /*XXX: check if i is
the one */
- BUG_ON(S_ISDIR(i->i_mode));
- d_add(odf_dentry, i);
- }
+ /* hardlinks, check if link inode is same as odf_dentry inode,
+ and if not, link them */
}
odi = odf_fill_info(old_odi, osi, odf_dentry);
@@ -1192,17 +1343,14 @@ int odf_get_opaque(struct super_block *sb, struct
dentry *dentry)
if (opaque == -1)
return -1;
- /* now check all branches for the branch id */
- for (i = 0; i < sbmax(sb); i++) {
- if (branch_id(sb, i) == opaque)
- return i;
- }
+ i = branch_id_to_idx(sb, opaque);
/* if this is reached then the opaque branch was deleted, so dentry
* can no longer be considered opaque
*/
- odf_set_opaque(dentry, -1);
- return -1;
+ if (i == -1)
+ odf_set_opaque(dentry, -1);
+ return i;
}
int __odf_is_opaque(struct inode *i)
@@ -1711,19 +1859,19 @@ void __odf_cleanup(void *args)
if (cl->force) {
cl->force = 0;
cleanup = ODF_CLEAN_CACHE;
- printk("unionfs cleanup thread: forced cleanup\n");
+// printk("unionfs cleanup thread: forced cleanup\n");
}
else if (stat.f_bavail * 100 < stat.f_blocks * (100 -
cl->attr->thresh_b->val)) {
cleanup = ODF_CLEAN_BLOCKS;
size = stat.f_blocks * (100 - cl->attr->thresh_b->val) -
(stat.f_bavail * 100);
- printk("unionfs cleanup thread: free blocks below critical
size\n");
+// printk("unionfs cleanup thread: free blocks below critical
size\n");
}
else if (stat.f_ffree * 100 < stat.f_files * (100 -
cl->attr->thresh_i->val)) {
cleanup = ODF_CLEAN_INODES;
size = stat.f_files * (100 - cl->attr->thresh_i->val) -
(stat.f_ffree * 100);
- printk("unionfs cleanup thread: free inodes below critical
size\n");
+// printk("unionfs cleanup thread: free inodes below critical
size\n");
}
if (cleanup)
err = odf_cleanup(cl->odf, cleanup, size);
diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h
index ed0bba5..8126cc5 100644
--- a/fs/unionfs/odf.h
+++ b/fs/unionfs/odf.h
@@ -67,12 +67,13 @@ static inline char *odf_get_branch_uuid(struct odf_sb_info
*odf, int branch)
/* lookup */
int odf_lookup(struct dentry *parent, struct dentry *dentry, int flags);
struct odf_dentry_info *__odf_lookup(struct odf_sb_info *osi, struct
odf_dentry_info *parent,
- const char *name, int len, int flags, struct odf_dentry_info
*old_odi, u64 ino);
+ const char *name, int len, int flags, struct odf_dentry_info
*old_odi,
+ struct dentry *link);
static inline struct odf_dentry_info *odf_lookup_name(struct odf_sb_info *osi,
struct odf_dentry_info *parent, const char *name, int len,
int flags, struct odf_dentry_info *old_odi)
{
- return __odf_lookup(osi, parent, name, len, flags, old_odi, 0);
+ return __odf_lookup(osi, parent, name, len, flags, old_odi, NULL);
}
struct odf_dentry_info *odf_getpath(struct dentry *d_odf, struct odf_sb_info
*osi, const char *name);
struct odf_dentry_info *odf_fill_info(struct odf_dentry_info *odi,
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs