commit 1ea2386bbaf70b3f6481dcd48f3f4026818b2017
Author: Yiannis Pericleous <[EMAIL PROTECTED]>
Date: Thu Apr 5 06:25:39 2007 -0400
save copyup dst and inode on copyup of hardlinks
diff --git a/fs/unionfs/copyup.c b/fs/unionfs/copyup.c
index 331c6ee..82571d2 100644
--- a/fs/unionfs/copyup.c
+++ b/fs/unionfs/copyup.c
@@ -435,6 +435,9 @@ 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);
+
goto out_unlock;
/****/
diff --git a/fs/unionfs/odf.c b/fs/unionfs/odf.c
index fb81d03..c53ed13 100644
--- a/fs/unionfs/odf.c
+++ b/fs/unionfs/odf.c
@@ -376,6 +376,172 @@ out_unlock:
out:
return err;
}
+
+int odf_copyup_link(struct super_block *sb, struct dentry *old_dentry, struct
dentry *new_dentry,
+ int old_branch, int new_branch)
+{
+ char *name, *uuid;
+ struct odf_dentry_info *links = NULL;
+ struct odf_sb_info *osi = UNIONFS_SB(sb)->odf;
+ 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));
+ if (old_dentry->d_inode->i_nlink <= 1)
+ return 0;
+
+ name = kmalloc(UUID_LEN * 2 + 1,GFP_KERNEL);
+ if (!name) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ /* update the old link info file with the copyup info */
+ uuid = odf_get_branch_uuid(osi, old_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, old_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;
+ }
+
+ oldfs = get_fs();
+ set_fs(KERNEL_DS);
+
+ /* 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));
+
+ /* 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));
+
+ 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));
+
+ err = 0;
+ set_fs(oldfs);
+out:
+ if (link_file)
+ filp_close(link_file, NULL);
+ odf_put_info(links);
+ kfree(name);
+ return err;
+}
+
+int __check_link_copyup(struct file *link_file)
+{
+ int err, bid;
+ __le64 le64;
+ __le32 le32;
+ u64 ino, cp_ino;
+ 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*)&le64,
+ sizeof(__le64), &link_file->f_pos);
+ if (err != sizeof(__le64))
+ ino = 0;
+ else
+ ino = le64_to_cpu(le64);
+
+ err = link_file->f_op->read(link_file, (char*)&le32,
+ sizeof(__le32), &link_file->f_pos);
+ if (err != sizeof(__le32))
+ bid = -1;
+ else
+ bid = le32_to_cpu(le32);
+
+ err = link_file->f_op->read(link_file, (char*)&le64,
+ sizeof(__le64), &link_file->f_pos);
+ if (err != sizeof(__le64))
+ cp_ino = 0;
+ else
+ cp_ino = le64_to_cpu(le64);
+
+ set_fs(oldfs);
+ return 0;
+}
+
/*
* Lookup an entry in the odf, and create it if necessary
* Returns a an odf_dentry_info containing whiteout and
@@ -446,7 +612,8 @@ int odf_lookup(struct dentry *parent, struct dentry
*dentry, int flags)
goto out;
}
- /* check if link was copied up and act approprietely */
+ /* check if link was copied up and act appropriately */
+ __check_link_copyup(link_file);
}
UNIONFS_D(dentry)->odf_info = __odf_lookup(
@@ -475,7 +642,7 @@ struct odf_dentry_info *__odf_lookup(struct odf_sb_info
*osi,
struct file *link_file)
{
struct inode *i;
- struct dentry *odf_dentry, *d;
+ struct dentry *odf_dentry;
struct odf_dentry_info *odi = old_odi;
struct inode *odf_i_dir = parent->dentry->d_inode;
int opaque, whiteout, err = 0, cleaned = 0;
@@ -496,7 +663,7 @@ struct odf_dentry_info *__odf_lookup(struct odf_sb_info
*osi,
err = link_file->f_op->read(link_file, (char*)&le64,
sizeof(__le64), &link_file->f_pos);
set_fs(oldfs);
- if (err<0) {
+ if (err < 0) {
odf_put_info(old_odi);
odi = ERR_PTR(err);
goto out;
@@ -551,10 +718,9 @@ retry:
if (link_file && ino && (flags & ODF_LOOKUP_FILE)) {
/* if link ino was set in the file, link to that */
i = iget(odf_dentry->d_sb, ino);
- d = d_splice_alias(i, odf_dentry);
- iput(i);
- if (IS_ERR(d))
- err = PTR_ERR(d);
+ 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 */
}
else if (flags & ODF_LOOKUP_FILE || flags & ODF_LOOKUP_WH) {
current->fsuid = 0;
@@ -621,16 +787,12 @@ retry:
if (link_file && 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);
- d = d_splice_alias(i, odf_dentry);
- iput(i);
- if (IS_ERR(d)) {
- odi = (struct odf_dentry_info *)d;
- odf_put_info(old_odi);
- goto out;
- }
+ 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);
}
}
-
+
/* if link file did not have the ino, write it */
if (link_file && !ino) {
oldfs = get_fs();
@@ -643,7 +805,7 @@ retry:
BUG_ON(err != sizeof(__le64));
err = 0;
}
-
+
odi = odf_fill_info(old_odi, osi, odf_dentry);
dput(odf_dentry); /* since we dget in fill_info */
out:
@@ -877,7 +1039,6 @@ out:
return err;
}
-
/*
* Unlinks the file from odf if exist, creates a new file with
* the same name and sets its whiteout flag
diff --git a/fs/unionfs/odf.h b/fs/unionfs/odf.h
index 3c2d918..51acbb0 100644
--- a/fs/unionfs/odf.h
+++ b/fs/unionfs/odf.h
@@ -92,6 +92,9 @@ int odf_cache_dir(struct dentry *d_upper, struct dentry
*d_odf, struct timespec
int odf_rename(struct dentry *old_dentry, struct dentry *new_dentry);
int odf_link(struct dentry *old_dentry, struct dentry *new_dentry);
+int odf_copyup_link(struct super_block *sb, struct dentry *old_dentry, struct
dentry *new_dentry,
+ int old_branch, int new_branch);
+
/* unlink */
int odf_remove(struct dentry *dentry, int flags);
int odf_reclaim(struct dentry *dentry);
_______________________________________________
unionfs-cvs mailing list: http://unionfs.filesystems.org/
[email protected]
http://www.fsl.cs.sunysb.edu/mailman/listinfo/unionfs-cvs