The following is a patch to xfs_ioctl.c in fs/xfs/linux.
It use anonymous dcache entries like nfssd.
It use dentry_open from fs/open.c to do the mundane work of
creating a file entry.
I hope this will meke the code cleaner and easier to maintain and I think it
gets
rid of some potentially problems that can come about with the way nfsd use
dcache entries. It really needs will formed cache entries for files
and directories or for them to be anonymous so it can ignore them.
---------------------- cut here
-----------------------------------------------------
*** xfs_ioctl.c.orig Sat Aug 19 14:03:21 2000
--- xfs_ioctl.c Sat Aug 19 14:07:58 2000
***************
*** 295,325 ****
vfs_t *vfsp,
xfs_mount_t *mp)
{
- int i;
int error;
! int klocked = 0;
! int newfd = -1;
int permflag;
- char sname[(2 * MAXFIDSZ) + 1];
- char *cpi;
- char *cpo;
__u32 igen;
struct dentry *dentry = NULL;
! struct dentry *pardentry;
! struct file *filp;
struct inode *inode = NULL;
- struct qstr sqstr;
void *hanp;
size_t hlen;
! vnode_t *vp = NULL;
xfs_fid_t *xfid;
xfs_handle_t *handlep;
xfs_handle_t handle;
- xfs_ino_t ino;
- xfs_inode_t *ip = NULL;
xfs_fsop_handlereq_t hreq;
-
#ifndef PERMISSIONS_BY_USER
/*
* Only allow Sys Admin capable users.
--- 295,315 ----
vfs_t *vfsp,
xfs_mount_t *mp)
{
int error;
! int new_fd;
int permflag;
__u32 igen;
struct dentry *dentry = NULL;
! struct file *filp = NULL;
struct inode *inode = NULL;
void *hanp;
size_t hlen;
! ino_t ino;
xfs_fid_t *xfid;
xfs_handle_t *handlep;
xfs_handle_t handle;
xfs_fsop_handlereq_t hreq;
#ifndef PERMISSIONS_BY_USER
/*
* Only allow Sys Admin capable users.
***************
*** 377,387 ****
* Crack the handle, obtain the inode # & generation #
*/
- /*
- * handle_to_vp(&handle)
- * VFS_VGET (vfsp, &vp, &handlep->ha_fid, error)
- * bdp, **vp, fidp;
- */
xfid = (struct xfs_fid *)&handlep->ha_fid;
if (xfid->xfs_fid_len == sizeof(*xfid) - sizeof(xfid->xfs_fid_len)) {
--- 367,372 ----
***************
*** 395,617 ****
return -XFS_ERROR(EINVAL);
}
-
/*
! * Make a unique name for dcache.
*/
! cpi = (char *)handlep;
! cpo = sname;
!
! for (i = 0; i < hlen && i < MAXFIDSZ; i++) {
! sprintf(cpo, "%02x", *cpi);
!
! cpi++;
! cpo += 2;
}
- *cpo = '\0';
/*
! * Obtain/create a 'dentry'.
*/
! sqstr.name = sname;
! sqstr.len = 2 * hlen;
! sqstr.hash = full_name_hash(sname, hlen);
!
! pardentry = parfilp->f_dentry;
!
!
! down(&parinode->i_sem);
!
! dentry = d_lookup(pardentry, &sqstr); /* There already? */
! if (!dentry) {
! dentry = d_alloc(pardentry, &sqstr);
!
! if (! dentry) {
! up(&parinode->i_sem);
! return -ENOMEM;
! }
! }
!
! up(&parinode->i_sem);
! inode = dentry->d_inode;
!
/*
! * Get the XFS inode, building a vnode to go with it
*/
! error = xfs_iget(mp, NULL, inode?inode->i_ino:ino, XFS_ILOCK_SHARED,
&ip, 0);
!
! if (error) {
! error = -error;
!
! goto cleanup_dentry;
! }
!
! if (ip == NULL) {
! error = -XFS_ERROR(EIO);
!
! goto cleanup_dentry;
! }
!
! if (ip->i_d.di_mode == 0 || ip->i_d.di_gen != igen) {
!
! xfs_iput(ip, XFS_ILOCK_SHARED);
!
! error = -XFS_ERROR(ENOENT);
!
! goto cleanup_dentry;
! }
!
! vp = XFS_ITOV(ip);
!
! xfs_iunlock(ip, XFS_ILOCK_SHARED);
!
! if (inode == NULL) {
! inode = igrab(vp->v_inode);
!
! if (! inode) {
! error = -EACCES;
!
! VN_RELE(vp);
!
! goto cleanup_dentry;
! }
!
! /*
! * Set xfs inode ops.
! */
! linvfs_set_inode_ops(inode);
! d_add(dentry, inode);
! }
/*
* Restrict handle operations to directories & regular files.
! */
if (! (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)) ) {
!
! error = -XFS_ERROR(EINVAL);
!
! goto cleanup_dentry;
}
!
/*
! * Get a file descriptor # to use.
*/
! lock_kernel();
!
! klocked = 1;
!
! newfd = get_unused_fd();
!
! if (newfd < 0) {
! error = newfd;
!
! goto cleanup_dentry;
}
/*
! * Get a file table entry.
*/
! filp = get_empty_filp();
!
! if (! filp) {
! error = -ENFILE;
- goto cleanup_fd;
- }
-
- filp->f_flags = hreq.oflags;
-
- filp->f_mode = (hreq.oflags + 1) & O_ACCMODE;
-
- #ifdef PERMISSIONS_BY_USER
/*
! * Do permission/write checks
*/
! permflag = 0;
!
! if (filp->f_mode & FMODE_READ)
! permflag |= MAY_READ;
!
! if (filp->f_mode & FMODE_WRITE)
! permflag |= MAY_WRITE;
!
! if (error = permission(inode, permflag))
! goto cleanup_file;
!
! #endif /* PERMISSIONS_BY_USER */
!
! if (filp->f_mode & FMODE_WRITE) {
!
! if (vp->v_type == VDIR) { /* Can't write directories */
! error = -EISDIR;
!
! goto cleanup_file;
! }
!
! error = get_write_access(inode);
!
! if (error)
! goto cleanup_file;
! }
!
/*
! * Stitch it all together.
*/
! filp->f_dentry = dentry;
! filp->f_pos = 0;
! filp->f_reada = 0;
! filp->f_op = inode->i_fop;
!
!
!
! if (inode->i_sb)
! file_move(filp, &inode->i_sb->s_files);
!
! if (filp->f_op && filp->f_op->open) {
!
! error = filp->f_op->open(inode, filp);
! if (error)
! goto cleanup_all;
}
! filp->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
!
! if (klocked)
! unlock_kernel();
! klocked = 0;
!
! fd_install(newfd, filp);
!
! iput(inode);
! return newfd;
! cleanup_all:
! if (filp->f_mode & FMODE_WRITE)
! put_write_access(inode);
!
! cleanup_file:
! filp->f_dentry = NULL;
! put_filp(filp);
!
! cleanup_fd:
! if (newfd >= 0)
! put_unused_fd(newfd);
!
! cleanup_dentry:
! if (inode)
! iput(inode);
! dput(dentry);
! if (klocked)
! unlock_kernel();
! return error;
}
--- 380,501 ----
return -XFS_ERROR(EINVAL);
}
/*
! * Get the inode.
*/
! inode = iget(parfilp->f_dentry->d_inode->i_sb, ino);
! if (is_bad_inode(inode) ||
! igen != inode->i_generation) {
! iput(inode);
! return -XFS_ERROR(ENOENT);
}
/*
! * Why do we need to do this?
! * XFS_IOC_FSBULKSTAT_SINGLE does a xfs_iget on the inode
! * and puts it in the linux inode cache with out
! * calling linvfs_set_inode_ops. The next time
! * the linux iget is called on the inode it will find the inode in the
linux
! * cache so read_inode is not called and the inode ops field is never
! * initialized.
*/
! linvfs_set_inode_ops(inode);
/*
! * Fix the mode flags that linvfs_set_inode_ops bashes.
*/
! linvfs_revalidate_core(inode);
/*
* Restrict handle operations to directories & regular files.
! */
if (! (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode)) ) {
! iput(inode);
! return -XFS_ERROR(EINVAL);
! }
!
! /*
! * Put open permission in namei format.
! */
! permflag = hreq.oflags;
! if ((permflag+1) & O_ACCMODE)
! permflag++;
! if (permflag & O_TRUNC)
! permflag |= 2;
!
! /*
! * Can't write directories.
! */
! if ( S_ISDIR(inode->i_mode) && (permflag & FMODE_WRITE)) {
! iput(inode);
! return -XFS_ERROR(EISDIR);
! }
!
! /*
! * Create new_fd
! */
! if ((new_fd = get_unused_fd()) < 0) {
! iput(inode);
! return new_fd;
}
!
/*
! * Create anonymous dcache entry.
*/
! dentry = d_alloc_root(inode);
! if (dentry == NULL) {
! iput(inode);
! put_unused_fd(new_fd);
! return -XFS_ERROR(ENOMEM);
}
/*
! * Keep nfsd happy.
*/
! dentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
/*
! * Make sure dput can find this dcache entry.
*/
! d_rehash(dentry);
/*
! * Make sure umount returns an EBUSY on umounts while this file is
open.
*/
! mntget(parfilp->f_vfsmnt);
! /*
! * Create file pointer.
! */
! filp = dentry_open(dentry, parfilp->f_vfsmnt, hreq.oflags);
! if (IS_ERR(filp)) {
! put_unused_fd(new_fd);
! return -XFS_ERROR(-PTR_ERR(filp));
}
! #ifdef PERMISSIONS_BY_USER
! /*
! * Do permission/write checks
! */
! permflag = 0;
! if (filp->f_mode & FMODE_READ)
! permflag |= MAY_READ;
! if (filp->f_mode & FMODE_WRITE)
! permflag |= MAY_WRITE;
+ if (error = permission(inode, permflag)) {
+ put_unused_fd(new_fd);
+ fput(filp);
+ return -XFS_ERROR(-error);
! }
! #endif /* PERMISSIONS_BY_USER */
! fd_install(new_fd, filp);
! return new_fd;
}
|