[RFC 11/26] tmpfs white-out support
From: Jan Blunck
Date: Mon Jul 30 2007 - 12:21:45 EST
Introduce white-out support to tmpfs.
Signed-off-by: Jan Blunck <jblunck@xxxxxxx>
---
include/linux/shmem_fs.h | 1
mm/shmem.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 55 insertions(+)
--- a/include/linux/shmem_fs.h
+++ b/include/linux/shmem_fs.h
@@ -33,6 +33,7 @@ struct shmem_sb_info {
int policy; /* Default NUMA memory alloc policy */
nodemask_t policy_nodes; /* nodemask for preferred and bind */
spinlock_t stat_lock;
+ struct inode *whiteout_inode;
};
static inline struct shmem_inode_info *SHMEM_I(struct inode *inode)
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1784,6 +1784,42 @@ static int shmem_create(struct inode *di
}
/*
+ * This is the whiteout support for tmpfs. It uses one singleton whiteout
+ * inode per superblock thus it is very similar to shmem_link().
+ */
+static int shmem_whiteout(struct inode *dir, struct dentry *dentry)
+{
+ struct shmem_sb_info *sbinfo = SHMEM_SB(dir->i_sb);
+ struct inode *inode = sbinfo->whiteout_inode;
+
+ if (!(dir->i_sb->s_flags & MS_WHITEOUT))
+ return -EPERM;
+
+ /*
+ * No ordinary (disk based) filesystem counts whiteouts as inodes;
+ * but each new link needs a new dentry, pinning lowmem, and
+ * tmpfs dentries cannot be pruned until they are unlinked.
+ */
+ if (sbinfo->max_inodes) {
+ spin_lock(&sbinfo->stat_lock);
+ if (!sbinfo->free_inodes) {
+ spin_unlock(&sbinfo->stat_lock);
+ return -ENOSPC;
+ }
+ sbinfo->free_inodes--;
+ spin_unlock(&sbinfo->stat_lock);
+ }
+
+ dir->i_size += BOGO_DIRENT_SIZE;
+ inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+ inc_nlink(inode);
+ atomic_inc(&inode->i_count); /* New dentry reference */
+ dget(dentry); /* Extra pinning count for the created dentry */
+ d_instantiate(dentry, inode);
+ return 0;
+}
+
+/*
* Link a file..
*/
static int shmem_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
@@ -2231,6 +2267,9 @@ out:
static void shmem_put_super(struct super_block *sb)
{
+ struct shmem_sb_info *sbinfo = sb->s_fs_info;
+
+ iput(sbinfo->whiteout_inode);
kfree(sb->s_fs_info);
sb->s_fs_info = NULL;
}
@@ -2305,6 +2344,19 @@ static int shmem_fill_super(struct super
if (!root)
goto failed_iput;
sb->s_root = root;
+
+#ifdef CONFIG_TMPFS
+ if (!(sb->s_flags & MS_NOUSER)) {
+ inode = shmem_get_inode(sb, S_IRUGO | S_IWUGO | S_IFWHT, 0);
+ if (!inode) {
+ dput(root);
+ goto failed;
+ }
+ sbinfo->whiteout_inode = inode;
+ sb->s_flags |= MS_WHITEOUT;
+ }
+#endif
+
return 0;
failed_iput:
@@ -2410,6 +2462,7 @@ static const struct inode_operations shm
.rmdir = shmem_rmdir,
.mknod = shmem_mknod,
.rename = shmem_rename,
+ .whiteout = shmem_whiteout,
#endif
#ifdef CONFIG_TMPFS_POSIX_ACL
.setattr = shmem_notify_change,
@@ -2464,6 +2517,7 @@ static struct file_system_type tmpfs_fs_
.name = "tmpfs",
.get_sb = shmem_get_sb,
.kill_sb = kill_litter_super,
+ .fs_flags = FS_WHT,
};
static struct vfsmount *shm_mnt;
--
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/