mirror of
git://projects.qi-hardware.com/openwrt-xburst.git
synced 2024-11-27 21:18:26 +02:00
remove incomplete union mounts / jffs2 patches. will be replaced by updated versions once they're ready - should fix #6375
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@18822 3c298f89-4303-0410-b956-a3cf2f4a3e73
This commit is contained in:
parent
e9b1e2efdf
commit
210b6ad13c
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
||||
--- a/fs/namespace.c
|
||||
+++ b/fs/namespace.c
|
||||
@@ -1550,7 +1550,7 @@ static int do_loopback(struct path *path
|
||||
if (!mnt)
|
||||
goto out;
|
||||
|
||||
- err = check_union_mnt(&old_path, mnt, mnt_flags);
|
||||
+ err = check_union_mnt(path, mnt, mnt_flags);
|
||||
if (err)
|
||||
goto out;
|
||||
|
@ -1,11 +0,0 @@
|
||||
--- a/include/linux/union.h
|
||||
+++ b/include/linux/union.h
|
||||
@@ -77,7 +77,7 @@ extern int union_permission(struct path
|
||||
#define __union_copyup(x, y, z) ({ BUG(); (0); })
|
||||
#define union_copyup(x, y) ({ (0); })
|
||||
#define union_copyup_dir(x) ({ BUG(); (0); })
|
||||
-#define union_permission(x, y) inode_permission(x->dentry->d_inode, y)
|
||||
+#define union_permission(x, y) inode_permission((x)->dentry->d_inode, y)
|
||||
|
||||
#endif /* CONFIG_UNION_MOUNT */
|
||||
#endif /* __KERNEL__ */
|
@ -1,186 +0,0 @@
|
||||
--- a/fs/jffs2/dir.c
|
||||
+++ b/fs/jffs2/dir.c
|
||||
@@ -34,6 +34,9 @@ static int jffs2_mknod (struct inode *,s
|
||||
static int jffs2_rename (struct inode *, struct dentry *,
|
||||
struct inode *, struct dentry *);
|
||||
|
||||
+static int jffs2_whiteout (struct inode *, struct dentry *, struct dentry *);
|
||||
+static int jffs2_fallthru (struct inode *, struct dentry *);
|
||||
+
|
||||
const struct file_operations jffs2_dir_operations =
|
||||
{
|
||||
.read = generic_read_dir,
|
||||
@@ -55,6 +58,8 @@ const struct inode_operations jffs2_dir_
|
||||
.rmdir = jffs2_rmdir,
|
||||
.mknod = jffs2_mknod,
|
||||
.rename = jffs2_rename,
|
||||
+ .fallthru = jffs2_fallthru,
|
||||
+ .whiteout = jffs2_whiteout,
|
||||
.permission = jffs2_permission,
|
||||
.setattr = jffs2_setattr,
|
||||
.setxattr = jffs2_setxattr,
|
||||
@@ -98,8 +103,21 @@ static struct dentry *jffs2_lookup(struc
|
||||
fd = fd_list;
|
||||
}
|
||||
}
|
||||
- if (fd)
|
||||
- ino = fd->ino;
|
||||
+ if (fd) {
|
||||
+ spin_lock(&target->d_lock);
|
||||
+ switch(fd->type) {
|
||||
+ case DT_WHT:
|
||||
+ target->d_flags |= DCACHE_WHITEOUT;
|
||||
+ break;
|
||||
+ case DT_UNKNOWN:
|
||||
+ target->d_flags |= DCACHE_FALLTHRU;
|
||||
+ break;
|
||||
+ default:
|
||||
+ ino = fd->ino;
|
||||
+ break;
|
||||
+ }
|
||||
+ spin_unlock(&target->d_lock);
|
||||
+ }
|
||||
mutex_unlock(&dir_f->sem);
|
||||
if (ino) {
|
||||
inode = jffs2_iget(dir_i->i_sb, ino);
|
||||
@@ -155,7 +173,9 @@ static int jffs2_readdir(struct file *fi
|
||||
fd->name, fd->ino, fd->type, curofs, offset));
|
||||
continue;
|
||||
}
|
||||
- if (!fd->ino) {
|
||||
+ if (fd->type == DT_UNKNOWN)
|
||||
+ fd->ino = 100; /* XXX: arbitrary */
|
||||
+ else if (!fd->ino && (fd->type != DT_WHT)) {
|
||||
D2(printk(KERN_DEBUG "Skipping deletion dirent \"%s\"\n", fd->name));
|
||||
offset++;
|
||||
continue;
|
||||
@@ -498,6 +518,11 @@ static int jffs2_mkdir (struct inode *di
|
||||
return PTR_ERR(inode);
|
||||
}
|
||||
|
||||
+ if (dentry->d_flags & DCACHE_WHITEOUT) {
|
||||
+ inode->i_flags |= S_OPAQUE;
|
||||
+ ri->flags = cpu_to_je16(JFFS2_INO_FLAG_OPAQUE);
|
||||
+ }
|
||||
+
|
||||
inode->i_op = &jffs2_dir_inode_operations;
|
||||
inode->i_fop = &jffs2_dir_operations;
|
||||
|
||||
@@ -779,6 +804,82 @@ static int jffs2_mknod (struct inode *di
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int jffs2_fallthru (struct inode *dir, struct dentry *dentry)
|
||||
+{
|
||||
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(dir->i_sb);
|
||||
+ uint32_t now;
|
||||
+ int ret;
|
||||
+
|
||||
+ now = get_seconds();
|
||||
+ ret = jffs2_do_link(c, JFFS2_INODE_INFO(dir), 0, DT_UNKNOWN,
|
||||
+ dentry->d_name.name, dentry->d_name.len, now);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ d_instantiate(dentry, NULL);
|
||||
+ spin_lock(&dentry->d_lock);
|
||||
+ dentry->d_flags |= DCACHE_FALLTHRU;
|
||||
+ spin_unlock(&dentry->d_lock);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int jffs2_whiteout (struct inode *dir, struct dentry *old_dentry,
|
||||
+ struct dentry *new_dentry)
|
||||
+{
|
||||
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(dir->i_sb);
|
||||
+ struct jffs2_inode_info *victim_f = NULL;
|
||||
+ uint32_t now;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* If it's a directory, then check whether it is really empty
|
||||
+ */
|
||||
+ if (new_dentry->d_inode) {
|
||||
+ victim_f = JFFS2_INODE_INFO(old_dentry->d_inode);
|
||||
+ if (S_ISDIR(old_dentry->d_inode->i_mode)) {
|
||||
+ struct jffs2_full_dirent *fd;
|
||||
+
|
||||
+ mutex_lock(&victim_f->sem);
|
||||
+ for (fd = victim_f->dents; fd; fd = fd->next) {
|
||||
+ if (fd->ino) {
|
||||
+ mutex_unlock(&victim_f->sem);
|
||||
+ return -ENOTEMPTY;
|
||||
+ }
|
||||
+ }
|
||||
+ mutex_unlock(&victim_f->sem);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ now = get_seconds();
|
||||
+ ret = jffs2_do_link(c, JFFS2_INODE_INFO(dir), 0, DT_WHT,
|
||||
+ new_dentry->d_name.name, new_dentry->d_name.len, now);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ spin_lock(&new_dentry->d_lock);
|
||||
+ new_dentry->d_flags &= ~DCACHE_FALLTHRU;
|
||||
+ new_dentry->d_flags |= DCACHE_WHITEOUT;
|
||||
+ spin_unlock(&new_dentry->d_lock);
|
||||
+ d_add(new_dentry, NULL);
|
||||
+
|
||||
+ if (victim_f) {
|
||||
+ /* There was a victim. Kill it off nicely */
|
||||
+ drop_nlink(old_dentry->d_inode);
|
||||
+ /* Don't oops if the victim was a dirent pointing to an
|
||||
+ inode which didn't exist. */
|
||||
+ if (victim_f->inocache) {
|
||||
+ mutex_lock(&victim_f->sem);
|
||||
+ if (S_ISDIR(old_dentry->d_inode->i_mode))
|
||||
+ victim_f->inocache->pino_nlink = 0;
|
||||
+ else
|
||||
+ victim_f->inocache->pino_nlink--;
|
||||
+ mutex_unlock(&victim_f->sem);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
|
||||
struct inode *new_dir_i, struct dentry *new_dentry)
|
||||
{
|
||||
--- a/fs/jffs2/fs.c
|
||||
+++ b/fs/jffs2/fs.c
|
||||
@@ -301,6 +301,10 @@ struct inode *jffs2_iget(struct super_bl
|
||||
|
||||
inode->i_op = &jffs2_dir_inode_operations;
|
||||
inode->i_fop = &jffs2_dir_operations;
|
||||
+
|
||||
+ if (je16_to_cpu(latest_node.flags) & JFFS2_INO_FLAG_OPAQUE)
|
||||
+ inode->i_flags |= S_OPAQUE;
|
||||
+
|
||||
break;
|
||||
}
|
||||
case S_IFREG:
|
||||
--- a/fs/jffs2/super.c
|
||||
+++ b/fs/jffs2/super.c
|
||||
@@ -172,7 +172,7 @@ static int jffs2_fill_super(struct super
|
||||
|
||||
sb->s_op = &jffs2_super_operations;
|
||||
sb->s_export_op = &jffs2_export_ops;
|
||||
- sb->s_flags = sb->s_flags | MS_NOATIME;
|
||||
+ sb->s_flags = sb->s_flags | MS_NOATIME | MS_WHITEOUT;
|
||||
sb->s_xattr = jffs2_xattr_handlers;
|
||||
#ifdef CONFIG_JFFS2_FS_POSIX_ACL
|
||||
sb->s_flags |= MS_POSIXACL;
|
||||
--- a/include/linux/jffs2.h
|
||||
+++ b/include/linux/jffs2.h
|
||||
@@ -87,6 +87,8 @@
|
||||
#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific
|
||||
compression type */
|
||||
|
||||
+#define JFFS2_INO_FLAG_OPAQUE 4 /* Directory is opaque (for union mounts) */
|
||||
+
|
||||
|
||||
/* These can go once we've made sure we've caught all uses without
|
||||
byteswapping */
|
@ -1,30 +0,0 @@
|
||||
--- a/fs/union.c
|
||||
+++ b/fs/union.c
|
||||
@@ -842,10 +842,8 @@ static int union_copyup_dir_one(void *bu
|
||||
/* Lookup this entry in the topmost directory */
|
||||
dentry = lookup_one_len(name, topmost_dentry, namlen);
|
||||
|
||||
- if (IS_ERR(dentry)) {
|
||||
- printk(KERN_INFO "error looking up %s\n", dentry->d_name.name);
|
||||
+ if (IS_ERR(dentry))
|
||||
goto out;
|
||||
- }
|
||||
|
||||
/*
|
||||
* If the entry already exists, one of the following is true:
|
||||
@@ -857,7 +855,6 @@ static int union_copyup_dir_one(void *bu
|
||||
*/
|
||||
if (dentry->d_inode || d_is_whiteout(dentry) ||
|
||||
d_is_fallthru(dentry)) {
|
||||
- printk(KERN_INFO "skipping copy of %s\n", dentry->d_name.name);
|
||||
goto out_dput;
|
||||
}
|
||||
|
||||
@@ -867,7 +864,6 @@ static int union_copyup_dir_one(void *bu
|
||||
* used, so each file system must implement its own way of
|
||||
* storing a fallthru entry.
|
||||
*/
|
||||
- printk(KERN_INFO "creating fallthru for %s\n", dentry->d_name.name);
|
||||
err = topmost_dentry->d_inode->i_op->fallthru(topmost_dentry->d_inode,
|
||||
dentry);
|
||||
/* FIXME */
|
@ -1,117 +0,0 @@
|
||||
--- a/fs/namespace.c
|
||||
+++ b/fs/namespace.c
|
||||
@@ -1656,8 +1656,10 @@ static int do_move_mount(struct path *pa
|
||||
|
||||
/* moving to or from a union mount is not supported */
|
||||
err = -EINVAL;
|
||||
+#if 0
|
||||
if (IS_MNT_UNION(path->mnt))
|
||||
goto exit;
|
||||
+#endif
|
||||
if (IS_MNT_UNION(old_path.mnt))
|
||||
goto exit;
|
||||
|
||||
--- a/fs/union.c
|
||||
+++ b/fs/union.c
|
||||
@@ -260,8 +260,6 @@ int append_to_union(struct vfsmount *mnt
|
||||
spin_lock(&union_lock);
|
||||
um = union_lookup(dentry, mnt);
|
||||
if (um) {
|
||||
- BUG_ON((um->u_next.dentry != dest_dentry) ||
|
||||
- (um->u_next.mnt != dest_mnt));
|
||||
spin_unlock(&union_lock);
|
||||
union_put(this);
|
||||
return 0;
|
||||
@@ -274,6 +272,23 @@ int append_to_union(struct vfsmount *mnt
|
||||
return 0;
|
||||
}
|
||||
|
||||
+int follow_union_mountpoint(struct path *path)
|
||||
+{
|
||||
+ struct path new_path = *path;
|
||||
+
|
||||
+ path_get(&new_path);
|
||||
+ while (follow_union_down(&new_path)) {
|
||||
+ if (new_path.dentry != new_path.mnt->mnt_root)
|
||||
+ continue;
|
||||
+
|
||||
+ path_put(path);
|
||||
+ *path = new_path;
|
||||
+ return 1;
|
||||
+ }
|
||||
+ path_put(&new_path);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* follow_union_down - follow the union stack one layer down
|
||||
*
|
||||
--- a/include/linux/union.h
|
||||
+++ b/include/linux/union.h
|
||||
@@ -47,6 +47,7 @@ extern int append_to_union(struct vfsmou
|
||||
struct vfsmount *, struct dentry *);
|
||||
extern int follow_union_down(struct path *);
|
||||
extern int follow_union_mount(struct path *);
|
||||
+extern int follow_union_mountpoint(struct path *path);
|
||||
extern void __d_drop_unions(struct dentry *);
|
||||
extern void shrink_d_unions(struct dentry *);
|
||||
extern void __shrink_d_unions(struct dentry *, struct list_head *);
|
||||
@@ -68,6 +69,7 @@ extern int union_permission(struct path
|
||||
#define append_to_union(x1, y1, x2, y2) ({ BUG(); (0); })
|
||||
#define follow_union_down(x) ({ (0); })
|
||||
#define follow_union_mount(x) ({ (0); })
|
||||
+#define follow_union_mountpoint(x) ({ (0); })
|
||||
#define __d_drop_unions(x) do { } while (0)
|
||||
#define shrink_d_unions(x) do { } while (0)
|
||||
#define __shrink_d_unions(x,y) do { } while (0)
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -613,6 +613,9 @@ static int cache_lookup_union(struct nam
|
||||
!S_ISDIR(path->dentry->d_inode->i_mode))
|
||||
goto out;
|
||||
|
||||
+ if (follow_union_mountpoint(path))
|
||||
+ goto out;
|
||||
+
|
||||
/* Build the union stack for this part */
|
||||
res = __cache_lookup_build_union(nd, name, path);
|
||||
if (res) {
|
||||
@@ -886,6 +889,9 @@ static int real_lookup_union(struct name
|
||||
!S_ISDIR(path->dentry->d_inode->i_mode))
|
||||
goto out;
|
||||
|
||||
+ if (follow_union_mountpoint(path))
|
||||
+ goto out;
|
||||
+
|
||||
/* Build the union stack for this part */
|
||||
res = __real_lookup_build_union(nd, name, path);
|
||||
if (res) {
|
||||
@@ -1813,6 +1819,9 @@ int hash_lookup_union(struct nameidata *
|
||||
!S_ISDIR(path->dentry->d_inode->i_mode))
|
||||
goto out;
|
||||
|
||||
+ if (follow_union_mountpoint(path))
|
||||
+ goto out;
|
||||
+
|
||||
/* Build the union stack for this part */
|
||||
res = __hash_lookup_build_union(nd, name, path);
|
||||
if (res) {
|
||||
--- a/fs/readdir.c
|
||||
+++ b/fs/readdir.c
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/union.h>
|
||||
+#include <linux/mount.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
@@ -45,7 +46,7 @@ int vfs_readdir(struct file *file, filld
|
||||
* below this one in the union stack.
|
||||
*/
|
||||
if (is_unionized(file->f_path.dentry, file->f_path.mnt) &&
|
||||
- !IS_OPAQUE(inode)) {
|
||||
+ !IS_OPAQUE(inode) && IS_MNT_UNION(file->f_path.mnt)) {
|
||||
res = union_copyup_dir(&file->f_path);
|
||||
if (res)
|
||||
goto out_unlock;
|
File diff suppressed because it is too large
Load Diff
@ -1,11 +0,0 @@
|
||||
--- a/fs/namespace.c
|
||||
+++ b/fs/namespace.c
|
||||
@@ -1550,7 +1550,7 @@ static int do_loopback(struct path *path
|
||||
if (!mnt)
|
||||
goto out;
|
||||
|
||||
- err = check_union_mnt(&old_path, mnt, mnt_flags);
|
||||
+ err = check_union_mnt(path, mnt, mnt_flags);
|
||||
if (err)
|
||||
goto out;
|
||||
|
@ -1,11 +0,0 @@
|
||||
--- a/include/linux/union.h
|
||||
+++ b/include/linux/union.h
|
||||
@@ -77,7 +77,7 @@ extern int union_permission(struct path
|
||||
#define __union_copyup(x, y, z) ({ BUG(); (0); })
|
||||
#define union_copyup(x, y) ({ (0); })
|
||||
#define union_copyup_dir(x) ({ BUG(); (0); })
|
||||
-#define union_permission(x, y) inode_permission(x->dentry->d_inode, y)
|
||||
+#define union_permission(x, y) inode_permission((x)->dentry->d_inode, y)
|
||||
|
||||
#endif /* CONFIG_UNION_MOUNT */
|
||||
#endif /* __KERNEL__ */
|
@ -1,186 +0,0 @@
|
||||
--- a/fs/jffs2/dir.c
|
||||
+++ b/fs/jffs2/dir.c
|
||||
@@ -34,6 +34,9 @@ static int jffs2_mknod (struct inode *,s
|
||||
static int jffs2_rename (struct inode *, struct dentry *,
|
||||
struct inode *, struct dentry *);
|
||||
|
||||
+static int jffs2_whiteout (struct inode *, struct dentry *, struct dentry *);
|
||||
+static int jffs2_fallthru (struct inode *, struct dentry *);
|
||||
+
|
||||
const struct file_operations jffs2_dir_operations =
|
||||
{
|
||||
.read = generic_read_dir,
|
||||
@@ -55,6 +58,8 @@ const struct inode_operations jffs2_dir_
|
||||
.rmdir = jffs2_rmdir,
|
||||
.mknod = jffs2_mknod,
|
||||
.rename = jffs2_rename,
|
||||
+ .fallthru = jffs2_fallthru,
|
||||
+ .whiteout = jffs2_whiteout,
|
||||
.check_acl = jffs2_check_acl,
|
||||
.setattr = jffs2_setattr,
|
||||
.setxattr = jffs2_setxattr,
|
||||
@@ -98,8 +103,21 @@ static struct dentry *jffs2_lookup(struc
|
||||
fd = fd_list;
|
||||
}
|
||||
}
|
||||
- if (fd)
|
||||
- ino = fd->ino;
|
||||
+ if (fd) {
|
||||
+ spin_lock(&target->d_lock);
|
||||
+ switch(fd->type) {
|
||||
+ case DT_WHT:
|
||||
+ target->d_flags |= DCACHE_WHITEOUT;
|
||||
+ break;
|
||||
+ case DT_UNKNOWN:
|
||||
+ target->d_flags |= DCACHE_FALLTHRU;
|
||||
+ break;
|
||||
+ default:
|
||||
+ ino = fd->ino;
|
||||
+ break;
|
||||
+ }
|
||||
+ spin_unlock(&target->d_lock);
|
||||
+ }
|
||||
mutex_unlock(&dir_f->sem);
|
||||
if (ino) {
|
||||
inode = jffs2_iget(dir_i->i_sb, ino);
|
||||
@@ -155,7 +173,9 @@ static int jffs2_readdir(struct file *fi
|
||||
fd->name, fd->ino, fd->type, curofs, offset));
|
||||
continue;
|
||||
}
|
||||
- if (!fd->ino) {
|
||||
+ if (fd->type == DT_UNKNOWN)
|
||||
+ fd->ino = 100; /* XXX: arbitrary */
|
||||
+ else if (!fd->ino && (fd->type != DT_WHT)) {
|
||||
D2(printk(KERN_DEBUG "Skipping deletion dirent \"%s\"\n", fd->name));
|
||||
offset++;
|
||||
continue;
|
||||
@@ -498,6 +518,11 @@ static int jffs2_mkdir (struct inode *di
|
||||
return PTR_ERR(inode);
|
||||
}
|
||||
|
||||
+ if (dentry->d_flags & DCACHE_WHITEOUT) {
|
||||
+ inode->i_flags |= S_OPAQUE;
|
||||
+ ri->flags = cpu_to_je16(JFFS2_INO_FLAG_OPAQUE);
|
||||
+ }
|
||||
+
|
||||
inode->i_op = &jffs2_dir_inode_operations;
|
||||
inode->i_fop = &jffs2_dir_operations;
|
||||
|
||||
@@ -779,6 +804,82 @@ static int jffs2_mknod (struct inode *di
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int jffs2_fallthru (struct inode *dir, struct dentry *dentry)
|
||||
+{
|
||||
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(dir->i_sb);
|
||||
+ uint32_t now;
|
||||
+ int ret;
|
||||
+
|
||||
+ now = get_seconds();
|
||||
+ ret = jffs2_do_link(c, JFFS2_INODE_INFO(dir), 0, DT_UNKNOWN,
|
||||
+ dentry->d_name.name, dentry->d_name.len, now);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ d_instantiate(dentry, NULL);
|
||||
+ spin_lock(&dentry->d_lock);
|
||||
+ dentry->d_flags |= DCACHE_FALLTHRU;
|
||||
+ spin_unlock(&dentry->d_lock);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int jffs2_whiteout (struct inode *dir, struct dentry *old_dentry,
|
||||
+ struct dentry *new_dentry)
|
||||
+{
|
||||
+ struct jffs2_sb_info *c = JFFS2_SB_INFO(dir->i_sb);
|
||||
+ struct jffs2_inode_info *victim_f = NULL;
|
||||
+ uint32_t now;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* If it's a directory, then check whether it is really empty
|
||||
+ */
|
||||
+ if (new_dentry->d_inode) {
|
||||
+ victim_f = JFFS2_INODE_INFO(old_dentry->d_inode);
|
||||
+ if (S_ISDIR(old_dentry->d_inode->i_mode)) {
|
||||
+ struct jffs2_full_dirent *fd;
|
||||
+
|
||||
+ mutex_lock(&victim_f->sem);
|
||||
+ for (fd = victim_f->dents; fd; fd = fd->next) {
|
||||
+ if (fd->ino) {
|
||||
+ mutex_unlock(&victim_f->sem);
|
||||
+ return -ENOTEMPTY;
|
||||
+ }
|
||||
+ }
|
||||
+ mutex_unlock(&victim_f->sem);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ now = get_seconds();
|
||||
+ ret = jffs2_do_link(c, JFFS2_INODE_INFO(dir), 0, DT_WHT,
|
||||
+ new_dentry->d_name.name, new_dentry->d_name.len, now);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ spin_lock(&new_dentry->d_lock);
|
||||
+ new_dentry->d_flags &= ~DCACHE_FALLTHRU;
|
||||
+ new_dentry->d_flags |= DCACHE_WHITEOUT;
|
||||
+ spin_unlock(&new_dentry->d_lock);
|
||||
+ d_add(new_dentry, NULL);
|
||||
+
|
||||
+ if (victim_f) {
|
||||
+ /* There was a victim. Kill it off nicely */
|
||||
+ drop_nlink(old_dentry->d_inode);
|
||||
+ /* Don't oops if the victim was a dirent pointing to an
|
||||
+ inode which didn't exist. */
|
||||
+ if (victim_f->inocache) {
|
||||
+ mutex_lock(&victim_f->sem);
|
||||
+ if (S_ISDIR(old_dentry->d_inode->i_mode))
|
||||
+ victim_f->inocache->pino_nlink = 0;
|
||||
+ else
|
||||
+ victim_f->inocache->pino_nlink--;
|
||||
+ mutex_unlock(&victim_f->sem);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
|
||||
struct inode *new_dir_i, struct dentry *new_dentry)
|
||||
{
|
||||
--- a/fs/jffs2/fs.c
|
||||
+++ b/fs/jffs2/fs.c
|
||||
@@ -301,6 +301,10 @@ struct inode *jffs2_iget(struct super_bl
|
||||
|
||||
inode->i_op = &jffs2_dir_inode_operations;
|
||||
inode->i_fop = &jffs2_dir_operations;
|
||||
+
|
||||
+ if (je16_to_cpu(latest_node.flags) & JFFS2_INO_FLAG_OPAQUE)
|
||||
+ inode->i_flags |= S_OPAQUE;
|
||||
+
|
||||
break;
|
||||
}
|
||||
case S_IFREG:
|
||||
--- a/fs/jffs2/super.c
|
||||
+++ b/fs/jffs2/super.c
|
||||
@@ -172,7 +172,7 @@ static int jffs2_fill_super(struct super
|
||||
|
||||
sb->s_op = &jffs2_super_operations;
|
||||
sb->s_export_op = &jffs2_export_ops;
|
||||
- sb->s_flags = sb->s_flags | MS_NOATIME;
|
||||
+ sb->s_flags = sb->s_flags | MS_NOATIME | MS_WHITEOUT;
|
||||
sb->s_xattr = jffs2_xattr_handlers;
|
||||
#ifdef CONFIG_JFFS2_FS_POSIX_ACL
|
||||
sb->s_flags |= MS_POSIXACL;
|
||||
--- a/include/linux/jffs2.h
|
||||
+++ b/include/linux/jffs2.h
|
||||
@@ -87,6 +87,8 @@
|
||||
#define JFFS2_INO_FLAG_USERCOMPR 2 /* User has requested a specific
|
||||
compression type */
|
||||
|
||||
+#define JFFS2_INO_FLAG_OPAQUE 4 /* Directory is opaque (for union mounts) */
|
||||
+
|
||||
|
||||
/* These can go once we've made sure we've caught all uses without
|
||||
byteswapping */
|
@ -1,30 +0,0 @@
|
||||
--- a/fs/union.c
|
||||
+++ b/fs/union.c
|
||||
@@ -842,10 +842,8 @@ static int union_copyup_dir_one(void *bu
|
||||
/* Lookup this entry in the topmost directory */
|
||||
dentry = lookup_one_len(name, topmost_dentry, namlen);
|
||||
|
||||
- if (IS_ERR(dentry)) {
|
||||
- printk(KERN_INFO "error looking up %s\n", dentry->d_name.name);
|
||||
+ if (IS_ERR(dentry))
|
||||
goto out;
|
||||
- }
|
||||
|
||||
/*
|
||||
* If the entry already exists, one of the following is true:
|
||||
@@ -857,7 +855,6 @@ static int union_copyup_dir_one(void *bu
|
||||
*/
|
||||
if (dentry->d_inode || d_is_whiteout(dentry) ||
|
||||
d_is_fallthru(dentry)) {
|
||||
- printk(KERN_INFO "skipping copy of %s\n", dentry->d_name.name);
|
||||
goto out_dput;
|
||||
}
|
||||
|
||||
@@ -867,7 +864,6 @@ static int union_copyup_dir_one(void *bu
|
||||
* used, so each file system must implement its own way of
|
||||
* storing a fallthru entry.
|
||||
*/
|
||||
- printk(KERN_INFO "creating fallthru for %s\n", dentry->d_name.name);
|
||||
err = topmost_dentry->d_inode->i_op->fallthru(topmost_dentry->d_inode,
|
||||
dentry);
|
||||
/* FIXME */
|
@ -1,117 +0,0 @@
|
||||
--- a/fs/namespace.c
|
||||
+++ b/fs/namespace.c
|
||||
@@ -1656,8 +1656,10 @@ static int do_move_mount(struct path *pa
|
||||
|
||||
/* moving to or from a union mount is not supported */
|
||||
err = -EINVAL;
|
||||
+#if 0
|
||||
if (IS_MNT_UNION(path->mnt))
|
||||
goto exit;
|
||||
+#endif
|
||||
if (IS_MNT_UNION(old_path.mnt))
|
||||
goto exit;
|
||||
|
||||
--- a/fs/union.c
|
||||
+++ b/fs/union.c
|
||||
@@ -260,8 +260,6 @@ int append_to_union(struct vfsmount *mnt
|
||||
spin_lock(&union_lock);
|
||||
um = union_lookup(dentry, mnt);
|
||||
if (um) {
|
||||
- BUG_ON((um->u_next.dentry != dest_dentry) ||
|
||||
- (um->u_next.mnt != dest_mnt));
|
||||
spin_unlock(&union_lock);
|
||||
union_put(this);
|
||||
return 0;
|
||||
@@ -274,6 +272,23 @@ int append_to_union(struct vfsmount *mnt
|
||||
return 0;
|
||||
}
|
||||
|
||||
+int follow_union_mountpoint(struct path *path)
|
||||
+{
|
||||
+ struct path new_path = *path;
|
||||
+
|
||||
+ path_get(&new_path);
|
||||
+ while (follow_union_down(&new_path)) {
|
||||
+ if (new_path.dentry != new_path.mnt->mnt_root)
|
||||
+ continue;
|
||||
+
|
||||
+ path_put(path);
|
||||
+ *path = new_path;
|
||||
+ return 1;
|
||||
+ }
|
||||
+ path_put(&new_path);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* follow_union_down - follow the union stack one layer down
|
||||
*
|
||||
--- a/include/linux/union.h
|
||||
+++ b/include/linux/union.h
|
||||
@@ -47,6 +47,7 @@ extern int append_to_union(struct vfsmou
|
||||
struct vfsmount *, struct dentry *);
|
||||
extern int follow_union_down(struct path *);
|
||||
extern int follow_union_mount(struct path *);
|
||||
+extern int follow_union_mountpoint(struct path *path);
|
||||
extern void __d_drop_unions(struct dentry *);
|
||||
extern void shrink_d_unions(struct dentry *);
|
||||
extern void __shrink_d_unions(struct dentry *, struct list_head *);
|
||||
@@ -68,6 +69,7 @@ extern int union_permission(struct path
|
||||
#define append_to_union(x1, y1, x2, y2) ({ BUG(); (0); })
|
||||
#define follow_union_down(x) ({ (0); })
|
||||
#define follow_union_mount(x) ({ (0); })
|
||||
+#define follow_union_mountpoint(x) ({ (0); })
|
||||
#define __d_drop_unions(x) do { } while (0)
|
||||
#define shrink_d_unions(x) do { } while (0)
|
||||
#define __shrink_d_unions(x,y) do { } while (0)
|
||||
--- a/fs/namei.c
|
||||
+++ b/fs/namei.c
|
||||
@@ -626,6 +626,9 @@ static int cache_lookup_union(struct nam
|
||||
!S_ISDIR(path->dentry->d_inode->i_mode))
|
||||
goto out;
|
||||
|
||||
+ if (follow_union_mountpoint(path))
|
||||
+ goto out;
|
||||
+
|
||||
/* Build the union stack for this part */
|
||||
res = __cache_lookup_build_union(nd, name, path);
|
||||
if (res) {
|
||||
@@ -892,6 +895,9 @@ static int real_lookup_union(struct name
|
||||
!S_ISDIR(path->dentry->d_inode->i_mode))
|
||||
goto out;
|
||||
|
||||
+ if (follow_union_mountpoint(path))
|
||||
+ goto out;
|
||||
+
|
||||
/* Build the union stack for this part */
|
||||
res = __real_lookup_build_union(nd, name, path);
|
||||
if (res) {
|
||||
@@ -1813,6 +1819,9 @@ int hash_lookup_union(struct nameidata *
|
||||
!S_ISDIR(path->dentry->d_inode->i_mode))
|
||||
goto out;
|
||||
|
||||
+ if (follow_union_mountpoint(path))
|
||||
+ goto out;
|
||||
+
|
||||
/* Build the union stack for this part */
|
||||
res = __hash_lookup_build_union(nd, name, path);
|
||||
if (res) {
|
||||
--- a/fs/readdir.c
|
||||
+++ b/fs/readdir.c
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/unistd.h>
|
||||
#include <linux/union.h>
|
||||
+#include <linux/mount.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
@@ -45,7 +46,7 @@ int vfs_readdir(struct file *file, filld
|
||||
* below this one in the union stack.
|
||||
*/
|
||||
if (is_unionized(file->f_path.dentry, file->f_path.mnt) &&
|
||||
- !IS_OPAQUE(inode)) {
|
||||
+ !IS_OPAQUE(inode) && IS_MNT_UNION(file->f_path.mnt)) {
|
||||
res = union_copyup_dir(&file->f_path);
|
||||
if (res)
|
||||
goto out_unlock;
|
Loading…
Reference in New Issue
Block a user