linux/fs/afs/file.c
<<
>>
Prefs
   1/* AFS filesystem file handling
   2 *
   3 * Copyright (C) 2002, 2007 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public License
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the License, or (at your option) any later version.
  10 */
  11
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14#include <linux/init.h>
  15#include <linux/slab.h>
  16#include <linux/fs.h>
  17#include <linux/pagemap.h>
  18#include <linux/writeback.h>
  19#include "internal.h"
  20
  21static int afs_readpage(struct file *file, struct page *page);
  22static void afs_invalidatepage(struct page *page, unsigned long offset);
  23static int afs_releasepage(struct page *page, gfp_t gfp_flags);
  24static int afs_launder_page(struct page *page);
  25
  26const struct file_operations afs_file_operations = {
  27        .open           = afs_open,
  28        .release        = afs_release,
  29        .llseek         = generic_file_llseek,
  30        .read           = do_sync_read,
  31        .write          = do_sync_write,
  32        .aio_read       = generic_file_aio_read,
  33        .aio_write      = afs_file_write,
  34        .mmap           = generic_file_readonly_mmap,
  35        .splice_read    = generic_file_splice_read,
  36        .fsync          = afs_fsync,
  37        .lock           = afs_lock,
  38        .flock          = afs_flock,
  39};
  40
  41const struct inode_operations afs_file_inode_operations = {
  42        .getattr        = afs_getattr,
  43        .setattr        = afs_setattr,
  44        .permission     = afs_permission,
  45};
  46
  47const struct address_space_operations afs_fs_aops = {
  48        .readpage       = afs_readpage,
  49        .set_page_dirty = afs_set_page_dirty,
  50        .launder_page   = afs_launder_page,
  51        .releasepage    = afs_releasepage,
  52        .invalidatepage = afs_invalidatepage,
  53        .prepare_write  = afs_prepare_write,
  54        .commit_write   = afs_commit_write,
  55        .writepage      = afs_writepage,
  56        .writepages     = afs_writepages,
  57};
  58
  59/*
  60 * open an AFS file or directory and attach a key to it
  61 */
  62int afs_open(struct inode *inode, struct file *file)
  63{
  64        struct afs_vnode *vnode = AFS_FS_I(inode);
  65        struct key *key;
  66        int ret;
  67
  68        _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
  69
  70        key = afs_request_key(vnode->volume->cell);
  71        if (IS_ERR(key)) {
  72                _leave(" = %ld [key]", PTR_ERR(key));
  73                return PTR_ERR(key);
  74        }
  75
  76        ret = afs_validate(vnode, key);
  77        if (ret < 0) {
  78                _leave(" = %d [val]", ret);
  79                return ret;
  80        }
  81
  82        file->private_data = key;
  83        _leave(" = 0");
  84        return 0;
  85}
  86
  87/*
  88 * release an AFS file or directory and discard its key
  89 */
  90int afs_release(struct inode *inode, struct file *file)
  91{
  92        struct afs_vnode *vnode = AFS_FS_I(inode);
  93
  94        _enter("{%x:%u},", vnode->fid.vid, vnode->fid.vnode);
  95
  96        key_put(file->private_data);
  97        _leave(" = 0");
  98        return 0;
  99}
 100
 101/*
 102 * deal with notification that a page was read from the cache
 103 */
 104#ifdef AFS_CACHING_SUPPORT
 105static void afs_readpage_read_complete(void *cookie_data,
 106                                       struct page *page,
 107                                       void *data,
 108                                       int error)
 109{
 110        _enter("%p,%p,%p,%d", cookie_data, page, data, error);
 111
 112        if (error)
 113                SetPageError(page);
 114        else
 115                SetPageUptodate(page);
 116        unlock_page(page);
 117
 118}
 119#endif
 120
 121/*
 122 * deal with notification that a page was written to the cache
 123 */
 124#ifdef AFS_CACHING_SUPPORT
 125static void afs_readpage_write_complete(void *cookie_data,
 126                                        struct page *page,
 127                                        void *data,
 128                                        int error)
 129{
 130        _enter("%p,%p,%p,%d", cookie_data, page, data, error);
 131
 132        unlock_page(page);
 133}
 134#endif
 135
 136/*
 137 * AFS read page from file, directory or symlink
 138 */
 139static int afs_readpage(struct file *file, struct page *page)
 140{
 141        struct afs_vnode *vnode;
 142        struct inode *inode;
 143        struct key *key;
 144        size_t len;
 145        off_t offset;
 146        int ret;
 147
 148        inode = page->mapping->host;
 149
 150        ASSERT(file != NULL);
 151        key = file->private_data;
 152        ASSERT(key != NULL);
 153
 154        _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);
 155
 156        vnode = AFS_FS_I(inode);
 157
 158        BUG_ON(!PageLocked(page));
 159
 160        ret = -ESTALE;
 161        if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
 162                goto error;
 163
 164#ifdef AFS_CACHING_SUPPORT
 165        /* is it cached? */
 166        ret = cachefs_read_or_alloc_page(vnode->cache,
 167                                         page,
 168                                         afs_file_readpage_read_complete,
 169                                         NULL,
 170                                         GFP_KERNEL);
 171#else
 172        ret = -ENOBUFS;
 173#endif
 174
 175        switch (ret) {
 176                /* read BIO submitted and wb-journal entry found */
 177        case 1:
 178                BUG(); // TODO - handle wb-journal match
 179
 180                /* read BIO submitted (page in cache) */
 181        case 0:
 182                break;
 183
 184                /* no page available in cache */
 185        case -ENOBUFS:
 186        case -ENODATA:
 187        default:
 188                offset = page->index << PAGE_CACHE_SHIFT;
 189                len = min_t(size_t, i_size_read(inode) - offset, PAGE_SIZE);
 190
 191                /* read the contents of the file from the server into the
 192                 * page */
 193                ret = afs_vnode_fetch_data(vnode, key, offset, len, page);
 194                if (ret < 0) {
 195                        if (ret == -ENOENT) {
 196                                _debug("got NOENT from server"
 197                                       " - marking file deleted and stale");
 198                                set_bit(AFS_VNODE_DELETED, &vnode->flags);
 199                                ret = -ESTALE;
 200                        }
 201#ifdef AFS_CACHING_SUPPORT
 202                        cachefs_uncache_page(vnode->cache, page);
 203#endif
 204                        goto error;
 205                }
 206
 207                SetPageUptodate(page);
 208
 209#ifdef AFS_CACHING_SUPPORT
 210                if (cachefs_write_page(vnode->cache,
 211                                       page,
 212                                       afs_file_readpage_write_complete,
 213                                       NULL,
 214                                       GFP_KERNEL) != 0
 215                    ) {
 216                        cachefs_uncache_page(vnode->cache, page);
 217                        unlock_page(page);
 218                }
 219#else
 220                unlock_page(page);
 221#endif
 222        }
 223
 224        _leave(" = 0");
 225        return 0;
 226
 227error:
 228        SetPageError(page);
 229        unlock_page(page);
 230        _leave(" = %d", ret);
 231        return ret;
 232}
 233
 234/*
 235 * invalidate part or all of a page
 236 */
 237static void afs_invalidatepage(struct page *page, unsigned long offset)
 238{
 239        int ret = 1;
 240
 241        _enter("{%lu},%lu", page->index, offset);
 242
 243        BUG_ON(!PageLocked(page));
 244
 245        if (PagePrivate(page)) {
 246                /* We release buffers only if the entire page is being
 247                 * invalidated.
 248                 * The get_block cached value has been unconditionally
 249                 * invalidated, so real IO is not possible anymore.
 250                 */
 251                if (offset == 0) {
 252                        BUG_ON(!PageLocked(page));
 253
 254                        ret = 0;
 255                        if (!PageWriteback(page))
 256                                ret = page->mapping->a_ops->releasepage(page,
 257                                                                        0);
 258                        /* possibly should BUG_ON(!ret); - neilb */
 259                }
 260        }
 261
 262        _leave(" = %d", ret);
 263}
 264
 265/*
 266 * write back a dirty page
 267 */
 268static int afs_launder_page(struct page *page)
 269{
 270        _enter("{%lu}", page->index);
 271
 272        return 0;
 273}
 274
 275/*
 276 * release a page and cleanup its private data
 277 */
 278static int afs_releasepage(struct page *page, gfp_t gfp_flags)
 279{
 280        struct afs_vnode *vnode = AFS_FS_I(page->mapping->host);
 281        struct afs_writeback *wb;
 282
 283        _enter("{{%x:%u}[%lu],%lx},%x",
 284               vnode->fid.vid, vnode->fid.vnode, page->index, page->flags,
 285               gfp_flags);
 286
 287        if (PagePrivate(page)) {
 288                wb = (struct afs_writeback *) page_private(page);
 289                ASSERT(wb != NULL);
 290                set_page_private(page, 0);
 291                ClearPagePrivate(page);
 292                afs_put_writeback(wb);
 293        }
 294
 295        _leave(" = 0");
 296        return 0;
 297}
 298