From: Chris Mason <mason@suse.com>
To: linux-kernel@vger.kernel.org
Subject: [RFC] yet another knfsd-reiserfs patch
Date: Mon, 23 Apr 2001 10:45:14 -0400 [thread overview]
Message-ID: <244320000.988037114@tiny> (raw)
Hi guys,
This patch is not meant to replace Neil Brown's knfsd ops stuff, the
goal was to whip up something that had a chance of getting into 2.4.x,
and that might be usable by the AFS guys too. Neil's patch tries to
address a bunch of things that I didn't, and looks better for the
long run.
Anyway, the basic idea is the FS provides:
int fill_fh(struct dentry *, __u32 *fh, int size) ;
fills the array of ints in fh with enough info to find the file and
its parent later.
struct inode *inode_from_fh(struct super_block *, __u32 *fh, int size) ;
struct inode *parent_from_fh(struct super_block *, __u32 *fh, int size) ;
iget the inode or parent directory inode based on data in the array.
Default ops are provided, the other filesystems should work the
same as before. Anyway, please take a look.
-chris
# This is a BitKeeper generated patch for the following project:
# Project Name: local kernel tree
# This patch format is intended for GNU patch command version 2.5 or higher.
# This patch includes the following deltas:
# ChangeSet 1.6 -> 1.7
# fs/reiserfs/super.c 1.1 -> 1.2
# fs/nfsd/nfsfh.c 1.1 -> 1.2
# include/linux/fs.h 1.2 -> 1.3
# fs/reiserfs/inode.c 1.1 -> 1.2
# include/linux/reiserfs_fs.h 1.1 -> 1.2
#
# The following is the BitKeeper ChangeSet Log
# --------------------------------------------
# 01/04/23 mason@suse.com 1.7
# reiserfs-knfsd-fh-ops-2
#
# Introduce file handle operations into the super ops. Add generic support and
# reiserfs support. Meant for use by NFS (and perhaps AFS) to get around
# reiserfs' inability to find a file with an inode number alone.
#
# fs.h reiserfs-knfsd-fh-ops-2
# reiserfs_fs.h reiserfs-knfsd-fh-ops-2
# nfsfh.c reiserfs-knfsd-fh-ops-2
# super.c reiserfs-knfsd-fh-ops-2
# inode.c reiserfs-knfsd-fh-ops-2
# --------------------------------------------
#
diff -Nru a/fs/nfsd/nfsfh.c b/fs/nfsd/nfsfh.c
--- a/fs/nfsd/nfsfh.c Mon Apr 23 02:14:42 2001
+++ b/fs/nfsd/nfsfh.c Mon Apr 23 02:14:42 2001
@@ -116,40 +116,12 @@
return error;
}
-/* this should be provided by each filesystem in an nfsd_operations interface as
- * iget isn't really the right interface
- */
-static struct dentry *nfsd_iget(struct super_block *sb, unsigned long ino, __u32 generation)
+static struct dentry *dentry_from_inode(struct inode *inode)
{
-
- /* iget isn't really right if the inode is currently unallocated!!
- * This should really all be done inside each filesystem
- *
- * ext2fs' read_inode has been strengthed to return a bad_inode if the inode
- * had been deleted.
- *
- * Currently we don't know the generation for parent directory, so a generation
- * of 0 means "accept any"
- */
- struct inode *inode;
struct list_head *lp;
struct dentry *result;
- inode = iget(sb, ino);
- if (is_bad_inode(inode)
- || (generation && inode->i_generation != generation)
- ) {
- /* we didn't find the right inode.. */
- dprintk("fh_verify: Inode %lu, Bad count: %d %d or version %u %u\n",
- inode->i_ino,
- inode->i_nlink, atomic_read(&inode->i_count),
- inode->i_generation,
- generation);
-
- iput(inode);
- return ERR_PTR(-ESTALE);
- }
- /* now to find a dentry.
- * If possible, get a well-connected one
+ /*
+ * If possible, get a well-connected dentry
*/
spin_lock(&dcache_lock);
for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) {
@@ -172,6 +144,92 @@
return result;
}
+static struct inode *__inode_from_fh(struct super_block *sb, int ino,
+ int generation)
+{
+ struct inode *inode ;
+
+ inode = iget(sb, ino);
+ if (is_bad_inode(inode)
+ || (generation && inode->i_generation != generation)
+ ) {
+ /* we didn't find the right inode.. */
+ dprintk("fh_verify: Inode %lu, Bad count: %d %d or version %u %u\n",
+ inode->i_ino,
+ inode->i_nlink, atomic_read(&inode->i_count),
+ inode->i_generation,
+ generation);
+
+ iput(inode);
+ return ERR_PTR(-ESTALE);
+ }
+ return inode ;
+}
+
+static struct inode *inode_from_fh(struct super_block *sb,
+ __u32 *datap,
+ int len)
+{
+ if (sb->s_op->inode_from_fh)
+ return sb->s_op->inode_from_fh(sb, datap, len) ;
+ return __inode_from_fh(sb, datap[0], datap[1]) ;
+}
+
+static struct inode *parent_from_fh(struct super_block *sb,
+ __u32 *datap,
+ int len)
+{
+ if (sb->s_op->parent_from_fh)
+ return sb->s_op->parent_from_fh(sb, datap, len) ;
+
+ if (len >= 3)
+ return __inode_from_fh(sb, datap[2], 0) ;
+ return ERR_PTR(-ESTALE);
+}
+
+/*
+ * two iget funcs, one for inode, and one for parent directory
+ *
+ * this should be provided by each filesystem in an nfsd_operations interface as
+ * iget isn't really the right interface
+ *
+ * If the filesystem doesn't provide funcs to get inodes from datap,
+ * it must be: inum, generation, dir inum. Length of 2 means the
+ * dir inum isn't there.
+ *
+ * iget isn't really right if the inode is currently unallocated!!
+ * This should really all be done inside each filesystem
+ *
+ * ext2fs' read_inode has been strengthed to return a bad_inode if the inode
+ * had been deleted.
+ *
+ * Currently we don't know the generation for parent directory, so a generation
+ * of 0 means "accept any"
+ */
+static struct dentry *nfsd_iget(struct super_block *sb, __u32 *datap, int len)
+{
+
+ struct inode *inode;
+
+ inode = inode_from_fh(sb, datap, len) ;
+ if (IS_ERR(inode)) {
+ return ERR_PTR(PTR_ERR(inode)) ;
+ }
+ return dentry_from_inode(inode) ;
+}
+
+static struct dentry *nfsd_parent_iget(struct super_block *sb, __u32 *datap,
+ int len)
+{
+ struct inode *inode;
+
+ inode = parent_from_fh(sb, datap, len) ;
+ if (IS_ERR(inode)) {
+ return ERR_PTR(PTR_ERR(inode)) ;
+ }
+ return dentry_from_inode(inode) ;
+}
+
/* this routine links an IS_ROOT dentry into the dcache tree. It gains "parent"
* as a parent and "name" as a name
* It should possibly go in dcache.c
@@ -339,9 +397,13 @@
* We use nfsd_iget and if that doesn't return a suitably connected dentry,
* we try to find the parent, and the parent of that and so-on until a
* connection if made.
+ *
+ * If the filesystem doesn't provide funcs to get inodes from datap,
+ * it must be: inum, generation, dir inum. Length of 2 means the
+ * dir inum isn't there.
*/
static struct dentry *
-find_fh_dentry(struct super_block *sb, ino_t ino, int generation, ino_t dirino, int needpath)
+find_fh_dentry(struct super_block *sb, __u32 *datap, int len, int needpath)
{
struct dentry *dentry, *result = NULL;
struct dentry *tmp;
@@ -361,7 +423,7 @@
*/
retry:
down(&sb->s_nfsd_free_path_sem);
- result = nfsd_iget(sb, ino, generation);
+ result = nfsd_iget(sb, datap, len) ;
if (IS_ERR(result)
|| !(result->d_flags & DCACHE_NFSD_DISCONNECTED)
|| (!S_ISDIR(result->d_inode->i_mode) && ! needpath)) {
@@ -378,37 +440,36 @@
/* It's a directory, or we are required to confirm the file's
* location in the tree.
*/
- dprintk("nfs_fh: need to look harder for %d/%ld\n",sb->s_dev,ino);
+ dprintk("nfs_fh: need to look harder for %d/%ld\n",sb->s_dev,result->d_inode->i_ino);
found = 0;
if (!S_ISDIR(result->d_inode->i_mode)) {
nfsdstats.fh_nocache_nondir++;
- if (dirino == 0)
- goto err_result; /* don't know how to find parent */
- else {
- /* need to iget dirino and make sure this inode is in that directory */
- dentry = nfsd_iget(sb, dirino, 0);
- err = PTR_ERR(dentry);
- if (IS_ERR(dentry))
- goto err_result;
- err = -ESTALE;
- if (!dentry->d_inode
- || !S_ISDIR(dentry->d_inode->i_mode)) {
- goto err_dentry;
- }
- if (!(dentry->d_flags & DCACHE_NFSD_DISCONNECTED))
- found = 1;
- tmp = splice(result, dentry);
- err = PTR_ERR(tmp);
- if (IS_ERR(tmp))
- goto err_dentry;
- if (tmp != result) {
- /* it is safe to just use tmp instead, but we must discard result first */
- d_drop(result);
- dput(result);
- result = tmp;
- /* If !found, then this is really wierd, but it shouldn't hurt */
- }
+ /* need to iget dirino and make sure this inode is in that
+ * directory . nfsd_parent_iget returns -ESTALE when the
+ * parent directory inum wasn't provided
+ */
+ dentry = nfsd_parent_iget(sb, datap, len) ;
+ err = PTR_ERR(dentry);
+ if (IS_ERR(dentry))
+ goto err_result;
+ err = -ESTALE;
+ if (!dentry->d_inode
+ || !S_ISDIR(dentry->d_inode->i_mode)) {
+ goto err_dentry;
+ }
+ if (!(dentry->d_flags & DCACHE_NFSD_DISCONNECTED))
+ found = 1;
+ tmp = splice(result, dentry);
+ err = PTR_ERR(tmp);
+ if (IS_ERR(tmp))
+ goto err_dentry;
+ if (tmp != result) {
+ /* it is safe to just use tmp instead, but we must discard result first */
+ d_drop(result);
+ dput(result);
+ result = tmp;
+ /* If !found, then this is really wierd, but it shouldn't hurt */
}
} else {
nfsdstats.fh_nocache_dir++;
@@ -577,24 +638,36 @@
case 1:
if ((data_left-=2)<0) goto out;
dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
- datap[0], datap[1],
- 0,
+ datap, 2,
!(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
break;
case 2:
+ /* NOTE, I'm overloading case 2 right now
+ * for both completely filesystem controlled
+ * and the standard filehandle. This means
+ * we might be using more than 3 ints in
+ * datap, and data_left might not be correct
+ * after this call.
+ *
+ * This looks ok right now, but needs to be
+ * fixed long term. It also means that
+ * if the FS stores things differently than
+ * the defaults, it can't use length < 4.
+ */
if ((data_left-=3)<0) goto out;
dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
- datap[0], datap[1],
- datap[2],
+ datap, 3 + data_left,
!(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
break;
default: goto out;
}
} else {
-
+ __u32 tmp[3] ;
+ tmp[0] = fh->ofh_ino ;
+ tmp[1] = fh->ofh_generation ;
+ tmp[2] = fh->ofh_dirino ;
dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
- fh->ofh_ino, fh->ofh_generation,
- fh->ofh_dirino,
+ tmp, 3,
!(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
}
if (IS_ERR(dentry)) {
@@ -703,9 +776,18 @@
__u32 **datapp, int maxsize)
{
__u32 *datap= *datapp;
+ struct super_block *sb = dentry->d_inode->i_sb ;
+
if (dentry == exp->ex_dentry)
return 0;
- /* if super_operations provides dentry_to_fh lookup, should use that */
+
+ /* use the provided FS provide func to fill the handle */
+ if (sb->s_op->fill_fh) {
+ int used ;
+ used = sb->s_op->fill_fh(dentry, datap, maxsize/sizeof(__u32)) ;
+ *datapp = datap + used ;
+ return 2 ;
+ }
*datap++ = ino_t_to_u32(dentry->d_inode->i_ino);
*datap++ = dentry->d_inode->i_generation;
diff -Nru a/fs/reiserfs/inode.c b/fs/reiserfs/inode.c
--- a/fs/reiserfs/inode.c Mon Apr 23 02:14:42 2001
+++ b/fs/reiserfs/inode.c Mon Apr 23 02:14:42 2001
@@ -1160,7 +1160,7 @@
return;
}
if (retval != ITEM_FOUND) {
- reiserfs_warning ("vs-13042: reiserfs_read_inode2: %K not found\n", &key);
+ /* a stale NFS handle can trigger this without it being an error */
pathrelse (&path_to_sd);
make_bad_inode(inode) ;
return;
@@ -1182,15 +1182,76 @@
if (!inode)
return inode ;
- // if (comp_short_keys (INODE_PKEY (inode), key)) {
- if (is_bad_inode (inode)) {
- reiserfs_warning ("vs-13048: reiserfs_iget: "
- "bad_inode. Stat data of (%lu %lu) not found\n",
- key->on_disk_key.k_dir_id, key->on_disk_key.k_objectid);
+ if (comp_short_keys (INODE_PKEY (inode), key) || is_bad_inode (inode)) {
+ /* either due to i/o error or a stale NFS handle */
iput (inode);
inode = 0;
}
return inode;
+}
+
+struct inode *reiserfs_inode_from_fh(struct super_block *sb, __u32 *data,
+ int len) {
+ struct cpu_key key ;
+ struct inode *inode = NULL ;
+
+ if (len < 2)
+ goto out ;
+
+ /* this works for handles from old kernels because the default
+ ** reiserfs generation number is the packing locality.
+ */
+ key.on_disk_key.k_objectid = data[0] ;
+ key.on_disk_key.k_dir_id = data[1] ;
+ inode = reiserfs_iget(sb, &key) ;
+
+out:
+ if (!inode)
+ return ERR_PTR(-ESTALE) ;
+ return inode ;
+}
+
+struct inode *reiserfs_parent_from_fh(struct super_block *sb, __u32 *data,
+ int len) {
+ struct cpu_key key ;
+ struct inode *inode ;
+
+ /*
+ ** Make sure the handle was long enough to store the parent directory
+ ** information. This also handles the case where an old
+ ** kernel (no filehandle interface) setup this filehandle, they use
+ ** a length of 3. Either way, we don't have enough info to find the
+ ** directory.
+ */
+ if (len < 4)
+ return ERR_PTR(-ESTALE) ;
+
+ key.on_disk_key.k_objectid = data[2] ;
+ key.on_disk_key.k_dir_id = data[3] ;
+ inode = reiserfs_iget(sb, &key) ;
+
+ if (!inode)
+ return ERR_PTR(-ESTALE) ;
+ return inode ;
+}
+
+int reiserfs_fill_fh(struct dentry *dentry, __u32 *data, int maxlen) {
+ struct inode *inode = dentry->d_inode ;
+
+ if (maxlen < 2)
+ return -ENOMEM ;
+
+ data[0] = inode->i_ino ;
+ data[1] = le32_to_cpu(INODE_PKEY (inode)->k_dir_id) ;
+
+ /* no room for directory info? return what we've stored so far */
+ if (maxlen < 4)
+ return 2 ;
+
+ inode = dentry->d_parent->d_inode ;
+ data[2] = inode->i_ino ;
+ data[3] = le32_to_cpu(INODE_PKEY (inode)->k_dir_id) ;
+ return 4;
}
diff -Nru a/fs/reiserfs/super.c b/fs/reiserfs/super.c
--- a/fs/reiserfs/super.c Mon Apr 23 02:14:42 2001
+++ b/fs/reiserfs/super.c Mon Apr 23 02:14:42 2001
@@ -147,7 +147,9 @@
unlockfs: reiserfs_unlockfs,
statfs: reiserfs_statfs,
remount_fs: reiserfs_remount,
-
+ fill_fh: reiserfs_fill_fh,
+ inode_from_fh: reiserfs_inode_from_fh,
+ parent_from_fh: reiserfs_parent_from_fh,
};
/* this was (ext2)parse_options */
diff -Nru a/include/linux/fs.h b/include/linux/fs.h
--- a/include/linux/fs.h Mon Apr 23 02:14:42 2001
+++ b/include/linux/fs.h Mon Apr 23 02:14:42 2001
@@ -822,6 +822,9 @@
int (*remount_fs) (struct super_block *, int *, char *);
void (*clear_inode) (struct inode *);
void (*umount_begin) (struct super_block *);
+ int (*fill_fh) (struct dentry *, __u32 *fh, int size);
+ struct inode * (*inode_from_fh) (struct super_block *, __u32 *, int);
+ struct inode * (*parent_from_fh) (struct super_block *, __u32 *, int);
};
/* Inode state bits.. */
diff -Nru a/include/linux/reiserfs_fs.h b/include/linux/reiserfs_fs.h
--- a/include/linux/reiserfs_fs.h Mon Apr 23 02:14:42 2001
+++ b/include/linux/reiserfs_fs.h Mon Apr 23 02:14:42 2001
@@ -1806,6 +1806,11 @@
extern int reiserfs_notify_change(struct dentry * dentry, struct iattr * attr);
void reiserfs_write_inode (struct inode * inode, int) ;
+/* nfs support funcs */
+int reiserfs_fill_fh(struct dentry *, __u32 *fh, int size);
+struct inode *reiserfs_inode_from_fh(struct super_block *, __u32 *, int);
+struct inode *reiserfs_parent_from_fh(struct super_block *, __u32 *, int);
+
/* we don't mark inodes dirty, we just log them */
void reiserfs_dirty_inode (struct inode * inode) ;
next reply other threads:[~2001-04-23 14:45 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2001-04-23 14:45 Chris Mason [this message]
2001-05-01 1:18 ` [RFC] yet another knfsd-reiserfs patch Chris Mason
2001-06-01 21:20 ` Chris Mason
2001-06-01 22:19 ` [NFS] " Trond Myklebust
2001-06-02 17:00 ` Chris Mason
2001-06-02 6:17 ` Hans Reiser
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=244320000.988037114@tiny \
--to=mason@suse.com \
--cc=linux-kernel@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.