Merge git://oss.sgi.com:8090/xfs/xfs-2.6
[linux-drm-fsl-dcu.git] / fs / xfs / xfs_vnodeops.c
index 00a6b7dc24a0a6ed047999b85f4eeca4f1494d1f..52c41714ec54c5a76cb5dbfe16a51233e44bf85f 100644 (file)
@@ -51,7 +51,6 @@
 #include "xfs_refcache.h"
 #include "xfs_trans_space.h"
 #include "xfs_log_priv.h"
-#include "xfs_mac.h"
 
 STATIC int
 xfs_open(
@@ -1013,7 +1012,7 @@ xfs_readlink(
        pathlen = (int)ip->i_d.di_size;
 
        if (ip->i_df.if_flags & XFS_IFINLINE) {
-               error = uio_read(ip->i_df.if_u1.if_data, pathlen, uiop);
+               error = xfs_uio_read(ip->i_df.if_u1.if_data, pathlen, uiop);
        }
        else {
                /*
@@ -1044,7 +1043,7 @@ xfs_readlink(
                                byte_cnt = pathlen;
                        pathlen -= byte_cnt;
 
-                       error = uio_read(XFS_BUF_PTR(bp), byte_cnt, uiop);
+                       error = xfs_uio_read(XFS_BUF_PTR(bp), byte_cnt, uiop);
                        xfs_buf_relse (bp);
                }
 
@@ -1381,7 +1380,7 @@ xfs_inactive_symlink_rmt(
        /*
         * Commit the first transaction.  This logs the EFI and the inode.
         */
-       if ((error = xfs_bmap_finish(&tp, &free_list, first_block, &committed)))
+       if ((error = xfs_bmap_finish(&tp, &free_list, &committed)))
                goto error1;
        /*
         * The transaction must have been committed, since there were
@@ -1790,8 +1789,7 @@ xfs_inactive(
                 * Just ignore errors at this point.  There is
                 * nothing we can do except to try to keep going.
                 */
-               (void) xfs_bmap_finish(&tp,  &free_list, first_block,
-                                      &committed);
+               (void) xfs_bmap_finish(&tp,  &free_list, &committed);
                (void) xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
        }
        /*
@@ -2022,7 +2020,7 @@ xfs_create(
        IHOLD(ip);
        vp = XFS_ITOV(ip);
 
-       error = xfs_bmap_finish(&tp, &free_list, first_block, &committed);
+       error = xfs_bmap_finish(&tp, &free_list, &committed);
        if (error) {
                xfs_bmap_cancel(&free_list);
                goto abort_rele;
@@ -2366,10 +2364,15 @@ xfs_remove(
 
        namelen = VNAMELEN(dentry);
 
+       if (!xfs_get_dir_entry(dentry, &ip)) {
+               dm_di_mode = ip->i_d.di_mode;
+               IRELE(ip);
+       }
+
        if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) {
                error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE, dir_vp,
                                        DM_RIGHT_NULL, NULL, DM_RIGHT_NULL,
-                                       name, NULL, 0, 0, 0);
+                                       name, NULL, dm_di_mode, 0, 0);
                if (error)
                        return error;
        }
@@ -2502,7 +2505,7 @@ xfs_remove(
                xfs_trans_set_sync(tp);
        }
 
-       error = xfs_bmap_finish(&tp, &free_list, first_block, &committed);
+       error = xfs_bmap_finish(&tp, &free_list, &committed);
        if (error) {
                REMOVE_DEBUG_TRACE(__LINE__);
                goto error_rele;
@@ -2603,8 +2606,7 @@ xfs_link(
        vn_trace_entry(src_vp, __FUNCTION__, (inst_t *)__return_address);
 
        target_namelen = VNAMELEN(dentry);
-       if (VN_ISDIR(src_vp))
-               return XFS_ERROR(EPERM);
+       ASSERT(!VN_ISDIR(src_vp));
 
        sip = xfs_vtoi(src_vp);
        tdp = XFS_BHVTOI(target_dir_bdp);
@@ -2699,9 +2701,8 @@ xfs_link(
        xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
 
        error = xfs_bumplink(tp, sip);
-       if (error) {
+       if (error)
                goto abort_return;
-       }
 
        /*
         * If this is a synchronous mount, make sure that the
@@ -2712,16 +2713,15 @@ xfs_link(
                xfs_trans_set_sync(tp);
        }
 
-       error = xfs_bmap_finish (&tp, &free_list, first_block, &committed);
+       error = xfs_bmap_finish (&tp, &free_list, &committed);
        if (error) {
                xfs_bmap_cancel(&free_list);
                goto abort_return;
        }
 
        error = xfs_trans_commit(tp, XFS_TRANS_RELEASE_LOG_RES, NULL);
-       if (error) {
+       if (error)
                goto std_return;
-       }
 
        /* Fall through to std_return with error = 0. */
 std_return:
@@ -2742,6 +2742,8 @@ std_return:
        xfs_trans_cancel(tp, cancel_flags);
        goto std_return;
 }
+
+
 /*
  * xfs_mkdir
  *
@@ -2928,7 +2930,7 @@ xfs_mkdir(
                xfs_trans_set_sync(tp);
        }
 
-       error = xfs_bmap_finish(&tp, &free_list, first_block, &committed);
+       error = xfs_bmap_finish(&tp, &free_list, &committed);
        if (error) {
                IRELE(cdp);
                goto error2;
@@ -2996,7 +2998,7 @@ xfs_rmdir(
        int                     cancel_flags;
        int                     committed;
        bhv_vnode_t             *dir_vp;
-       int                     dm_di_mode = 0;
+       int                     dm_di_mode = S_IFDIR;
        int                     last_cdp_link;
        int                     namelen;
        uint                    resblks;
@@ -3011,11 +3013,16 @@ xfs_rmdir(
                return XFS_ERROR(EIO);
        namelen = VNAMELEN(dentry);
 
+       if (!xfs_get_dir_entry(dentry, &cdp)) {
+               dm_di_mode = cdp->i_d.di_mode;
+               IRELE(cdp);
+       }
+
        if (DM_EVENT_ENABLED(dir_vp->v_vfsp, dp, DM_EVENT_REMOVE)) {
                error = XFS_SEND_NAMESP(mp, DM_EVENT_REMOVE,
                                        dir_vp, DM_RIGHT_NULL,
                                        NULL, DM_RIGHT_NULL,
-                                       name, NULL, 0, 0, 0);
+                                       name, NULL, dm_di_mode, 0, 0);
                if (error)
                        return XFS_ERROR(error);
        }
@@ -3174,7 +3181,7 @@ xfs_rmdir(
                xfs_trans_set_sync(tp);
        }
 
-       error = xfs_bmap_finish (&tp, &free_list, first_block, &committed);
+       error = xfs_bmap_finish (&tp, &free_list, &committed);
        if (error) {
                xfs_bmap_cancel(&free_list);
                xfs_trans_cancel(tp, (XFS_TRANS_RELEASE_LOG_RES |
@@ -3524,7 +3531,7 @@ xfs_symlink(
         */
        IHOLD(ip);
 
-       error = xfs_bmap_finish(&tp, &free_list, first_block, &committed);
+       error = xfs_bmap_finish(&tp, &free_list, &committed);
        if (error) {
                goto error2;
        }
@@ -3818,11 +3825,16 @@ xfs_reclaim(
         */
        xfs_synchronize_atime(ip);
 
-       /* If we have nothing to flush with this inode then complete the
-        * teardown now, otherwise break the link between the xfs inode
-        * and the linux inode and clean up the xfs inode later. This
-        * avoids flushing the inode to disk during the delete operation
-        * itself.
+       /*
+        * If we have nothing to flush with this inode then complete the
+        * teardown now, otherwise break the link between the xfs inode and the
+        * linux inode and clean up the xfs inode later. This avoids flushing
+        * the inode to disk during the delete operation itself.
+        *
+        * When breaking the link, we need to set the XFS_IRECLAIMABLE flag
+        * first to ensure that xfs_iunpin() will never see an xfs inode
+        * that has a linux inode being reclaimed. Synchronisation is provided
+        * by the i_flags_lock.
         */
        if (!ip->i_update_core && (ip->i_itemp == NULL)) {
                xfs_ilock(ip, XFS_ILOCK_EXCL);
@@ -3831,11 +3843,13 @@ xfs_reclaim(
        } else {
                xfs_mount_t     *mp = ip->i_mount;
 
-               /* Protect sync from us */
+               /* Protect sync and unpin from us */
                XFS_MOUNT_ILOCK(mp);
+               spin_lock(&ip->i_flags_lock);
+               __xfs_iflags_set(ip, XFS_IRECLAIMABLE);
                vn_bhv_remove(VN_BHV_HEAD(vp), XFS_ITOBHV(ip));
+               spin_unlock(&ip->i_flags_lock);
                list_add_tail(&ip->i_reclaim, &mp->m_del_inodes);
-               ip->i_flags |= XFS_IRECLAIMABLE;
                XFS_MOUNT_IUNLOCK(mp);
        }
        return 0;
@@ -3860,8 +3874,10 @@ xfs_finish_reclaim(
         * us.
         */
        write_lock(&ih->ih_lock);
-       if ((ip->i_flags & XFS_IRECLAIM) ||
-           (!(ip->i_flags & XFS_IRECLAIMABLE) && vp == NULL)) {
+       spin_lock(&ip->i_flags_lock);
+       if (__xfs_iflags_test(ip, XFS_IRECLAIM) ||
+           (!__xfs_iflags_test(ip, XFS_IRECLAIMABLE) && vp == NULL)) {
+               spin_unlock(&ip->i_flags_lock);
                write_unlock(&ih->ih_lock);
                if (locked) {
                        xfs_ifunlock(ip);
@@ -3869,7 +3885,8 @@ xfs_finish_reclaim(
                }
                return 1;
        }
-       ip->i_flags |= XFS_IRECLAIM;
+       __xfs_iflags_set(ip, XFS_IRECLAIM);
+       spin_unlock(&ip->i_flags_lock);
        write_unlock(&ih->ih_lock);
 
        /*
@@ -4126,7 +4143,7 @@ retry:
                /*
                 * Complete the transaction
                 */
-               error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed);
+               error = xfs_bmap_finish(&tp, &free_list, &committed);
                if (error) {
                        goto error0;
                }
@@ -4273,7 +4290,7 @@ xfs_free_file_space(
        xfs_mount_t             *mp;
        int                     nimap;
        uint                    resblks;
-       int                     rounding;
+       uint                    rounding;
        int                     rt;
        xfs_fileoff_t           startoffset_fsb;
        xfs_trans_t             *tp;
@@ -4314,8 +4331,7 @@ xfs_free_file_space(
                vn_iowait(vp);  /* wait for the completion of any pending DIOs */
        }
 
-       rounding = MAX((__uint8_t)(1 << mp->m_sb.sb_blocklog),
-                       (__uint8_t)NBPP);
+       rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, NBPP);
        ilen = len + (offset & (rounding - 1));
        ioffset = offset & ~(rounding - 1);
        if (ilen & (rounding - 1))
@@ -4434,7 +4450,7 @@ xfs_free_file_space(
                /*
                 * complete the transaction
                 */
-               error = xfs_bmap_finish(&tp, &free_list, firstfsb, &committed);
+               error = xfs_bmap_finish(&tp, &free_list, &committed);
                if (error) {
                        goto error0;
                }