linux/fs/xfs/xfs_utils.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2000-2002,2005 Silicon Graphics, Inc.
   3 * All Rights Reserved.
   4 *
   5 * This program is free software; you can redistribute it and/or
   6 * modify it under the terms of the GNU General Public License as
   7 * published by the Free Software Foundation.
   8 *
   9 * This program is distributed in the hope that it would be useful,
  10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 * GNU General Public License for more details.
  13 *
  14 * You should have received a copy of the GNU General Public License
  15 * along with this program; if not, write the Free Software Foundation,
  16 * Inc.,  51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  17 */
  18#include "xfs.h"
  19#include "xfs_fs.h"
  20#include "xfs_types.h"
  21#include "xfs_log.h"
  22#include "xfs_trans.h"
  23#include "xfs_sb.h"
  24#include "xfs_ag.h"
  25#include "xfs_dir2.h"
  26#include "xfs_mount.h"
  27#include "xfs_bmap_btree.h"
  28#include "xfs_dinode.h"
  29#include "xfs_inode.h"
  30#include "xfs_inode_item.h"
  31#include "xfs_bmap.h"
  32#include "xfs_error.h"
  33#include "xfs_quota.h"
  34#include "xfs_itable.h"
  35#include "xfs_utils.h"
  36
  37
  38/*
  39 * Allocates a new inode from disk and return a pointer to the
  40 * incore copy. This routine will internally commit the current
  41 * transaction and allocate a new one if the Space Manager needed
  42 * to do an allocation to replenish the inode free-list.
  43 *
  44 * This routine is designed to be called from xfs_create and
  45 * xfs_create_dir.
  46 *
  47 */
  48int
  49xfs_dir_ialloc(
  50        xfs_trans_t     **tpp,          /* input: current transaction;
  51                                           output: may be a new transaction. */
  52        xfs_inode_t     *dp,            /* directory within whose allocate
  53                                           the inode. */
  54        umode_t         mode,
  55        xfs_nlink_t     nlink,
  56        xfs_dev_t       rdev,
  57        prid_t          prid,           /* project id */
  58        int             okalloc,        /* ok to allocate new space */
  59        xfs_inode_t     **ipp,          /* pointer to inode; it will be
  60                                           locked. */
  61        int             *committed)
  62
  63{
  64        xfs_trans_t     *tp;
  65        xfs_trans_t     *ntp;
  66        xfs_inode_t     *ip;
  67        xfs_buf_t       *ialloc_context = NULL;
  68        int             code;
  69        uint            log_res;
  70        uint            log_count;
  71        void            *dqinfo;
  72        uint            tflags;
  73
  74        tp = *tpp;
  75        ASSERT(tp->t_flags & XFS_TRANS_PERM_LOG_RES);
  76
  77        /*
  78         * xfs_ialloc will return a pointer to an incore inode if
  79         * the Space Manager has an available inode on the free
  80         * list. Otherwise, it will do an allocation and replenish
  81         * the freelist.  Since we can only do one allocation per
  82         * transaction without deadlocks, we will need to commit the
  83         * current transaction and start a new one.  We will then
  84         * need to call xfs_ialloc again to get the inode.
  85         *
  86         * If xfs_ialloc did an allocation to replenish the freelist,
  87         * it returns the bp containing the head of the freelist as
  88         * ialloc_context. We will hold a lock on it across the
  89         * transaction commit so that no other process can steal
  90         * the inode(s) that we've just allocated.
  91         */
  92        code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid, okalloc,
  93                          &ialloc_context, &ip);
  94
  95        /*
  96         * Return an error if we were unable to allocate a new inode.
  97         * This should only happen if we run out of space on disk or
  98         * encounter a disk error.
  99         */
 100        if (code) {
 101                *ipp = NULL;
 102                return code;
 103        }
 104        if (!ialloc_context && !ip) {
 105                *ipp = NULL;
 106                return XFS_ERROR(ENOSPC);
 107        }
 108
 109        /*
 110         * If the AGI buffer is non-NULL, then we were unable to get an
 111         * inode in one operation.  We need to commit the current
 112         * transaction and call xfs_ialloc() again.  It is guaranteed
 113         * to succeed the second time.
 114         */
 115        if (ialloc_context) {
 116                /*
 117                 * Normally, xfs_trans_commit releases all the locks.
 118                 * We call bhold to hang on to the ialloc_context across
 119                 * the commit.  Holding this buffer prevents any other
 120                 * processes from doing any allocations in this
 121                 * allocation group.
 122                 */
 123                xfs_trans_bhold(tp, ialloc_context);
 124                /*
 125                 * Save the log reservation so we can use
 126                 * them in the next transaction.
 127                 */
 128                log_res = xfs_trans_get_log_res(tp);
 129                log_count = xfs_trans_get_log_count(tp);
 130
 131                /*
 132                 * We want the quota changes to be associated with the next
 133                 * transaction, NOT this one. So, detach the dqinfo from this
 134                 * and attach it to the next transaction.
 135                 */
 136                dqinfo = NULL;
 137                tflags = 0;
 138                if (tp->t_dqinfo) {
 139                        dqinfo = (void *)tp->t_dqinfo;
 140                        tp->t_dqinfo = NULL;
 141                        tflags = tp->t_flags & XFS_TRANS_DQ_DIRTY;
 142                        tp->t_flags &= ~(XFS_TRANS_DQ_DIRTY);
 143                }
 144
 145                ntp = xfs_trans_dup(tp);
 146                code = xfs_trans_commit(tp, 0);
 147                tp = ntp;
 148                if (committed != NULL) {
 149                        *committed = 1;
 150                }
 151                /*
 152                 * If we get an error during the commit processing,
 153                 * release the buffer that is still held and return
 154                 * to the caller.
 155                 */
 156                if (code) {
 157                        xfs_buf_relse(ialloc_context);
 158                        if (dqinfo) {
 159                                tp->t_dqinfo = dqinfo;
 160                                xfs_trans_free_dqinfo(tp);
 161                        }
 162                        *tpp = ntp;
 163                        *ipp = NULL;
 164                        return code;
 165                }
 166
 167                /*
 168                 * transaction commit worked ok so we can drop the extra ticket
 169                 * reference that we gained in xfs_trans_dup()
 170                 */
 171                xfs_log_ticket_put(tp->t_ticket);
 172                code = xfs_trans_reserve(tp, 0, log_res, 0,
 173                                         XFS_TRANS_PERM_LOG_RES, log_count);
 174                /*
 175                 * Re-attach the quota info that we detached from prev trx.
 176                 */
 177                if (dqinfo) {
 178                        tp->t_dqinfo = dqinfo;
 179                        tp->t_flags |= tflags;
 180                }
 181
 182                if (code) {
 183                        xfs_buf_relse(ialloc_context);
 184                        *tpp = ntp;
 185                        *ipp = NULL;
 186                        return code;
 187                }
 188                xfs_trans_bjoin(tp, ialloc_context);
 189
 190                /*
 191                 * Call ialloc again. Since we've locked out all
 192                 * other allocations in this allocation group,
 193                 * this call should always succeed.
 194                 */
 195                code = xfs_ialloc(tp, dp, mode, nlink, rdev, prid,
 196                                  okalloc, &ialloc_context, &ip);
 197
 198                /*
 199                 * If we get an error at this point, return to the caller
 200                 * so that the current transaction can be aborted.
 201                 */
 202                if (code) {
 203                        *tpp = tp;
 204                        *ipp = NULL;
 205                        return code;
 206                }
 207                ASSERT(!ialloc_context && ip);
 208
 209        } else {
 210                if (committed != NULL)
 211                        *committed = 0;
 212        }
 213
 214        *ipp = ip;
 215        *tpp = tp;
 216
 217        return 0;
 218}
 219
 220/*
 221 * Decrement the link count on an inode & log the change.
 222 * If this causes the link count to go to zero, initiate the
 223 * logging activity required to truncate a file.
 224 */
 225int                             /* error */
 226xfs_droplink(
 227        xfs_trans_t *tp,
 228        xfs_inode_t *ip)
 229{
 230        int     error;
 231
 232        xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
 233
 234        ASSERT (ip->i_d.di_nlink > 0);
 235        ip->i_d.di_nlink--;
 236        drop_nlink(VFS_I(ip));
 237        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 238
 239        error = 0;
 240        if (ip->i_d.di_nlink == 0) {
 241                /*
 242                 * We're dropping the last link to this file.
 243                 * Move the on-disk inode to the AGI unlinked list.
 244                 * From xfs_inactive() we will pull the inode from
 245                 * the list and free it.
 246                 */
 247                error = xfs_iunlink(tp, ip);
 248        }
 249        return error;
 250}
 251
 252/*
 253 * This gets called when the inode's version needs to be changed from 1 to 2.
 254 * Currently this happens when the nlink field overflows the old 16-bit value
 255 * or when chproj is called to change the project for the first time.
 256 * As a side effect the superblock version will also get rev'd
 257 * to contain the NLINK bit.
 258 */
 259void
 260xfs_bump_ino_vers2(
 261        xfs_trans_t     *tp,
 262        xfs_inode_t     *ip)
 263{
 264        xfs_mount_t     *mp;
 265
 266        ASSERT(xfs_isilocked(ip, XFS_ILOCK_EXCL));
 267        ASSERT(ip->i_d.di_version == 1);
 268
 269        ip->i_d.di_version = 2;
 270        ip->i_d.di_onlink = 0;
 271        memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad));
 272        mp = tp->t_mountp;
 273        if (!xfs_sb_version_hasnlink(&mp->m_sb)) {
 274                spin_lock(&mp->m_sb_lock);
 275                if (!xfs_sb_version_hasnlink(&mp->m_sb)) {
 276                        xfs_sb_version_addnlink(&mp->m_sb);
 277                        spin_unlock(&mp->m_sb_lock);
 278                        xfs_mod_sb(tp, XFS_SB_VERSIONNUM);
 279                } else {
 280                        spin_unlock(&mp->m_sb_lock);
 281                }
 282        }
 283        /* Caller must log the inode */
 284}
 285
 286/*
 287 * Increment the link count on an inode & log the change.
 288 */
 289int
 290xfs_bumplink(
 291        xfs_trans_t *tp,
 292        xfs_inode_t *ip)
 293{
 294        xfs_trans_ichgtime(tp, ip, XFS_ICHGTIME_CHG);
 295
 296        ASSERT(ip->i_d.di_nlink > 0);
 297        ip->i_d.di_nlink++;
 298        inc_nlink(VFS_I(ip));
 299        if ((ip->i_d.di_version == 1) &&
 300            (ip->i_d.di_nlink > XFS_MAXLINK_1)) {
 301                /*
 302                 * The inode has increased its number of links beyond
 303                 * what can fit in an old format inode.  It now needs
 304                 * to be converted to a version 2 inode with a 32 bit
 305                 * link count.  If this is the first inode in the file
 306                 * system to do this, then we need to bump the superblock
 307                 * version number as well.
 308                 */
 309                xfs_bump_ino_vers2(tp, ip);
 310        }
 311
 312        xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE);
 313        return 0;
 314}
 315
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.