linux/fs/afs/inode.c
<<
>>
Prefs
   1/*
   2 * Copyright (c) 2002 Red Hat, Inc. All rights reserved.
   3 *
   4 * This software may be freely redistributed under the terms of the
   5 * GNU General Public License.
   6 *
   7 * You should have received a copy of the GNU General Public License
   8 * along with this program; if not, write to the Free Software
   9 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  10 *
  11 * Authors: David Woodhouse <dwmw2@infradead.org>
  12 *          David Howells <dhowells@redhat.com>
  13 *
  14 */
  15
  16#include <linux/kernel.h>
  17#include <linux/module.h>
  18#include <linux/init.h>
  19#include <linux/fs.h>
  20#include <linux/pagemap.h>
  21#include <linux/sched.h>
  22#include <linux/mount.h>
  23#include <linux/namei.h>
  24#include "internal.h"
  25
  26struct afs_iget_data {
  27        struct afs_fid          fid;
  28        struct afs_volume       *volume;        /* volume on which resides */
  29};
  30
  31/*
  32 * map the AFS file status to the inode member variables
  33 */
  34static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
  35{
  36        struct inode *inode = AFS_VNODE_TO_I(vnode);
  37
  38        _debug("FS: ft=%d lk=%d sz=%llu ver=%Lu mod=%hu",
  39               vnode->status.type,
  40               vnode->status.nlink,
  41               (unsigned long long) vnode->status.size,
  42               vnode->status.data_version,
  43               vnode->status.mode);
  44
  45        switch (vnode->status.type) {
  46        case AFS_FTYPE_FILE:
  47                inode->i_mode   = S_IFREG | vnode->status.mode;
  48                inode->i_op     = &afs_file_inode_operations;
  49                inode->i_fop    = &afs_file_operations;
  50                break;
  51        case AFS_FTYPE_DIR:
  52                inode->i_mode   = S_IFDIR | vnode->status.mode;
  53                inode->i_op     = &afs_dir_inode_operations;
  54                inode->i_fop    = &afs_dir_file_operations;
  55                break;
  56        case AFS_FTYPE_SYMLINK:
  57                inode->i_mode   = S_IFLNK | vnode->status.mode;
  58                inode->i_op     = &page_symlink_inode_operations;
  59                break;
  60        default:
  61                printk("kAFS: AFS vnode with undefined type\n");
  62                return -EBADMSG;
  63        }
  64
  65#ifdef CONFIG_AFS_FSCACHE
  66        if (vnode->status.size != inode->i_size)
  67                fscache_attr_changed(vnode->cache);
  68#endif
  69
  70        set_nlink(inode, vnode->status.nlink);
  71        inode->i_uid            = vnode->status.owner;
  72        inode->i_gid            = 0;
  73        inode->i_size           = vnode->status.size;
  74        inode->i_ctime.tv_sec   = vnode->status.mtime_server;
  75        inode->i_ctime.tv_nsec  = 0;
  76        inode->i_atime          = inode->i_mtime = inode->i_ctime;
  77        inode->i_blocks         = 0;
  78        inode->i_generation     = vnode->fid.unique;
  79        inode->i_version        = vnode->status.data_version;
  80        inode->i_mapping->a_ops = &afs_fs_aops;
  81
  82        /* check to see whether a symbolic link is really a mountpoint */
  83        if (vnode->status.type == AFS_FTYPE_SYMLINK) {
  84                afs_mntpt_check_symlink(vnode, key);
  85
  86                if (test_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags)) {
  87                        inode->i_mode   = S_IFDIR | vnode->status.mode;
  88                        inode->i_op     = &afs_mntpt_inode_operations;
  89                        inode->i_fop    = &afs_mntpt_file_operations;
  90                }
  91        }
  92
  93        return 0;
  94}
  95
  96/*
  97 * iget5() comparator
  98 */
  99static int afs_iget5_test(struct inode *inode, void *opaque)
 100{
 101        struct afs_iget_data *data = opaque;
 102
 103        return inode->i_ino == data->fid.vnode &&
 104                inode->i_generation == data->fid.unique;
 105}
 106
 107/*
 108 * iget5() comparator for inode created by autocell operations
 109 *
 110 * These pseudo inodes don't match anything.
 111 */
 112static int afs_iget5_autocell_test(struct inode *inode, void *opaque)
 113{
 114        return 0;
 115}
 116
 117/*
 118 * iget5() inode initialiser
 119 */
 120static int afs_iget5_set(struct inode *inode, void *opaque)
 121{
 122        struct afs_iget_data *data = opaque;
 123        struct afs_vnode *vnode = AFS_FS_I(inode);
 124
 125        inode->i_ino = data->fid.vnode;
 126        inode->i_generation = data->fid.unique;
 127        vnode->fid = data->fid;
 128        vnode->volume = data->volume;
 129
 130        return 0;
 131}
 132
 133/*
 134 * inode retrieval for autocell
 135 */
 136struct inode *afs_iget_autocell(struct inode *dir, const char *dev_name,
 137                                int namesz, struct key *key)
 138{
 139        struct afs_iget_data data;
 140        struct afs_super_info *as;
 141        struct afs_vnode *vnode;
 142        struct super_block *sb;
 143        struct inode *inode;
 144        static atomic_t afs_autocell_ino;
 145
 146        _enter("{%x:%u},%*.*s,",
 147               AFS_FS_I(dir)->fid.vid, AFS_FS_I(dir)->fid.vnode,
 148               namesz, namesz, dev_name ?: "");
 149
 150        sb = dir->i_sb;
 151        as = sb->s_fs_info;
 152        data.volume = as->volume;
 153        data.fid.vid = as->volume->vid;
 154        data.fid.unique = 0;
 155        data.fid.vnode = 0;
 156
 157        inode = iget5_locked(sb, atomic_inc_return(&afs_autocell_ino),
 158                             afs_iget5_autocell_test, afs_iget5_set,
 159                             &data);
 160        if (!inode) {
 161                _leave(" = -ENOMEM");
 162                return ERR_PTR(-ENOMEM);
 163        }
 164
 165        _debug("GOT INODE %p { ino=%lu, vl=%x, vn=%x, u=%x }",
 166               inode, inode->i_ino, data.fid.vid, data.fid.vnode,
 167               data.fid.unique);
 168
 169        vnode = AFS_FS_I(inode);
 170
 171        /* there shouldn't be an existing inode */
 172        BUG_ON(!(inode->i_state & I_NEW));
 173
 174        inode->i_size           = 0;
 175        inode->i_mode           = S_IFDIR | S_IRUGO | S_IXUGO;
 176        inode->i_op             = &afs_autocell_inode_operations;
 177        set_nlink(inode, 2);
 178        inode->i_uid            = 0;
 179        inode->i_gid            = 0;
 180        inode->i_ctime.tv_sec   = get_seconds();
 181        inode->i_ctime.tv_nsec  = 0;
 182        inode->i_atime          = inode->i_mtime = inode->i_ctime;
 183        inode->i_blocks         = 0;
 184        inode->i_version        = 0;
 185        inode->i_generation     = 0;
 186
 187        set_bit(AFS_VNODE_PSEUDODIR, &vnode->flags);
 188        set_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags);
 189        inode->i_flags |= S_AUTOMOUNT | S_NOATIME;
 190        unlock_new_inode(inode);
 191        _leave(" = %p", inode);
 192        return inode;
 193}
 194
 195/*
 196 * inode retrieval
 197 */
 198struct inode *afs_iget(struct super_block *sb, struct key *key,
 199                       struct afs_fid *fid, struct afs_file_status *status,
 200                       struct afs_callback *cb)
 201{
 202        struct afs_iget_data data = { .fid = *fid };
 203        struct afs_super_info *as;
 204        struct afs_vnode *vnode;
 205        struct inode *inode;
 206        int ret;
 207
 208        _enter(",{%x:%u.%u},,", fid->vid, fid->vnode, fid->unique);
 209
 210        as = sb->s_fs_info;
 211        data.volume = as->volume;
 212
 213        inode = iget5_locked(sb, fid->vnode, afs_iget5_test, afs_iget5_set,
 214                             &data);
 215        if (!inode) {
 216                _leave(" = -ENOMEM");
 217                return ERR_PTR(-ENOMEM);
 218        }
 219
 220        _debug("GOT INODE %p { vl=%x vn=%x, u=%x }",
 221               inode, fid->vid, fid->vnode, fid->unique);
 222
 223        vnode = AFS_FS_I(inode);
 224
 225        /* deal with an existing inode */
 226        if (!(inode->i_state & I_NEW)) {
 227                _leave(" = %p", inode);
 228                return inode;
 229        }
 230
 231        if (!status) {
 232                /* it's a remotely extant inode */
 233                set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
 234                ret = afs_vnode_fetch_status(vnode, NULL, key);
 235                if (ret < 0)
 236                        goto bad_inode;
 237        } else {
 238                /* it's an inode we just created */
 239                memcpy(&vnode->status, status, sizeof(vnode->status));
 240
 241                if (!cb) {
 242                        /* it's a symlink we just created (the fileserver
 243                         * didn't give us a callback) */
 244                        vnode->cb_version = 0;
 245                        vnode->cb_expiry = 0;
 246                        vnode->cb_type = 0;
 247                        vnode->cb_expires = get_seconds();
 248                } else {
 249                        vnode->cb_version = cb->version;
 250                        vnode->cb_expiry = cb->expiry;
 251                        vnode->cb_type = cb->type;
 252                        vnode->cb_expires = vnode->cb_expiry + get_seconds();
 253                }
 254        }
 255
 256        /* set up caching before mapping the status, as map-status reads the
 257         * first page of symlinks to see if they're really mountpoints */
 258        inode->i_size = vnode->status.size;
 259#ifdef CONFIG_AFS_FSCACHE
 260        vnode->cache = fscache_acquire_cookie(vnode->volume->cache,
 261                                              &afs_vnode_cache_index_def,
 262                                              vnode);
 263#endif
 264
 265        ret = afs_inode_map_status(vnode, key);
 266        if (ret < 0)
 267                goto bad_inode;
 268
 269        /* success */
 270        clear_bit(AFS_VNODE_UNSET, &vnode->flags);
 271        inode->i_flags |= S_NOATIME;
 272        unlock_new_inode(inode);
 273        _leave(" = %p [CB { v=%u t=%u }]", inode, vnode->cb_version, vnode->cb_type);
 274        return inode;
 275
 276        /* failure */
 277bad_inode:
 278#ifdef CONFIG_AFS_FSCACHE
 279        fscache_relinquish_cookie(vnode->cache, 0);
 280        vnode->cache = NULL;
 281#endif
 282        iget_failed(inode);
 283        _leave(" = %d [bad]", ret);
 284        return ERR_PTR(ret);
 285}
 286
 287/*
 288 * mark the data attached to an inode as obsolete due to a write on the server
 289 * - might also want to ditch all the outstanding writes and dirty pages
 290 */
 291void afs_zap_data(struct afs_vnode *vnode)
 292{
 293        _enter("{%x:%u}", vnode->fid.vid, vnode->fid.vnode);
 294
 295        /* nuke all the non-dirty pages that aren't locked, mapped or being
 296         * written back in a regular file and completely discard the pages in a
 297         * directory or symlink */
 298        if (S_ISREG(vnode->vfs_inode.i_mode))
 299                invalidate_remote_inode(&vnode->vfs_inode);
 300        else
 301                invalidate_inode_pages2(vnode->vfs_inode.i_mapping);
 302}
 303
 304/*
 305 * validate a vnode/inode
 306 * - there are several things we need to check
 307 *   - parent dir data changes (rm, rmdir, rename, mkdir, create, link,
 308 *     symlink)
 309 *   - parent dir metadata changed (security changes)
 310 *   - dentry data changed (write, truncate)
 311 *   - dentry metadata changed (security changes)
 312 */
 313int afs_validate(struct afs_vnode *vnode, struct key *key)
 314{
 315        int ret;
 316
 317        _enter("{v={%x:%u} fl=%lx},%x",
 318               vnode->fid.vid, vnode->fid.vnode, vnode->flags,
 319               key_serial(key));
 320
 321        if (vnode->cb_promised &&
 322            !test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags) &&
 323            !test_bit(AFS_VNODE_MODIFIED, &vnode->flags) &&
 324            !test_bit(AFS_VNODE_ZAP_DATA, &vnode->flags)) {
 325                if (vnode->cb_expires < get_seconds() + 10) {
 326                        _debug("callback expired");
 327                        set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
 328                } else {
 329                        goto valid;
 330                }
 331        }
 332
 333        if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
 334                goto valid;
 335
 336        mutex_lock(&vnode->validate_lock);
 337
 338        /* if the promise has expired, we need to check the server again to get
 339         * a new promise - note that if the (parent) directory's metadata was
 340         * changed then the security may be different and we may no longer have
 341         * access */
 342        if (!vnode->cb_promised ||
 343            test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) {
 344                _debug("not promised");
 345                ret = afs_vnode_fetch_status(vnode, NULL, key);
 346                if (ret < 0)
 347                        goto error_unlock;
 348                _debug("new promise [fl=%lx]", vnode->flags);
 349        }
 350
 351        if (test_bit(AFS_VNODE_DELETED, &vnode->flags)) {
 352                _debug("file already deleted");
 353                ret = -ESTALE;
 354                goto error_unlock;
 355        }
 356
 357        /* if the vnode's data version number changed then its contents are
 358         * different */
 359        if (test_and_clear_bit(AFS_VNODE_ZAP_DATA, &vnode->flags))
 360                afs_zap_data(vnode);
 361
 362        clear_bit(AFS_VNODE_MODIFIED, &vnode->flags);
 363        mutex_unlock(&vnode->validate_lock);
 364valid:
 365        _leave(" = 0");
 366        return 0;
 367
 368error_unlock:
 369        mutex_unlock(&vnode->validate_lock);
 370        _leave(" = %d", ret);
 371        return ret;
 372}
 373
 374/*
 375 * read the attributes of an inode
 376 */
 377int afs_getattr(struct vfsmount *mnt, struct dentry *dentry,
 378                      struct kstat *stat)
 379{
 380        struct inode *inode;
 381
 382        inode = dentry->d_inode;
 383
 384        _enter("{ ino=%lu v=%u }", inode->i_ino, inode->i_generation);
 385
 386        generic_fillattr(inode, stat);
 387        return 0;
 388}
 389
 390/*
 391 * discard an AFS inode
 392 */
 393int afs_drop_inode(struct inode *inode)
 394{
 395        _enter("");
 396
 397        if (test_bit(AFS_VNODE_PSEUDODIR, &AFS_FS_I(inode)->flags))
 398                return generic_delete_inode(inode);
 399        else
 400                return generic_drop_inode(inode);
 401}
 402
 403/*
 404 * clear an AFS inode
 405 */
 406void afs_evict_inode(struct inode *inode)
 407{
 408        struct afs_permits *permits;
 409        struct afs_vnode *vnode;
 410
 411        vnode = AFS_FS_I(inode);
 412
 413        _enter("{%x:%u.%d} v=%u x=%u t=%u }",
 414               vnode->fid.vid,
 415               vnode->fid.vnode,
 416               vnode->fid.unique,
 417               vnode->cb_version,
 418               vnode->cb_expiry,
 419               vnode->cb_type);
 420
 421        _debug("CLEAR INODE %p", inode);
 422
 423        ASSERTCMP(inode->i_ino, ==, vnode->fid.vnode);
 424
 425        truncate_inode_pages(&inode->i_data, 0);
 426        clear_inode(inode);
 427
 428        afs_give_up_callback(vnode);
 429
 430        if (vnode->server) {
 431                spin_lock(&vnode->server->fs_lock);
 432                rb_erase(&vnode->server_rb, &vnode->server->fs_vnodes);
 433                spin_unlock(&vnode->server->fs_lock);
 434                afs_put_server(vnode->server);
 435                vnode->server = NULL;
 436        }
 437
 438        ASSERT(list_empty(&vnode->writebacks));
 439        ASSERT(!vnode->cb_promised);
 440
 441#ifdef CONFIG_AFS_FSCACHE
 442        fscache_relinquish_cookie(vnode->cache, 0);
 443        vnode->cache = NULL;
 444#endif
 445
 446        mutex_lock(&vnode->permits_lock);
 447        permits = vnode->permits;
 448        rcu_assign_pointer(vnode->permits, NULL);
 449        mutex_unlock(&vnode->permits_lock);
 450        if (permits)
 451                call_rcu(&permits->rcu, afs_zap_permits);
 452
 453        _leave("");
 454}
 455
 456/*
 457 * set the attributes of an inode
 458 */
 459int afs_setattr(struct dentry *dentry, struct iattr *attr)
 460{
 461        struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
 462        struct key *key;
 463        int ret;
 464
 465        _enter("{%x:%u},{n=%s},%x",
 466               vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,
 467               attr->ia_valid);
 468
 469        if (!(attr->ia_valid & (ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID |
 470                                ATTR_MTIME))) {
 471                _leave(" = 0 [unsupported]");
 472                return 0;
 473        }
 474
 475        /* flush any dirty data outstanding on a regular file */
 476        if (S_ISREG(vnode->vfs_inode.i_mode)) {
 477                filemap_write_and_wait(vnode->vfs_inode.i_mapping);
 478                afs_writeback_all(vnode);
 479        }
 480
 481        if (attr->ia_valid & ATTR_FILE) {
 482                key = attr->ia_file->private_data;
 483        } else {
 484                key = afs_request_key(vnode->volume->cell);
 485                if (IS_ERR(key)) {
 486                        ret = PTR_ERR(key);
 487                        goto error;
 488                }
 489        }
 490
 491        ret = afs_vnode_setattr(vnode, key, attr);
 492        if (!(attr->ia_valid & ATTR_FILE))
 493                key_put(key);
 494
 495error:
 496        _leave(" = %d", ret);
 497        return ret;
 498}
 499
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.