[XFS] remove old vmap cache
[safe/jmp/linux-2.6] / fs / xfs / xfs_vnodeops.c
index 7fb577c..f07bf87 100644 (file)
 #include "xfs_vnodeops.h"
 
 int
-xfs_open(
-       xfs_inode_t     *ip)
-{
-       int             mode;
-
-       if (XFS_FORCED_SHUTDOWN(ip->i_mount))
-               return XFS_ERROR(EIO);
-
-       /*
-        * If it's a directory with any blocks, read-ahead block 0
-        * as we're almost certain to have the next operation be a read there.
-        */
-       if (S_ISDIR(ip->i_d.di_mode) && ip->i_d.di_nextents > 0) {
-               mode = xfs_ilock_map_shared(ip);
-               if (ip->i_d.di_nextents > 0)
-                       (void)xfs_da_reada_buf(NULL, ip, 0, XFS_DATA_FORK);
-               xfs_iunlock(ip, mode);
-       }
-       return 0;
-}
-
-int
 xfs_setattr(
        struct xfs_inode        *ip,
        struct iattr            *iattr,
-       int                     flags,
-       cred_t                  *credp)
+       int                     flags)
 {
        xfs_mount_t             *mp = ip->i_mount;
        struct inode            *inode = VFS_I(ip);
@@ -93,7 +70,6 @@ xfs_setattr(
        gid_t                   gid=0, igid=0;
        int                     timeflags = 0;
        struct xfs_dquot        *udqp, *gdqp, *olddquot1, *olddquot2;
-       int                     file_owner;
        int                     need_iolock = 1;
 
        xfs_itrace_entry(ip);
@@ -104,6 +80,10 @@ xfs_setattr(
        if (XFS_FORCED_SHUTDOWN(mp))
                return XFS_ERROR(EIO);
 
+       code = -inode_change_ok(inode, iattr);
+       if (code)
+               return code;
+
        olddquot1 = olddquot2 = NULL;
        udqp = gdqp = NULL;
 
@@ -181,62 +161,8 @@ xfs_setattr(
 
        xfs_ilock(ip, lock_flags);
 
-       /* boolean: are we the file owner? */
-       file_owner = (current_fsuid() == ip->i_d.di_uid);
-
-       /*
-        * Change various properties of a file.
-        * Only the owner or users with CAP_FOWNER
-        * capability may do these things.
-        */
-       if (mask & (ATTR_MODE|ATTR_UID|ATTR_GID)) {
-               /*
-                * CAP_FOWNER overrides the following restrictions:
-                *
-                * The user ID of the calling process must be equal
-                * to the file owner ID, except in cases where the
-                * CAP_FSETID capability is applicable.
-                */
-               if (!file_owner && !capable(CAP_FOWNER)) {
-                       code = XFS_ERROR(EPERM);
-                       goto error_return;
-               }
-
-               /*
-                * CAP_FSETID overrides the following restrictions:
-                *
-                * The effective user ID of the calling process shall match
-                * the file owner when setting the set-user-ID and
-                * set-group-ID bits on that file.
-                *
-                * The effective group ID or one of the supplementary group
-                * IDs of the calling process shall match the group owner of
-                * the file when setting the set-group-ID bit on that file
-                */
-               if (mask & ATTR_MODE) {
-                       mode_t m = 0;
-
-                       if ((iattr->ia_mode & S_ISUID) && !file_owner)
-                               m |= S_ISUID;
-                       if ((iattr->ia_mode & S_ISGID) &&
-                           !in_group_p((gid_t)ip->i_d.di_gid))
-                               m |= S_ISGID;
-#if 0
-                       /* Linux allows this, Irix doesn't. */
-                       if ((iattr->ia_mode & S_ISVTX) && !S_ISDIR(ip->i_d.di_mode))
-                               m |= S_ISVTX;
-#endif
-                       if (m && !capable(CAP_FSETID))
-                               iattr->ia_mode &= ~m;
-               }
-       }
-
        /*
         * Change file ownership.  Must be the owner or privileged.
-        * If the system was configured with the "restricted_chown"
-        * option, the owner is not permitted to give away the file,
-        * and can change the group id only to a group of which he
-        * or she is a member.
         */
        if (mask & (ATTR_UID|ATTR_GID)) {
                /*
@@ -251,23 +177,6 @@ xfs_setattr(
                uid = (mask & ATTR_UID) ? iattr->ia_uid : iuid;
 
                /*
-                * CAP_CHOWN overrides the following restrictions:
-                *
-                * If _POSIX_CHOWN_RESTRICTED is defined, this capability
-                * shall override the restriction that a process cannot
-                * change the user ID of a file it owns and the restriction
-                * that the group ID supplied to the chown() function
-                * shall be equal to either the group ID or one of the
-                * supplementary group IDs of the calling process.
-                */
-               if (restricted_chown &&
-                   (iuid != uid || (igid != gid &&
-                                    !in_group_p((gid_t)gid))) &&
-                   !capable(CAP_CHOWN)) {
-                       code = XFS_ERROR(EPERM);
-                       goto error_return;
-               }
-               /*
                 * Do a quota reservation only if uid/gid is actually
                 * going to change.
                 */
@@ -304,36 +213,22 @@ xfs_setattr(
                        code = XFS_ERROR(EINVAL);
                        goto error_return;
                }
+
                /*
                 * Make sure that the dquots are attached to the inode.
                 */
-               if ((code = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED)))
+               code = XFS_QM_DQATTACH(mp, ip, XFS_QMOPT_ILOCKED);
+               if (code)
                        goto error_return;
-       }
 
-       /*
-        * Change file access or modified times.
-        */
-       if (mask & (ATTR_ATIME|ATTR_MTIME)) {
-               if (!file_owner) {
-                       if ((mask & (ATTR_MTIME_SET|ATTR_ATIME_SET)) &&
-                           !capable(CAP_FOWNER)) {
-                               code = XFS_ERROR(EPERM);
-                               goto error_return;
-                       }
-               }
-       }
-
-       /*
-        * Now we can make the changes.  Before we join the inode
-        * to the transaction, if ATTR_SIZE is set then take care of
-        * the part of the truncation that must be done without the
-        * inode lock.  This needs to be done before joining the inode
-        * to the transaction, because the inode cannot be unlocked
-        * once it is a part of the transaction.
-        */
-       if (mask & ATTR_SIZE) {
-               code = 0;
+               /*
+                * Now we can make the changes.  Before we join the inode
+                * to the transaction, if ATTR_SIZE is set then take care of
+                * the part of the truncation that must be done without the
+                * inode lock.  This needs to be done before joining the inode
+                * to the transaction, because the inode cannot be unlocked
+                * once it is a part of the transaction.
+                */
                if (iattr->ia_size > ip->i_size) {
                        /*
                         * Do the first part of growing a file: zero any data
@@ -366,7 +261,7 @@ xfs_setattr(
                }
 
                /* wait for all I/O to complete */
-               vn_iowait(ip);
+               xfs_ioend_wait(ip);
 
                if (!code)
                        code = xfs_itruncate_data(ip, iattr->ia_size);
@@ -388,17 +283,10 @@ xfs_setattr(
                }
                commit_flags = XFS_TRANS_RELEASE_LOG_RES;
                xfs_ilock(ip, XFS_ILOCK_EXCL);
-       }
 
-       if (tp) {
                xfs_trans_ijoin(tp, ip, lock_flags);
                xfs_trans_ihold(tp, ip);
-       }
 
-       /*
-        * Truncate file.  Must have write permission and not be a directory.
-        */
-       if (mask & ATTR_SIZE) {
                /*
                 * Only change the c/mtime if we are changing the size
                 * or we are explicitly asked to change it. This handles
@@ -438,28 +326,13 @@ xfs_setattr(
                         */
                        xfs_iflags_set(ip, XFS_ITRUNCATED);
                }
-       }
-
-       /*
-        * Change file access modes.
-        */
-       if (mask & ATTR_MODE) {
-               ip->i_d.di_mode &= S_IFMT;
-               ip->i_d.di_mode |= iattr->ia_mode & ~S_IFMT;
-
-               inode->i_mode &= S_IFMT;
-               inode->i_mode |= iattr->ia_mode & ~S_IFMT;
-
-               xfs_trans_log_inode (tp, ip, XFS_ILOG_CORE);
-               timeflags |= XFS_ICHGTIME_CHG;
+       } else if (tp) {
+               xfs_trans_ijoin(tp, ip, lock_flags);
+               xfs_trans_ihold(tp, ip);
        }
 
        /*
         * Change file ownership.  Must be the owner or privileged.
-        * If the system was configured with the "restricted_chown"
-        * option, the owner is not permitted to give away the file,
-        * and can change the group id only to a group of which he
-        * or she is a member.
         */
        if (mask & (ATTR_UID|ATTR_GID)) {
                /*
@@ -503,6 +376,24 @@ xfs_setattr(
                timeflags |= XFS_ICHGTIME_CHG;
        }
 
+       /*
+        * Change file access modes.
+        */
+       if (mask & ATTR_MODE) {
+               umode_t mode = iattr->ia_mode;
+
+               if (!in_group_p(inode->i_gid) && !capable(CAP_FSETID))
+                       mode &= ~S_ISGID;
+
+               ip->i_d.di_mode &= S_IFMT;
+               ip->i_d.di_mode |= mode & ~S_IFMT;
+
+               inode->i_mode &= S_IFMT;
+               inode->i_mode |= mode & ~S_IFMT;
+
+               xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
+               timeflags |= XFS_ICHGTIME_CHG;
+       }
 
        /*
         * Change file access or modified times.
@@ -713,7 +604,7 @@ xfs_fsync(
                return XFS_ERROR(EIO);
 
        /* capture size updates in I/O completion before writing the inode. */
-       error = filemap_fdatawait(VFS_I(ip)->i_mapping);
+       error = xfs_wait_on_pages(ip, 0, -1);
        if (error)
                return XFS_ERROR(error);
 
@@ -1029,6 +920,12 @@ xfs_inactive_symlink_rmt(
                goto error0;
        }
        /*
+        * transaction commit worked ok so we can drop the extra ticket
+        * reference that we gained in xfs_trans_dup()
+        */
+       xfs_log_ticket_put(tp->t_ticket);
+
+       /*
         * Remove the memory for extent descriptions (just bookkeeping).
         */
        if (ip->i_df.if_bytes)
@@ -1625,8 +1522,6 @@ xfs_create(
                xfs_trans_set_sync(tp);
        }
 
-       dp->i_gen++;
-
        /*
         * Attach the dquot(s) to the inodes and modify them incore.
         * These ids of the inode couldn't have changed since the new
@@ -1993,13 +1888,6 @@ xfs_remove(
        }
        xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 
-       /*
-        * Bump the in memory generation count on the parent
-        * directory so that other can know that it has changed.
-        */
-       dp->i_gen++;
-       xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
-
        if (is_dir) {
                /*
                 * Drop the link from ip's "..".
@@ -2009,7 +1897,7 @@ xfs_remove(
                        goto out_bmap_cancel;
 
                /*
-                * Drop the link from dp to ip.
+                * Drop the "." link from ip to self.
                 */
                error = xfs_droplink(tp, ip);
                if (error)
@@ -2017,14 +1905,14 @@ xfs_remove(
        } else {
                /*
                 * When removing a non-directory we need to log the parent
-                * inode here for the i_gen update.  For a directory this is
-                * done implicitly by the xfs_droplink call for the ".." entry.
+                * inode here.  For a directory this is done implicitly
+                * by the xfs_droplink call for the ".." entry.
                 */
                xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
        }
 
        /*
-        * Drop the "." link from ip to self.
+        * Drop the link from dp to ip.
         */
        error = xfs_droplink(tp, ip);
        if (error)
@@ -2178,7 +2066,6 @@ xfs_link(
        if (error)
                goto abort_return;
        xfs_ichgtime(tdp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
-       tdp->i_gen++;
        xfs_trans_log_inode(tp, tdp, XFS_ILOG_CORE);
 
        error = xfs_bumplink(tp, sip);
@@ -2355,18 +2242,10 @@ xfs_mkdir(
        }
        xfs_ichgtime(dp, XFS_ICHGTIME_MOD | XFS_ICHGTIME_CHG);
 
-       /*
-        * Bump the in memory version number of the parent directory
-        * so that other processes accessing it will recognize that
-        * the directory has changed.
-        */
-       dp->i_gen++;
-
        error = xfs_dir_init(tp, cdp, dp);
        if (error)
                goto error2;
 
-       cdp->i_gen = 1;
        error = xfs_bumplink(tp, dp);
        if (error)
                goto error2;
@@ -2653,13 +2532,6 @@ xfs_symlink(
        xfs_trans_log_inode(tp, dp, XFS_ILOG_CORE);
 
        /*
-        * Bump the in memory version number of the parent directory
-        * so that other processes accessing it will recognize that
-        * the directory has changed.
-        */
-       dp->i_gen++;
-
-       /*
         * If this is a synchronous mount, make sure that the
         * symlink transaction goes to disk before returning to
         * the user.
@@ -2809,7 +2681,7 @@ xfs_reclaim(
                return 0;
        }
 
-       vn_iowait(ip);
+       xfs_ioend_wait(ip);
 
        ASSERT(XFS_FORCED_SHUTDOWN(ip->i_mount) || ip->i_delayed_blks == 0);
 
@@ -2834,108 +2706,9 @@ xfs_reclaim(
                xfs_ilock(ip, XFS_ILOCK_EXCL);
                xfs_iflock(ip);
                xfs_iflags_set(ip, XFS_IRECLAIMABLE);
-               return xfs_finish_reclaim(ip, 1, XFS_IFLUSH_DELWRI_ELSE_SYNC);
-       } else {
-               xfs_mount_t     *mp = ip->i_mount;
-
-               /* Protect sync and unpin from us */
-               XFS_MOUNT_ILOCK(mp);
-               spin_lock(&ip->i_flags_lock);
-               __xfs_iflags_set(ip, XFS_IRECLAIMABLE);
-               spin_unlock(&ip->i_flags_lock);
-               list_add_tail(&ip->i_reclaim, &mp->m_del_inodes);
-               XFS_MOUNT_IUNLOCK(mp);
-       }
-       return 0;
-}
-
-int
-xfs_finish_reclaim(
-       xfs_inode_t     *ip,
-       int             locked,
-       int             sync_mode)
-{
-       xfs_perag_t     *pag = xfs_get_perag(ip->i_mount, ip->i_ino);
-
-       /* The hash lock here protects a thread in xfs_iget_core from
-        * racing with us on linking the inode back with a vnode.
-        * Once we have the XFS_IRECLAIM flag set it will not touch
-        * us.
-        */
-       write_lock(&pag->pag_ici_lock);
-       spin_lock(&ip->i_flags_lock);
-       if (__xfs_iflags_test(ip, XFS_IRECLAIM) ||
-           !__xfs_iflags_test(ip, XFS_IRECLAIMABLE)) {
-               spin_unlock(&ip->i_flags_lock);
-               write_unlock(&pag->pag_ici_lock);
-               if (locked) {
-                       xfs_ifunlock(ip);
-                       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-               }
-               return 1;
-       }
-       __xfs_iflags_set(ip, XFS_IRECLAIM);
-       spin_unlock(&ip->i_flags_lock);
-       write_unlock(&pag->pag_ici_lock);
-       xfs_put_perag(ip->i_mount, pag);
-
-       /*
-        * If the inode is still dirty, then flush it out.  If the inode
-        * is not in the AIL, then it will be OK to flush it delwri as
-        * long as xfs_iflush() does not keep any references to the inode.
-        * We leave that decision up to xfs_iflush() since it has the
-        * knowledge of whether it's OK to simply do a delwri flush of
-        * the inode or whether we need to wait until the inode is
-        * pulled from the AIL.
-        * We get the flush lock regardless, though, just to make sure
-        * we don't free it while it is being flushed.
-        */
-       if (!locked) {
-               xfs_ilock(ip, XFS_ILOCK_EXCL);
-               xfs_iflock(ip);
-       }
-
-       /*
-        * In the case of a forced shutdown we rely on xfs_iflush() to
-        * wait for the inode to be unpinned before returning an error.
-        */
-       if (!is_bad_inode(VFS_I(ip)) && xfs_iflush(ip, sync_mode) == 0) {
-               /* synchronize with xfs_iflush_done */
-               xfs_iflock(ip);
-               xfs_ifunlock(ip);
-       }
-
-       xfs_iunlock(ip, XFS_ILOCK_EXCL);
-       xfs_ireclaim(ip);
-       return 0;
-}
-
-int
-xfs_finish_reclaim_all(
-       xfs_mount_t     *mp,
-       int              noblock,
-       int             mode)
-{
-       xfs_inode_t     *ip, *n;
-
-restart:
-       XFS_MOUNT_ILOCK(mp);
-       list_for_each_entry_safe(ip, n, &mp->m_del_inodes, i_reclaim) {
-               if (noblock) {
-                       if (xfs_ilock_nowait(ip, XFS_ILOCK_EXCL) == 0)
-                               continue;
-                       if (xfs_ipincount(ip) ||
-                           !xfs_iflock_nowait(ip)) {
-                               xfs_iunlock(ip, XFS_ILOCK_EXCL);
-                               continue;
-                       }
-               }
-               XFS_MOUNT_IUNLOCK(mp);
-               if (xfs_finish_reclaim(ip, noblock, mode))
-                       delay(1);
-               goto restart;
+               return xfs_reclaim_inode(ip, 1, XFS_IFLUSH_DELWRI_ELSE_SYNC);
        }
-       XFS_MOUNT_IUNLOCK(mp);
+       xfs_inode_set_reclaim_tag(ip);
        return 0;
 }
 
@@ -3184,6 +2957,8 @@ xfs_zero_remaining_bytes(
        bp = xfs_buf_get_noaddr(mp->m_sb.sb_blocksize,
                                XFS_IS_REALTIME_INODE(ip) ?
                                mp->m_rtdev_targp : mp->m_ddev_targp);
+       if (!bp)
+               return XFS_ERROR(ENOMEM);
 
        for (offset = startoff; offset <= endoff; offset = lastoffset + 1) {
                offset_fsb = XFS_B_TO_FSBT(mp, offset);
@@ -3299,7 +3074,8 @@ xfs_free_file_space(
                need_iolock = 0;
        if (need_iolock) {
                xfs_ilock(ip, XFS_IOLOCK_EXCL);
-               vn_iowait(ip);  /* wait for the completion of any pending DIOs */
+               /* wait for the completion of any pending DIOs */
+               xfs_ioend_wait(ip);
        }
 
        rounding = max_t(uint, 1 << mp->m_sb.sb_blocklog, PAGE_CACHE_SIZE);
@@ -3461,7 +3237,6 @@ xfs_change_file_space(
        int             cmd,
        xfs_flock64_t   *bf,
        xfs_off_t       offset,
-       cred_t          *credp,
        int             attr_flags)
 {
        xfs_mount_t     *mp = ip->i_mount;
@@ -3549,7 +3324,7 @@ xfs_change_file_space(
                iattr.ia_valid = ATTR_SIZE;
                iattr.ia_size = startoffset;
 
-               error = xfs_setattr(ip, &iattr, attr_flags, credp);
+               error = xfs_setattr(ip, &iattr, attr_flags);
 
                if (error)
                        return error;