remove incomplete union mounts / jffs2 patches. will be replaced by updated versions once they're ready - should fix #6375
SVN-Revision: 18822master
parent
17ee33ebb9
commit
7ce0bc4472
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