aboutsummaryrefslogtreecommitdiffstats
path: root/mm/shmem.c
diff options
context:
space:
mode:
authorDavid M. Grimes <dgrimes@navisite.com>2006-10-17 03:09:45 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-10-17 11:18:43 -0400
commit91828a405ae454a9503c41a7744f6ff877a80714 (patch)
treeaa1f051da60f320675a970ad304a9987ca1d7ce3 /mm/shmem.c
parent5c496374a72320279ddb86291ef709e090a5d531 (diff)
[PATCH] knfsd: add nfs-export support to tmpfs
We need to encode a decode the 'file' part of a handle. We simply use the inode number and generation number to construct the filehandle. The generation number is the time when the file was created. As inode numbers cycle through the full 32 bits before being reused, there is no real chance of the same inum being allocated to different files in the same second so this is suitably unique. Using time-of-day rather than e.g. jiffies makes it less likely that the same filehandle can be created after a reboot. In order to be able to decode a filehandle we need to be able to lookup by inum, which means that the inode needs to be added to the inode hash table (tmpfs doesn't currently hash inodes as there is never a need to lookup by inum). To avoid overhead when not exporting, we only hash an inode when it is first exported. This requires a lock to ensure it isn't hashed twice. This code is separate from the patch posted in June06 from Atal Shargorodsky which provided the same functionality, but does borrow slightly from it. Locking comment: Most filesystems that hash their inodes do so at the point where the 'struct inode' is initialised, and that has suitable locking (I_NEW). Here in shmem, we are hashing the inode later, the first time we need an NFS file handle for it. We no longer have I_NEW to ensure only one thread tries to add it to the hash table. Cc: Atal Shargorodsky <atal@codefidence.com> Cc: Gilad Ben-Yossef <gilad@codefidence.com> Signed-off-by: David M. Grimes <dgrimes@navisite.com> Signed-off-by: Neil Brown <neilb@suse.de> Acked-by: Hugh Dickins <hugh@veritas.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'mm/shmem.c')
-rw-r--r--mm/shmem.c81
1 files changed, 81 insertions, 0 deletions
diff --git a/mm/shmem.c b/mm/shmem.c
index bb8ca7ef7094..b378f66cf2f9 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -1362,6 +1362,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
1362 inode->i_mapping->a_ops = &shmem_aops; 1362 inode->i_mapping->a_ops = &shmem_aops;
1363 inode->i_mapping->backing_dev_info = &shmem_backing_dev_info; 1363 inode->i_mapping->backing_dev_info = &shmem_backing_dev_info;
1364 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; 1364 inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
1365 inode->i_generation = get_seconds();
1365 info = SHMEM_I(inode); 1366 info = SHMEM_I(inode);
1366 memset(info, 0, (char *)inode - (char *)info); 1367 memset(info, 0, (char *)inode - (char *)info);
1367 spin_lock_init(&info->lock); 1368 spin_lock_init(&info->lock);
@@ -1956,6 +1957,85 @@ static struct xattr_handler *shmem_xattr_handlers[] = {
1956}; 1957};
1957#endif 1958#endif
1958 1959
1960static struct dentry *shmem_get_parent(struct dentry *child)
1961{
1962 return ERR_PTR(-ESTALE);
1963}
1964
1965static int shmem_match(struct inode *ino, void *vfh)
1966{
1967 __u32 *fh = vfh;
1968 __u64 inum = fh[2];
1969 inum = (inum << 32) | fh[1];
1970 return ino->i_ino == inum && fh[0] == ino->i_generation;
1971}
1972
1973static struct dentry *shmem_get_dentry(struct super_block *sb, void *vfh)
1974{
1975 struct dentry *de = NULL;
1976 struct inode *inode;
1977 __u32 *fh = vfh;
1978 __u64 inum = fh[2];
1979 inum = (inum << 32) | fh[1];
1980
1981 inode = ilookup5(sb, (unsigned long)(inum+fh[0]), shmem_match, vfh);
1982 if (inode) {
1983 de = d_find_alias(inode);
1984 iput(inode);
1985 }
1986
1987 return de? de: ERR_PTR(-ESTALE);
1988}
1989
1990static struct dentry *shmem_decode_fh(struct super_block *sb, __u32 *fh,
1991 int len, int type,
1992 int (*acceptable)(void *context, struct dentry *de),
1993 void *context)
1994{
1995 if (len < 3)
1996 return ERR_PTR(-ESTALE);
1997
1998 return sb->s_export_op->find_exported_dentry(sb, fh, NULL, acceptable,
1999 context);
2000}
2001
2002static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
2003 int connectable)
2004{
2005 struct inode *inode = dentry->d_inode;
2006
2007 if (*len < 3)
2008 return 255;
2009
2010 if (hlist_unhashed(&inode->i_hash)) {
2011 /* Unfortunately insert_inode_hash is not idempotent,
2012 * so as we hash inodes here rather than at creation
2013 * time, we need a lock to ensure we only try
2014 * to do it once
2015 */
2016 static DEFINE_SPINLOCK(lock);
2017 spin_lock(&lock);
2018 if (hlist_unhashed(&inode->i_hash))
2019 __insert_inode_hash(inode,
2020 inode->i_ino + inode->i_generation);
2021 spin_unlock(&lock);
2022 }
2023
2024 fh[0] = inode->i_generation;
2025 fh[1] = inode->i_ino;
2026 fh[2] = ((__u64)inode->i_ino) >> 32;
2027
2028 *len = 3;
2029 return 1;
2030}
2031
2032static struct export_operations shmem_export_ops = {
2033 .get_parent = shmem_get_parent,
2034 .get_dentry = shmem_get_dentry,
2035 .encode_fh = shmem_encode_fh,
2036 .decode_fh = shmem_decode_fh,
2037};
2038
1959static int shmem_parse_options(char *options, int *mode, uid_t *uid, 2039static int shmem_parse_options(char *options, int *mode, uid_t *uid,
1960 gid_t *gid, unsigned long *blocks, unsigned long *inodes, 2040 gid_t *gid, unsigned long *blocks, unsigned long *inodes,
1961 int *policy, nodemask_t *policy_nodes) 2041 int *policy, nodemask_t *policy_nodes)
@@ -2128,6 +2208,7 @@ static int shmem_fill_super(struct super_block *sb,
2128 &inodes, &policy, &policy_nodes)) 2208 &inodes, &policy, &policy_nodes))
2129 return -EINVAL; 2209 return -EINVAL;
2130 } 2210 }
2211 sb->s_export_op = &shmem_export_ops;
2131#else 2212#else
2132 sb->s_flags |= MS_NOUSER; 2213 sb->s_flags |= MS_NOUSER;
2133#endif 2214#endif