xfs
[Top] [All Lists]

Cleaned up the open_by_handle code in xfs/linux/xfs_ioctl.c

To: linux-xfs@xxxxxxxxxxx
Subject: Cleaned up the open_by_handle code in xfs/linux/xfs_ioctl.c
From: William L Jones <jones@xxxxxxxxxxxxxxxxxx>
Date: Sat, 19 Aug 2000 16:14:09 -0500 (CDT)
Sender: owner-linux-xfs@xxxxxxxxxxx
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;
  }
  
  

<Prev in Thread] Current Thread [Next in Thread>
  • Cleaned up the open_by_handle code in xfs/linux/xfs_ioctl.c, William L Jones <=