[PATCH] NFS client handling of FIFOs.

Aaron Denney (wnoise@myxo.ugcs.caltech.edu)
Tue, 12 Jan 1999 04:31:12 -0800


Currently Linux uses an unused bit in the mode field to indicate a file
is a FIFO over NFS requests. Unfortunately no other unix uses this bit
to indicate a FIFO, instead they use a character device with the field
rdev set to 0xffffffff (checked on Solaris, HPUX, and IRIX; the comment
about not checking with tcpdump is out of date).

I have a patch that fixes this on the client side, but nothing
for either the userspace or kernel nfsd yet. (Soon I hope).

Fixing this to recognize both linux-style fifos, and traditional Unix
fifos is pretty simple, but getting it to create them properly is
impossible as we can't tell whether the server wants the fifo indicated
as a char device or with the unused mode bit. (Trying it with the
unused mode bit first, then failing to the char device might work on
some servers, as I did get errors on mknod() when the server was HPUX.
But I'm too lazy to implement that.) So, anyways this patch doesn't
allow you to create fifos on Linux servers.

The creation part of the patch is the dir.c patch; if you
don't apply it you will be able to create fifos on Linux servers,
but not on Unix servers.

Could someone with more experience in the NFS code comment?

The patch is against 2.2.0-pre6, hopefully your mailer hasn't wrapped the
lines.

-- 
Aaron Denney
-><-

Patch follows:

diff -urN linux-2.2.0-pre6/fs/nfs/dir.c linux-2.2.0-pre6-nfsfifo/fs/nfs/dir.c --- linux-2.2.0-pre6/fs/nfs/dir.c Tue Jan 12 00:28:01 1999 +++ linux-2.2.0-pre6-nfsfifo/fs/nfs/dir.c Tue Jan 12 02:57:56 1999 @@ -660,6 +660,32 @@ sattr.uid = sattr.gid = sattr.size = (unsigned) -1; if (S_ISCHR(mode) || S_ISBLK(mode)) sattr.size = rdev; /* get out your barf bag */ + /* luckily, NFS v2 uses the same bits for block and character + * devices as we do. */ +#if !defined NFS_FIFO_BROKEN + if (S_ISFIFO(mode)) + /* NFS v2 doesn't define a mode for FIFOs. + * Solaris uses a char device 0xffffffff for FIFOs. + * HPUX, IRIX use something which comes down to + * c (255, 255), I am assuming 0xffffffff truncated + * to -1 in 8 bits. I have yet to verify this with + * tcpdump. NFS v2 sucks, and nasty kluges like + * this don't help. This needs to be rewritten to + * work with V3. + * Note that we have to do the translations here, as + * we can't alter xdr_encode_sattr. Similarly, + * I decided not to have xdr_decode_fattr auto-translate + * mode. I should probably write nfs_mode_to_vfs() + * and its reverse (or at least NFS_ISFIFO(). See also + * nfs_fill_inode() + * Unfortunately this will cause fifo creation to break on + * current Linux servers. + * --Aaron Denney <wnoise@ugcs.caltech.edu> */ + sattr.size = 0xffffffff; /* Should use NFS_FIFO_DEV ? */ + sattr.mode &= ~S_IFIFO; + sattr.mode |= NFSMODE_CHR; +#endif + sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1; nfs_invalidate_dircache(dir); diff -urN linux-2.2.0-pre6/fs/nfs/inode.c linux-2.2.0-pre6-nfsfifo/fs/nfs/inode.c --- linux-2.2.0-pre6/fs/nfs/inode.c Tue Jan 12 01:16:14 1999 +++ linux-2.2.0-pre6-nfsfifo/fs/nfs/inode.c Tue Jan 12 02:57:17 1999 @@ -419,6 +419,15 @@ */ if (inode->i_mode == 0) { inode->i_mode = fattr->mode; +#if !defined NFS_FIFO_BROKEN + if ((inode->i_mode & NFSMODE_CHR) && + (fattr->rdev == NFS_FIFO_DEV)) { + inode->i_mode &= ~NFSMODE_CHR; + inode->i_mode |= S_IFIFO; + } + /* see notes in dir.c:nfs_mknod(). This should still allow + * using FIFOs on Linux servers. --Aaron Denney */ +#endif if (S_ISREG(inode->i_mode)) inode->i_op = &nfs_file_inode_operations; else if (S_ISDIR(inode->i_mode)) @@ -741,8 +750,18 @@ /* * Make sure the inode's type hasn't changed. */ +#if !defined NFS_FIFO_BROKEN + /* Ugh, special casing this. We need to do this consistently + * when comparing the NFS modes and the vfs modes. --Aaron */ + if (S_ISFIFO(inode->i_mode) && (fattr->mode & S_IFCHR) && (fattr->rdev == NFS_FIFO_DEV)) { + /* "correct" the fattr->mode to what vfs uses. */ + fattr->mode &= ~NFSMODE_CHR; + fattr->mode |= S_IFIFO; + } +#else /* NFS_FIFO_BROKEN */ if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT)) goto out_changed; +#endif inode->i_mode = fattr->mode; inode->i_nlink = fattr->nlink;

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/