diff options
Diffstat (limited to 'target')
| -rw-r--r-- | target/linux/generic-2.6/patches-2.6.31/233-jffs2_whiteout_support.patch | 186 | 
1 files changed, 186 insertions, 0 deletions
diff --git a/target/linux/generic-2.6/patches-2.6.31/233-jffs2_whiteout_support.patch b/target/linux/generic-2.6/patches-2.6.31/233-jffs2_whiteout_support.patch new file mode 100644 index 000000000..72a428237 --- /dev/null +++ b/target/linux/generic-2.6/patches-2.6.31/233-jffs2_whiteout_support.patch @@ -0,0 +1,186 @@ +--- a/fs/jffs2/dir.c ++++ b/fs/jffs2/dir.c +@@ -34,6 +34,9 @@ + 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 @@ + 	.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 @@ + 			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 @@ + 				  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 @@ + 		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 @@ + 	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 @@ +  + 		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 @@ +  + 	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 */  | 
