|
@@ -1362,6 +1362,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
|
|
|
inode->i_mapping->a_ops = &shmem_aops;
|
|
|
inode->i_mapping->backing_dev_info = &shmem_backing_dev_info;
|
|
|
inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
|
|
|
+ inode->i_generation = get_seconds();
|
|
|
info = SHMEM_I(inode);
|
|
|
memset(info, 0, (char *)inode - (char *)info);
|
|
|
spin_lock_init(&info->lock);
|
|
@@ -1956,6 +1957,85 @@ static struct xattr_handler *shmem_xattr_handlers[] = {
|
|
|
};
|
|
|
#endif
|
|
|
|
|
|
+static struct dentry *shmem_get_parent(struct dentry *child)
|
|
|
+{
|
|
|
+ return ERR_PTR(-ESTALE);
|
|
|
+}
|
|
|
+
|
|
|
+static int shmem_match(struct inode *ino, void *vfh)
|
|
|
+{
|
|
|
+ __u32 *fh = vfh;
|
|
|
+ __u64 inum = fh[2];
|
|
|
+ inum = (inum << 32) | fh[1];
|
|
|
+ return ino->i_ino == inum && fh[0] == ino->i_generation;
|
|
|
+}
|
|
|
+
|
|
|
+static struct dentry *shmem_get_dentry(struct super_block *sb, void *vfh)
|
|
|
+{
|
|
|
+ struct dentry *de = NULL;
|
|
|
+ struct inode *inode;
|
|
|
+ __u32 *fh = vfh;
|
|
|
+ __u64 inum = fh[2];
|
|
|
+ inum = (inum << 32) | fh[1];
|
|
|
+
|
|
|
+ inode = ilookup5(sb, (unsigned long)(inum+fh[0]), shmem_match, vfh);
|
|
|
+ if (inode) {
|
|
|
+ de = d_find_alias(inode);
|
|
|
+ iput(inode);
|
|
|
+ }
|
|
|
+
|
|
|
+ return de? de: ERR_PTR(-ESTALE);
|
|
|
+}
|
|
|
+
|
|
|
+static struct dentry *shmem_decode_fh(struct super_block *sb, __u32 *fh,
|
|
|
+ int len, int type,
|
|
|
+ int (*acceptable)(void *context, struct dentry *de),
|
|
|
+ void *context)
|
|
|
+{
|
|
|
+ if (len < 3)
|
|
|
+ return ERR_PTR(-ESTALE);
|
|
|
+
|
|
|
+ return sb->s_export_op->find_exported_dentry(sb, fh, NULL, acceptable,
|
|
|
+ context);
|
|
|
+}
|
|
|
+
|
|
|
+static int shmem_encode_fh(struct dentry *dentry, __u32 *fh, int *len,
|
|
|
+ int connectable)
|
|
|
+{
|
|
|
+ struct inode *inode = dentry->d_inode;
|
|
|
+
|
|
|
+ if (*len < 3)
|
|
|
+ return 255;
|
|
|
+
|
|
|
+ if (hlist_unhashed(&inode->i_hash)) {
|
|
|
+ /* Unfortunately insert_inode_hash is not idempotent,
|
|
|
+ * so as we hash inodes here rather than at creation
|
|
|
+ * time, we need a lock to ensure we only try
|
|
|
+ * to do it once
|
|
|
+ */
|
|
|
+ static DEFINE_SPINLOCK(lock);
|
|
|
+ spin_lock(&lock);
|
|
|
+ if (hlist_unhashed(&inode->i_hash))
|
|
|
+ __insert_inode_hash(inode,
|
|
|
+ inode->i_ino + inode->i_generation);
|
|
|
+ spin_unlock(&lock);
|
|
|
+ }
|
|
|
+
|
|
|
+ fh[0] = inode->i_generation;
|
|
|
+ fh[1] = inode->i_ino;
|
|
|
+ fh[2] = ((__u64)inode->i_ino) >> 32;
|
|
|
+
|
|
|
+ *len = 3;
|
|
|
+ return 1;
|
|
|
+}
|
|
|
+
|
|
|
+static struct export_operations shmem_export_ops = {
|
|
|
+ .get_parent = shmem_get_parent,
|
|
|
+ .get_dentry = shmem_get_dentry,
|
|
|
+ .encode_fh = shmem_encode_fh,
|
|
|
+ .decode_fh = shmem_decode_fh,
|
|
|
+};
|
|
|
+
|
|
|
static int shmem_parse_options(char *options, int *mode, uid_t *uid,
|
|
|
gid_t *gid, unsigned long *blocks, unsigned long *inodes,
|
|
|
int *policy, nodemask_t *policy_nodes)
|
|
@@ -2128,6 +2208,7 @@ static int shmem_fill_super(struct super_block *sb,
|
|
|
&inodes, &policy, &policy_nodes))
|
|
|
return -EINVAL;
|
|
|
}
|
|
|
+ sb->s_export_op = &shmem_export_ops;
|
|
|
#else
|
|
|
sb->s_flags |= MS_NOUSER;
|
|
|
#endif
|