linux/fs/9p/vfs_file.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/9p/vfs_file.c
   3 *
   4 * This file contians vfs file ops for 9P2000.
   5 *
   6 *  Copyright (C) 2004 by Eric Van Hensbergen <ericvh@gmail.com>
   7 *  Copyright (C) 2002 by Ron Minnich <rminnich@lanl.gov>
   8 *
   9 *  This program is free software; you can redistribute it and/or modify
  10 *  it under the terms of the GNU General Public License version 2
  11 *  as published by the Free Software Foundation.
  12 *
  13 *  This program is distributed in the hope that it will be useful,
  14 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 *  GNU General Public License for more details.
  17 *
  18 *  You should have received a copy of the GNU General Public License
  19 *  along with this program; if not, write to:
  20 *  Free Software Foundation
  21 *  51 Franklin Street, Fifth Floor
  22 *  Boston, MA  02111-1301  USA
  23 *
  24 */
  25
  26#include <linux/module.h>
  27#include <linux/errno.h>
  28#include <linux/fs.h>
  29#include <linux/sched.h>
  30#include <linux/file.h>
  31#include <linux/stat.h>
  32#include <linux/string.h>
  33#include <linux/inet.h>
  34#include <linux/list.h>
  35#include <linux/pagemap.h>
  36#include <linux/utsname.h>
  37#include <asm/uaccess.h>
  38#include <linux/idr.h>
  39#include <net/9p/9p.h>
  40#include <net/9p/client.h>
  41
  42#include "v9fs.h"
  43#include "v9fs_vfs.h"
  44#include "fid.h"
  45#include "cache.h"
  46
  47static const struct vm_operations_struct v9fs_file_vm_ops;
  48static const struct vm_operations_struct v9fs_mmap_file_vm_ops;
  49
  50/**
  51 * v9fs_file_open - open a file (or directory)
  52 * @inode: inode to be opened
  53 * @file: file being opened
  54 *
  55 */
  56
  57int v9fs_file_open(struct inode *inode, struct file *file)
  58{
  59        int err;
  60        struct v9fs_inode *v9inode;
  61        struct v9fs_session_info *v9ses;
  62        struct p9_fid *fid;
  63        int omode;
  64
  65        p9_debug(P9_DEBUG_VFS, "inode: %p file: %p\n", inode, file);
  66        v9inode = V9FS_I(inode);
  67        v9ses = v9fs_inode2v9ses(inode);
  68        if (v9fs_proto_dotl(v9ses))
  69                omode = v9fs_open_to_dotl_flags(file->f_flags);
  70        else
  71                omode = v9fs_uflags2omode(file->f_flags,
  72                                        v9fs_proto_dotu(v9ses));
  73        fid = file->private_data;
  74        if (!fid) {
  75                fid = v9fs_fid_clone(file->f_path.dentry);
  76                if (IS_ERR(fid))
  77                        return PTR_ERR(fid);
  78
  79                err = p9_client_open(fid, omode);
  80                if (err < 0) {
  81                        p9_client_clunk(fid);
  82                        return err;
  83                }
  84                if ((file->f_flags & O_APPEND) &&
  85                        (!v9fs_proto_dotu(v9ses) && !v9fs_proto_dotl(v9ses)))
  86                        generic_file_llseek(file, 0, SEEK_END);
  87        }
  88
  89        file->private_data = fid;
  90        mutex_lock(&v9inode->v_mutex);
  91        if ((v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) &&
  92            !v9inode->writeback_fid &&
  93            ((file->f_flags & O_ACCMODE) != O_RDONLY)) {
  94                /*
  95                 * clone a fid and add it to writeback_fid
  96                 * we do it during open time instead of
  97                 * page dirty time via write_begin/page_mkwrite
  98                 * because we want write after unlink usecase
  99                 * to work.
 100                 */
 101                fid = v9fs_writeback_fid(file->f_path.dentry);
 102                if (IS_ERR(fid)) {
 103                        err = PTR_ERR(fid);
 104                        mutex_unlock(&v9inode->v_mutex);
 105                        goto out_error;
 106                }
 107                v9inode->writeback_fid = (void *) fid;
 108        }
 109        mutex_unlock(&v9inode->v_mutex);
 110        if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE)
 111                v9fs_cache_inode_set_cookie(inode, file);
 112        return 0;
 113out_error:
 114        p9_client_clunk(file->private_data);
 115        file->private_data = NULL;
 116        return err;
 117}
 118
 119/**
 120 * v9fs_file_lock - lock a file (or directory)
 121 * @filp: file to be locked
 122 * @cmd: lock command
 123 * @fl: file lock structure
 124 *
 125 * Bugs: this looks like a local only lock, we should extend into 9P
 126 *       by using open exclusive
 127 */
 128
 129static int v9fs_file_lock(struct file *filp, int cmd, struct file_lock *fl)
 130{
 131        int res = 0;
 132        struct inode *inode = file_inode(filp);
 133
 134        p9_debug(P9_DEBUG_VFS, "filp: %p lock: %p\n", filp, fl);
 135
 136        /* No mandatory locks */
 137        if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
 138                return -ENOLCK;
 139
 140        if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
 141                filemap_write_and_wait(inode->i_mapping);
 142                invalidate_mapping_pages(&inode->i_data, 0, -1);
 143        }
 144
 145        return res;
 146}
 147
 148static int v9fs_file_do_lock(struct file *filp, int cmd, struct file_lock *fl)
 149{
 150        struct p9_flock flock;
 151        struct p9_fid *fid;
 152        uint8_t status;
 153        int res = 0;
 154        unsigned char fl_type;
 155
 156        fid = filp->private_data;
 157        BUG_ON(fid == NULL);
 158
 159        if ((fl->fl_flags & FL_POSIX) != FL_POSIX)
 160                BUG();
 161
 162        res = posix_lock_file_wait(filp, fl);
 163        if (res < 0)
 164                goto out;
 165
 166        /* convert posix lock to p9 tlock args */
 167        memset(&flock, 0, sizeof(flock));
 168        /* map the lock type */
 169        switch (fl->fl_type) {
 170        case F_RDLCK:
 171                flock.type = P9_LOCK_TYPE_RDLCK;
 172                break;
 173        case F_WRLCK:
 174                flock.type = P9_LOCK_TYPE_WRLCK;
 175                break;
 176        case F_UNLCK:
 177                flock.type = P9_LOCK_TYPE_UNLCK;
 178                break;
 179        }
 180        flock.start = fl->fl_start;
 181        if (fl->fl_end == OFFSET_MAX)
 182                flock.length = 0;
 183        else
 184                flock.length = fl->fl_end - fl->fl_start + 1;
 185        flock.proc_id = fl->fl_pid;
 186        flock.client_id = fid->clnt->name;
 187        if (IS_SETLKW(cmd))
 188                flock.flags = P9_LOCK_FLAGS_BLOCK;
 189
 190        /*
 191         * if its a blocked request and we get P9_LOCK_BLOCKED as the status
 192         * for lock request, keep on trying
 193         */
 194        for (;;) {
 195                res = p9_client_lock_dotl(fid, &flock, &status);
 196                if (res < 0)
 197                        break;
 198
 199                if (status != P9_LOCK_BLOCKED)
 200                        break;
 201                if (status == P9_LOCK_BLOCKED && !IS_SETLKW(cmd))
 202                        break;
 203                if (schedule_timeout_interruptible(P9_LOCK_TIMEOUT) != 0)
 204                        break;
 205        }
 206
 207        /* map 9p status to VFS status */
 208        switch (status) {
 209        case P9_LOCK_SUCCESS:
 210                res = 0;
 211                break;
 212        case P9_LOCK_BLOCKED:
 213                res = -EAGAIN;
 214                break;
 215        case P9_LOCK_ERROR:
 216        case P9_LOCK_GRACE:
 217                res = -ENOLCK;
 218                break;
 219        default:
 220                BUG();
 221        }
 222
 223        /*
 224         * incase server returned error for lock request, revert
 225         * it locally
 226         */
 227        if (res < 0 && fl->fl_type != F_UNLCK) {
 228                fl_type = fl->fl_type;
 229                fl->fl_type = F_UNLCK;
 230                res = posix_lock_file_wait(filp, fl);
 231                fl->fl_type = fl_type;
 232        }
 233out:
 234        return res;
 235}
 236
 237static int v9fs_file_getlock(struct file *filp, struct file_lock *fl)
 238{
 239        struct p9_getlock glock;
 240        struct p9_fid *fid;
 241        int res = 0;
 242
 243        fid = filp->private_data;
 244        BUG_ON(fid == NULL);
 245
 246        posix_test_lock(filp, fl);
 247        /*
 248         * if we have a conflicting lock locally, no need to validate
 249         * with server
 250         */
 251        if (fl->fl_type != F_UNLCK)
 252                return res;
 253
 254        /* convert posix lock to p9 tgetlock args */
 255        memset(&glock, 0, sizeof(glock));
 256        glock.type  = P9_LOCK_TYPE_UNLCK;
 257        glock.start = fl->fl_start;
 258        if (fl->fl_end == OFFSET_MAX)
 259                glock.length = 0;
 260        else
 261                glock.length = fl->fl_end - fl->fl_start + 1;
 262        glock.proc_id = fl->fl_pid;
 263        glock.client_id = fid->clnt->name;
 264
 265        res = p9_client_getlock_dotl(fid, &glock);
 266        if (res < 0)
 267                return res;
 268        /* map 9p lock type to os lock type */
 269        switch (glock.type) {
 270        case P9_LOCK_TYPE_RDLCK:
 271                fl->fl_type = F_RDLCK;
 272                break;
 273        case P9_LOCK_TYPE_WRLCK:
 274                fl->fl_type = F_WRLCK;
 275                break;
 276        case P9_LOCK_TYPE_UNLCK:
 277                fl->fl_type = F_UNLCK;
 278                break;
 279        }
 280        if (glock.type != P9_LOCK_TYPE_UNLCK) {
 281                fl->fl_start = glock.start;
 282                if (glock.length == 0)
 283                        fl->fl_end = OFFSET_MAX;
 284                else
 285                        fl->fl_end = glock.start + glock.length - 1;
 286                fl->fl_pid = glock.proc_id;
 287        }
 288        return res;
 289}
 290
 291/**
 292 * v9fs_file_lock_dotl - lock a file (or directory)
 293 * @filp: file to be locked
 294 * @cmd: lock command
 295 * @fl: file lock structure
 296 *
 297 */
 298
 299static int v9fs_file_lock_dotl(struct file *filp, int cmd, struct file_lock *fl)
 300{
 301        struct inode *inode = file_inode(filp);
 302        int ret = -ENOLCK;
 303
 304        p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n",
 305                 filp, cmd, fl, filp->f_path.dentry->d_name.name);
 306
 307        /* No mandatory locks */
 308        if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
 309                goto out_err;
 310
 311        if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
 312                filemap_write_and_wait(inode->i_mapping);
 313                invalidate_mapping_pages(&inode->i_data, 0, -1);
 314        }
 315
 316        if (IS_SETLK(cmd) || IS_SETLKW(cmd))
 317                ret = v9fs_file_do_lock(filp, cmd, fl);
 318        else if (IS_GETLK(cmd))
 319                ret = v9fs_file_getlock(filp, fl);
 320        else
 321                ret = -EINVAL;
 322out_err:
 323        return ret;
 324}
 325
 326/**
 327 * v9fs_file_flock_dotl - lock a file
 328 * @filp: file to be locked
 329 * @cmd: lock command
 330 * @fl: file lock structure
 331 *
 332 */
 333
 334static int v9fs_file_flock_dotl(struct file *filp, int cmd,
 335        struct file_lock *fl)
 336{
 337        struct inode *inode = file_inode(filp);
 338        int ret = -ENOLCK;
 339
 340        p9_debug(P9_DEBUG_VFS, "filp: %p cmd:%d lock: %p name: %s\n",
 341                 filp, cmd, fl, filp->f_path.dentry->d_name.name);
 342
 343        /* No mandatory locks */
 344        if (__mandatory_lock(inode) && fl->fl_type != F_UNLCK)
 345                goto out_err;
 346
 347        if (!(fl->fl_flags & FL_FLOCK))
 348                goto out_err;
 349
 350        if ((IS_SETLK(cmd) || IS_SETLKW(cmd)) && fl->fl_type != F_UNLCK) {
 351                filemap_write_and_wait(inode->i_mapping);
 352                invalidate_mapping_pages(&inode->i_data, 0, -1);
 353        }
 354        /* Convert flock to posix lock */
 355        fl->fl_flags |= FL_POSIX;
 356        fl->fl_flags ^= FL_FLOCK;
 357
 358        if (IS_SETLK(cmd) | IS_SETLKW(cmd))
 359                ret = v9fs_file_do_lock(filp, cmd, fl);
 360        else
 361                ret = -EINVAL;
 362out_err:
 363        return ret;
 364}
 365
 366/**
 367 * v9fs_fid_readn - read from a fid
 368 * @fid: fid to read
 369 * @data: data buffer to read data into
 370 * @udata: user data buffer to read data into
 371 * @count: size of buffer
 372 * @offset: offset at which to read data
 373 *
 374 */
 375ssize_t
 376v9fs_fid_readn(struct p9_fid *fid, char *data, char __user *udata, u32 count,
 377               u64 offset)
 378{
 379        int n, total, size;
 380
 381        p9_debug(P9_DEBUG_VFS, "fid %d offset %llu count %d\n",
 382                 fid->fid, (long long unsigned)offset, count);
 383        n = 0;
 384        total = 0;
 385        size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
 386        do {
 387                n = p9_client_read(fid, data, udata, offset, count);
 388                if (n <= 0)
 389                        break;
 390
 391                if (data)
 392                        data += n;
 393                if (udata)
 394                        udata += n;
 395
 396                offset += n;
 397                count -= n;
 398                total += n;
 399        } while (count > 0 && n == size);
 400
 401        if (n < 0)
 402                total = n;
 403
 404        return total;
 405}
 406
 407/**
 408 * v9fs_file_readn - read from a file
 409 * @filp: file pointer to read
 410 * @data: data buffer to read data into
 411 * @udata: user data buffer to read data into
 412 * @count: size of buffer
 413 * @offset: offset at which to read data
 414 *
 415 */
 416ssize_t
 417v9fs_file_readn(struct file *filp, char *data, char __user *udata, u32 count,
 418               u64 offset)
 419{
 420        return v9fs_fid_readn(filp->private_data, data, udata, count, offset);
 421}
 422
 423/**
 424 * v9fs_file_read - read from a file
 425 * @filp: file pointer to read
 426 * @udata: user data buffer to read data into
 427 * @count: size of buffer
 428 * @offset: offset at which to read data
 429 *
 430 */
 431
 432static ssize_t
 433v9fs_file_read(struct file *filp, char __user *udata, size_t count,
 434               loff_t * offset)
 435{
 436        int ret;
 437        struct p9_fid *fid;
 438        size_t size;
 439
 440        p9_debug(P9_DEBUG_VFS, "count %zu offset %lld\n", count, *offset);
 441        fid = filp->private_data;
 442
 443        size = fid->iounit ? fid->iounit : fid->clnt->msize - P9_IOHDRSZ;
 444        if (count > size)
 445                ret = v9fs_file_readn(filp, NULL, udata, count, *offset);
 446        else
 447                ret = p9_client_read(fid, NULL, udata, *offset, count);
 448
 449        if (ret > 0)
 450                *offset += ret;
 451
 452        return ret;
 453}
 454
 455ssize_t
 456v9fs_file_write_internal(struct inode *inode, struct p9_fid *fid,
 457                         const char __user *data, size_t count,
 458                         loff_t *offset, int invalidate)
 459{
 460        int n;
 461        loff_t i_size;
 462        size_t total = 0;
 463        loff_t origin = *offset;
 464        unsigned long pg_start, pg_end;
 465
 466        p9_debug(P9_DEBUG_VFS, "data %p count %d offset %x\n",
 467                 data, (int)count, (int)*offset);
 468
 469        do {
 470                n = p9_client_write(fid, NULL, data+total, origin+total, count);
 471                if (n <= 0)
 472                        break;
 473                count -= n;
 474                total += n;
 475        } while (count > 0);
 476
 477        if (invalidate && (total > 0)) {
 478                pg_start = origin >> PAGE_CACHE_SHIFT;
 479                pg_end = (origin + total - 1) >> PAGE_CACHE_SHIFT;
 480                if (inode->i_mapping && inode->i_mapping->nrpages)
 481                        invalidate_inode_pages2_range(inode->i_mapping,
 482                                                      pg_start, pg_end);
 483                *offset += total;
 484                i_size = i_size_read(inode);
 485                if (*offset > i_size) {
 486                        inode_add_bytes(inode, *offset - i_size);
 487                        i_size_write(inode, *offset);
 488                }
 489        }
 490        if (n < 0)
 491                return n;
 492
 493        return total;
 494}
 495
 496/**
 497 * v9fs_file_write - write to a file
 498 * @filp: file pointer to write
 499 * @data: data buffer to write data from
 500 * @count: size of buffer
 501 * @offset: offset at which to write data
 502 *
 503 */
 504static ssize_t
 505v9fs_file_write(struct file *filp, const char __user * data,
 506                size_t count, loff_t *offset)
 507{
 508        ssize_t retval = 0;
 509        loff_t origin = *offset;
 510
 511
 512        retval = generic_write_checks(filp, &origin, &count, 0);
 513        if (retval)
 514                goto out;
 515
 516        retval = -EINVAL;
 517        if ((ssize_t) count < 0)
 518                goto out;
 519        retval = 0;
 520        if (!count)
 521                goto out;
 522
 523        retval = v9fs_file_write_internal(file_inode(filp),
 524                                        filp->private_data,
 525                                        data, count, &origin, 1);
 526        /* update offset on successful write */
 527        if (retval > 0)
 528                *offset = origin;
 529out:
 530        return retval;
 531}
 532
 533
 534static int v9fs_file_fsync(struct file *filp, loff_t start, loff_t end,
 535                           int datasync)
 536{
 537        struct p9_fid *fid;
 538        struct inode *inode = filp->f_mapping->host;
 539        struct p9_wstat wstat;
 540        int retval;
 541
 542        retval = filemap_write_and_wait_range(inode->i_mapping, start, end);
 543        if (retval)
 544                return retval;
 545
 546        mutex_lock(&inode->i_mutex);
 547        p9_debug(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
 548
 549        fid = filp->private_data;
 550        v9fs_blank_wstat(&wstat);
 551
 552        retval = p9_client_wstat(fid, &wstat);
 553        mutex_unlock(&inode->i_mutex);
 554
 555        return retval;
 556}
 557
 558int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end,
 559                         int datasync)
 560{
 561        struct p9_fid *fid;
 562        struct inode *inode = filp->f_mapping->host;
 563        int retval;
 564
 565        retval = filemap_write_and_wait_range(inode->i_mapping, start, end);
 566        if (retval)
 567                return retval;
 568
 569        mutex_lock(&inode->i_mutex);
 570        p9_debug(P9_DEBUG_VFS, "filp %p datasync %x\n", filp, datasync);
 571
 572        fid = filp->private_data;
 573
 574        retval = p9_client_fsync(fid, datasync);
 575        mutex_unlock(&inode->i_mutex);
 576
 577        return retval;
 578}
 579
 580static int
 581v9fs_file_mmap(struct file *filp, struct vm_area_struct *vma)
 582{
 583        int retval;
 584
 585
 586        retval = generic_file_mmap(filp, vma);
 587        if (!retval)
 588                vma->vm_ops = &v9fs_file_vm_ops;
 589
 590        return retval;
 591}
 592
 593static int
 594v9fs_mmap_file_mmap(struct file *filp, struct vm_area_struct *vma)
 595{
 596        int retval;
 597        struct inode *inode;
 598        struct v9fs_inode *v9inode;
 599        struct p9_fid *fid;
 600
 601        inode = file_inode(filp);
 602        v9inode = V9FS_I(inode);
 603        mutex_lock(&v9inode->v_mutex);
 604        if (!v9inode->writeback_fid &&
 605            (vma->vm_flags & VM_WRITE)) {
 606                /*
 607                 * clone a fid and add it to writeback_fid
 608                 * we do it during mmap instead of
 609                 * page dirty time via write_begin/page_mkwrite
 610                 * because we want write after unlink usecase
 611                 * to work.
 612                 */
 613                fid = v9fs_writeback_fid(filp->f_path.dentry);
 614                if (IS_ERR(fid)) {
 615                        retval = PTR_ERR(fid);
 616                        mutex_unlock(&v9inode->v_mutex);
 617                        return retval;
 618                }
 619                v9inode->writeback_fid = (void *) fid;
 620        }
 621        mutex_unlock(&v9inode->v_mutex);
 622
 623        retval = generic_file_mmap(filp, vma);
 624        if (!retval)
 625                vma->vm_ops = &v9fs_mmap_file_vm_ops;
 626
 627        return retval;
 628}
 629
 630static int
 631v9fs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 632{
 633        struct v9fs_inode *v9inode;
 634        struct page *page = vmf->page;
 635        struct file *filp = vma->vm_file;
 636        struct inode *inode = file_inode(filp);
 637
 638
 639        p9_debug(P9_DEBUG_VFS, "page %p fid %lx\n",
 640                 page, (unsigned long)filp->private_data);
 641
 642        /* Update file times before taking page lock */
 643        file_update_time(filp);
 644
 645        v9inode = V9FS_I(inode);
 646        /* make sure the cache has finished storing the page */
 647        v9fs_fscache_wait_on_page_write(inode, page);
 648        BUG_ON(!v9inode->writeback_fid);
 649        lock_page(page);
 650        if (page->mapping != inode->i_mapping)
 651                goto out_unlock;
 652        wait_for_stable_page(page);
 653
 654        return VM_FAULT_LOCKED;
 655out_unlock:
 656        unlock_page(page);
 657        return VM_FAULT_NOPAGE;
 658}
 659
 660static ssize_t
 661v9fs_direct_read(struct file *filp, char __user *udata, size_t count,
 662                 loff_t *offsetp)
 663{
 664        loff_t size, offset;
 665        struct inode *inode;
 666        struct address_space *mapping;
 667
 668        offset = *offsetp;
 669        mapping = filp->f_mapping;
 670        inode = mapping->host;
 671        if (!count)
 672                return 0;
 673        size = i_size_read(inode);
 674        if (offset < size)
 675                filemap_write_and_wait_range(mapping, offset,
 676                                             offset + count - 1);
 677
 678        return v9fs_file_read(filp, udata, count, offsetp);
 679}
 680
 681/**
 682 * v9fs_cached_file_read - read from a file
 683 * @filp: file pointer to read
 684 * @data: user data buffer to read data into
 685 * @count: size of buffer
 686 * @offset: offset at which to read data
 687 *
 688 */
 689static ssize_t
 690v9fs_cached_file_read(struct file *filp, char __user *data, size_t count,
 691                      loff_t *offset)
 692{
 693        if (filp->f_flags & O_DIRECT)
 694                return v9fs_direct_read(filp, data, count, offset);
 695        return new_sync_read(filp, data, count, offset);
 696}
 697
 698/**
 699 * v9fs_mmap_file_read - read from a file
 700 * @filp: file pointer to read
 701 * @data: user data buffer to read data into
 702 * @count: size of buffer
 703 * @offset: offset at which to read data
 704 *
 705 */
 706static ssize_t
 707v9fs_mmap_file_read(struct file *filp, char __user *data, size_t count,
 708                      loff_t *offset)
 709{
 710        /* TODO: Check if there are dirty pages */
 711        return v9fs_file_read(filp, data, count, offset);
 712}
 713
 714static ssize_t
 715v9fs_direct_write(struct file *filp, const char __user * data,
 716                  size_t count, loff_t *offsetp)
 717{
 718        loff_t offset;
 719        ssize_t retval;
 720        struct inode *inode;
 721        struct address_space *mapping;
 722
 723        offset = *offsetp;
 724        mapping = filp->f_mapping;
 725        inode = mapping->host;
 726        if (!count)
 727                return 0;
 728
 729        mutex_lock(&inode->i_mutex);
 730        retval = filemap_write_and_wait_range(mapping, offset,
 731                                              offset + count - 1);
 732        if (retval)
 733                goto err_out;
 734        /*
 735         * After a write we want buffered reads to be sure to go to disk to get
 736         * the new data.  We invalidate clean cached page from the region we're
 737         * about to write.  We do this *before* the write so that if we fail
 738         * here we fall back to buffered write
 739         */
 740        if (mapping->nrpages) {
 741                pgoff_t pg_start = offset >> PAGE_CACHE_SHIFT;
 742                pgoff_t pg_end   = (offset + count - 1) >> PAGE_CACHE_SHIFT;
 743
 744                retval = invalidate_inode_pages2_range(mapping,
 745                                                        pg_start, pg_end);
 746                /*
 747                 * If a page can not be invalidated, fall back
 748                 * to buffered write.
 749                 */
 750                if (retval) {
 751                        if (retval == -EBUSY)
 752                                goto buff_write;
 753                        goto err_out;
 754                }
 755        }
 756        retval = v9fs_file_write(filp, data, count, offsetp);
 757err_out:
 758        mutex_unlock(&inode->i_mutex);
 759        return retval;
 760
 761buff_write:
 762        mutex_unlock(&inode->i_mutex);
 763        return new_sync_write(filp, data, count, offsetp);
 764}
 765
 766/**
 767 * v9fs_cached_file_write - write to a file
 768 * @filp: file pointer to write
 769 * @data: data buffer to write data from
 770 * @count: size of buffer
 771 * @offset: offset at which to write data
 772 *
 773 */
 774static ssize_t
 775v9fs_cached_file_write(struct file *filp, const char __user * data,
 776                       size_t count, loff_t *offset)
 777{
 778
 779        if (filp->f_flags & O_DIRECT)
 780                return v9fs_direct_write(filp, data, count, offset);
 781        return new_sync_write(filp, data, count, offset);
 782}
 783
 784
 785/**
 786 * v9fs_mmap_file_write - write to a file
 787 * @filp: file pointer to write
 788 * @data: data buffer to write data from
 789 * @count: size of buffer
 790 * @offset: offset at which to write data
 791 *
 792 */
 793static ssize_t
 794v9fs_mmap_file_write(struct file *filp, const char __user *data,
 795                       size_t count, loff_t *offset)
 796{
 797        /*
 798         * TODO: invalidate mmaps on filp's inode between
 799         * offset and offset+count
 800         */
 801        return v9fs_file_write(filp, data, count, offset);
 802}
 803
 804static void v9fs_mmap_vm_close(struct vm_area_struct *vma)
 805{
 806        struct inode *inode;
 807
 808        struct writeback_control wbc = {
 809                .nr_to_write = LONG_MAX,
 810                .sync_mode = WB_SYNC_ALL,
 811                .range_start = vma->vm_pgoff * PAGE_SIZE,
 812                 /* absolute end, byte at end included */
 813                .range_end = vma->vm_pgoff * PAGE_SIZE +
 814                        (vma->vm_end - vma->vm_start - 1),
 815        };
 816
 817
 818        p9_debug(P9_DEBUG_VFS, "9p VMA close, %p, flushing", vma);
 819
 820        inode = file_inode(vma->vm_file);
 821
 822        if (!mapping_cap_writeback_dirty(inode->i_mapping))
 823                wbc.nr_to_write = 0;
 824
 825        might_sleep();
 826        sync_inode(inode, &wbc);
 827}
 828
 829
 830static const struct vm_operations_struct v9fs_file_vm_ops = {
 831        .fault = filemap_fault,
 832        .map_pages = filemap_map_pages,
 833        .page_mkwrite = v9fs_vm_page_mkwrite,
 834        .remap_pages = generic_file_remap_pages,
 835};
 836
 837static const struct vm_operations_struct v9fs_mmap_file_vm_ops = {
 838        .close = v9fs_mmap_vm_close,
 839        .fault = filemap_fault,
 840        .map_pages = filemap_map_pages,
 841        .page_mkwrite = v9fs_vm_page_mkwrite,
 842        .remap_pages = generic_file_remap_pages,
 843};
 844
 845
 846const struct file_operations v9fs_cached_file_operations = {
 847        .llseek = generic_file_llseek,
 848        .read = v9fs_cached_file_read,
 849        .write = v9fs_cached_file_write,
 850        .read_iter = generic_file_read_iter,
 851        .write_iter = generic_file_write_iter,
 852        .open = v9fs_file_open,
 853        .release = v9fs_dir_release,
 854        .lock = v9fs_file_lock,
 855        .mmap = v9fs_file_mmap,
 856        .fsync = v9fs_file_fsync,
 857};
 858
 859const struct file_operations v9fs_cached_file_operations_dotl = {
 860        .llseek = generic_file_llseek,
 861        .read = v9fs_cached_file_read,
 862        .write = v9fs_cached_file_write,
 863        .read_iter = generic_file_read_iter,
 864        .write_iter = generic_file_write_iter,
 865        .open = v9fs_file_open,
 866        .release = v9fs_dir_release,
 867        .lock = v9fs_file_lock_dotl,
 868        .flock = v9fs_file_flock_dotl,
 869        .mmap = v9fs_file_mmap,
 870        .fsync = v9fs_file_fsync_dotl,
 871};
 872
 873const struct file_operations v9fs_file_operations = {
 874        .llseek = generic_file_llseek,
 875        .read = v9fs_file_read,
 876        .write = v9fs_file_write,
 877        .open = v9fs_file_open,
 878        .release = v9fs_dir_release,
 879        .lock = v9fs_file_lock,
 880        .mmap = generic_file_readonly_mmap,
 881        .fsync = v9fs_file_fsync,
 882};
 883
 884const struct file_operations v9fs_file_operations_dotl = {
 885        .llseek = generic_file_llseek,
 886        .read = v9fs_file_read,
 887        .write = v9fs_file_write,
 888        .open = v9fs_file_open,
 889        .release = v9fs_dir_release,
 890        .lock = v9fs_file_lock_dotl,
 891        .flock = v9fs_file_flock_dotl,
 892        .mmap = generic_file_readonly_mmap,
 893        .fsync = v9fs_file_fsync_dotl,
 894};
 895
 896const struct file_operations v9fs_mmap_file_operations = {
 897        .llseek = generic_file_llseek,
 898        .read = v9fs_mmap_file_read,
 899        .write = v9fs_mmap_file_write,
 900        .open = v9fs_file_open,
 901        .release = v9fs_dir_release,
 902        .lock = v9fs_file_lock,
 903        .mmap = v9fs_mmap_file_mmap,
 904        .fsync = v9fs_file_fsync,
 905};
 906
 907const struct file_operations v9fs_mmap_file_operations_dotl = {
 908        .llseek = generic_file_llseek,
 909        .read = v9fs_mmap_file_read,
 910        .write = v9fs_mmap_file_write,
 911        .open = v9fs_file_open,
 912        .release = v9fs_dir_release,
 913        .lock = v9fs_file_lock_dotl,
 914        .flock = v9fs_file_flock_dotl,
 915        .mmap = v9fs_mmap_file_mmap,
 916        .fsync = v9fs_file_fsync_dotl,
 917};
 918