linux/fs/9p/vfs_inode_dotl.c
<<
>>
Prefs
   1/*
   2 *  linux/fs/9p/vfs_inode_dotl.c
   3 *
   4 * This file contains vfs inode ops for the 9P2000.L protocol.
   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/file.h>
  30#include <linux/pagemap.h>
  31#include <linux/stat.h>
  32#include <linux/string.h>
  33#include <linux/inet.h>
  34#include <linux/namei.h>
  35#include <linux/idr.h>
  36#include <linux/sched.h>
  37#include <linux/slab.h>
  38#include <linux/xattr.h>
  39#include <linux/posix_acl.h>
  40#include <net/9p/9p.h>
  41#include <net/9p/client.h>
  42
  43#include "v9fs.h"
  44#include "v9fs_vfs.h"
  45#include "fid.h"
  46#include "cache.h"
  47#include "xattr.h"
  48#include "acl.h"
  49
  50static int
  51v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
  52                    dev_t rdev);
  53
  54/**
  55 * v9fs_get_fsgid_for_create - Helper function to get the gid for creating a
  56 * new file system object. This checks the S_ISGID to determine the owning
  57 * group of the new file system object.
  58 */
  59
  60static gid_t v9fs_get_fsgid_for_create(struct inode *dir_inode)
  61{
  62        BUG_ON(dir_inode == NULL);
  63
  64        if (dir_inode->i_mode & S_ISGID) {
  65                /* set_gid bit is set.*/
  66                return dir_inode->i_gid;
  67        }
  68        return current_fsgid();
  69}
  70
  71static int v9fs_test_inode_dotl(struct inode *inode, void *data)
  72{
  73        struct v9fs_inode *v9inode = V9FS_I(inode);
  74        struct p9_stat_dotl *st = (struct p9_stat_dotl *)data;
  75
  76        /* don't match inode of different type */
  77        if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT))
  78                return 0;
  79
  80        if (inode->i_generation != st->st_gen)
  81                return 0;
  82
  83        /* compare qid details */
  84        if (memcmp(&v9inode->qid.version,
  85                   &st->qid.version, sizeof(v9inode->qid.version)))
  86                return 0;
  87
  88        if (v9inode->qid.type != st->qid.type)
  89                return 0;
  90        return 1;
  91}
  92
  93/* Always get a new inode */
  94static int v9fs_test_new_inode_dotl(struct inode *inode, void *data)
  95{
  96        return 0;
  97}
  98
  99static int v9fs_set_inode_dotl(struct inode *inode,  void *data)
 100{
 101        struct v9fs_inode *v9inode = V9FS_I(inode);
 102        struct p9_stat_dotl *st = (struct p9_stat_dotl *)data;
 103
 104        memcpy(&v9inode->qid, &st->qid, sizeof(st->qid));
 105        inode->i_generation = st->st_gen;
 106        return 0;
 107}
 108
 109static struct inode *v9fs_qid_iget_dotl(struct super_block *sb,
 110                                        struct p9_qid *qid,
 111                                        struct p9_fid *fid,
 112                                        struct p9_stat_dotl *st,
 113                                        int new)
 114{
 115        int retval;
 116        unsigned long i_ino;
 117        struct inode *inode;
 118        struct v9fs_session_info *v9ses = sb->s_fs_info;
 119        int (*test)(struct inode *, void *);
 120
 121        if (new)
 122                test = v9fs_test_new_inode_dotl;
 123        else
 124                test = v9fs_test_inode_dotl;
 125
 126        i_ino = v9fs_qid2ino(qid);
 127        inode = iget5_locked(sb, i_ino, test, v9fs_set_inode_dotl, st);
 128        if (!inode)
 129                return ERR_PTR(-ENOMEM);
 130        if (!(inode->i_state & I_NEW))
 131                return inode;
 132        /*
 133         * initialize the inode with the stat info
 134         * FIXME!! we may need support for stale inodes
 135         * later.
 136         */
 137        inode->i_ino = i_ino;
 138        retval = v9fs_init_inode(v9ses, inode,
 139                                 st->st_mode, new_decode_dev(st->st_rdev));
 140        if (retval)
 141                goto error;
 142
 143        v9fs_stat2inode_dotl(st, inode);
 144#ifdef CONFIG_9P_FSCACHE
 145        v9fs_cache_inode_get_cookie(inode);
 146#endif
 147        retval = v9fs_get_acl(inode, fid);
 148        if (retval)
 149                goto error;
 150
 151        unlock_new_inode(inode);
 152        return inode;
 153error:
 154        unlock_new_inode(inode);
 155        iput(inode);
 156        return ERR_PTR(retval);
 157
 158}
 159
 160struct inode *
 161v9fs_inode_from_fid_dotl(struct v9fs_session_info *v9ses, struct p9_fid *fid,
 162                         struct super_block *sb, int new)
 163{
 164        struct p9_stat_dotl *st;
 165        struct inode *inode = NULL;
 166
 167        st = p9_client_getattr_dotl(fid, P9_STATS_BASIC | P9_STATS_GEN);
 168        if (IS_ERR(st))
 169                return ERR_CAST(st);
 170
 171        inode = v9fs_qid_iget_dotl(sb, &st->qid, fid, st, new);
 172        kfree(st);
 173        return inode;
 174}
 175
 176struct dotl_openflag_map {
 177        int open_flag;
 178        int dotl_flag;
 179};
 180
 181static int v9fs_mapped_dotl_flags(int flags)
 182{
 183        int i;
 184        int rflags = 0;
 185        struct dotl_openflag_map dotl_oflag_map[] = {
 186                { O_CREAT,      P9_DOTL_CREATE },
 187                { O_EXCL,       P9_DOTL_EXCL },
 188                { O_NOCTTY,     P9_DOTL_NOCTTY },
 189                { O_TRUNC,      P9_DOTL_TRUNC },
 190                { O_APPEND,     P9_DOTL_APPEND },
 191                { O_NONBLOCK,   P9_DOTL_NONBLOCK },
 192                { O_DSYNC,      P9_DOTL_DSYNC },
 193                { FASYNC,       P9_DOTL_FASYNC },
 194                { O_DIRECT,     P9_DOTL_DIRECT },
 195                { O_LARGEFILE,  P9_DOTL_LARGEFILE },
 196                { O_DIRECTORY,  P9_DOTL_DIRECTORY },
 197                { O_NOFOLLOW,   P9_DOTL_NOFOLLOW },
 198                { O_NOATIME,    P9_DOTL_NOATIME },
 199                { O_CLOEXEC,    P9_DOTL_CLOEXEC },
 200                { O_SYNC,       P9_DOTL_SYNC},
 201        };
 202        for (i = 0; i < ARRAY_SIZE(dotl_oflag_map); i++) {
 203                if (flags & dotl_oflag_map[i].open_flag)
 204                        rflags |= dotl_oflag_map[i].dotl_flag;
 205        }
 206        return rflags;
 207}
 208
 209/**
 210 * v9fs_open_to_dotl_flags- convert Linux specific open flags to
 211 * plan 9 open flag.
 212 * @flags: flags to convert
 213 */
 214int v9fs_open_to_dotl_flags(int flags)
 215{
 216        int rflags = 0;
 217
 218        /*
 219         * We have same bits for P9_DOTL_READONLY, P9_DOTL_WRONLY
 220         * and P9_DOTL_NOACCESS
 221         */
 222        rflags |= flags & O_ACCMODE;
 223        rflags |= v9fs_mapped_dotl_flags(flags);
 224
 225        return rflags;
 226}
 227
 228/**
 229 * v9fs_vfs_create_dotl - VFS hook to create files for 9P2000.L protocol.
 230 * @dir: directory inode that is being created
 231 * @dentry:  dentry that is being deleted
 232 * @mode: create permissions
 233 *
 234 */
 235
 236static int
 237v9fs_vfs_create_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
 238                bool excl)
 239{
 240        return v9fs_vfs_mknod_dotl(dir, dentry, omode, 0);
 241}
 242
 243static int
 244v9fs_vfs_atomic_open_dotl(struct inode *dir, struct dentry *dentry,
 245                          struct file *file, unsigned flags, umode_t omode,
 246                          int *opened)
 247{
 248        int err = 0;
 249        gid_t gid;
 250        umode_t mode;
 251        char *name = NULL;
 252        struct p9_qid qid;
 253        struct inode *inode;
 254        struct p9_fid *fid = NULL;
 255        struct v9fs_inode *v9inode;
 256        struct p9_fid *dfid, *ofid, *inode_fid;
 257        struct v9fs_session_info *v9ses;
 258        struct posix_acl *pacl = NULL, *dacl = NULL;
 259        struct dentry *res = NULL;
 260
 261        if (d_unhashed(dentry)) {
 262                res = v9fs_vfs_lookup(dir, dentry, 0);
 263                if (IS_ERR(res))
 264                        return PTR_ERR(res);
 265
 266                if (res)
 267                        dentry = res;
 268        }
 269
 270        /* Only creates */
 271        if (!(flags & O_CREAT) || dentry->d_inode)
 272                return finish_no_open(file, res);
 273
 274        v9ses = v9fs_inode2v9ses(dir);
 275
 276        name = (char *) dentry->d_name.name;
 277        p9_debug(P9_DEBUG_VFS, "name:%s flags:0x%x mode:0x%hx\n",
 278                 name, flags, omode);
 279
 280        dfid = v9fs_fid_lookup(dentry->d_parent);
 281        if (IS_ERR(dfid)) {
 282                err = PTR_ERR(dfid);
 283                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
 284                goto out;
 285        }
 286
 287        /* clone a fid to use for creation */
 288        ofid = p9_client_walk(dfid, 0, NULL, 1);
 289        if (IS_ERR(ofid)) {
 290                err = PTR_ERR(ofid);
 291                p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
 292                goto out;
 293        }
 294
 295        gid = v9fs_get_fsgid_for_create(dir);
 296
 297        mode = omode;
 298        /* Update mode based on ACL value */
 299        err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
 300        if (err) {
 301                p9_debug(P9_DEBUG_VFS, "Failed to get acl values in creat %d\n",
 302                         err);
 303                goto error;
 304        }
 305        err = p9_client_create_dotl(ofid, name, v9fs_open_to_dotl_flags(flags),
 306                                    mode, gid, &qid);
 307        if (err < 0) {
 308                p9_debug(P9_DEBUG_VFS, "p9_client_open_dotl failed in creat %d\n",
 309                         err);
 310                goto error;
 311        }
 312        v9fs_invalidate_inode_attr(dir);
 313
 314        /* instantiate inode and assign the unopened fid to the dentry */
 315        fid = p9_client_walk(dfid, 1, &name, 1);
 316        if (IS_ERR(fid)) {
 317                err = PTR_ERR(fid);
 318                p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n", err);
 319                fid = NULL;
 320                goto error;
 321        }
 322        inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
 323        if (IS_ERR(inode)) {
 324                err = PTR_ERR(inode);
 325                p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n", err);
 326                goto error;
 327        }
 328        err = v9fs_fid_add(dentry, fid);
 329        if (err < 0)
 330                goto error;
 331        d_instantiate(dentry, inode);
 332
 333        /* Now set the ACL based on the default value */
 334        v9fs_set_create_acl(dentry, &dacl, &pacl);
 335
 336        v9inode = V9FS_I(inode);
 337        mutex_lock(&v9inode->v_mutex);
 338        if (v9ses->cache && !v9inode->writeback_fid &&
 339            ((flags & O_ACCMODE) != O_RDONLY)) {
 340                /*
 341                 * clone a fid and add it to writeback_fid
 342                 * we do it during open time instead of
 343                 * page dirty time via write_begin/page_mkwrite
 344                 * because we want write after unlink usecase
 345                 * to work.
 346                 */
 347                inode_fid = v9fs_writeback_fid(dentry);
 348                if (IS_ERR(inode_fid)) {
 349                        err = PTR_ERR(inode_fid);
 350                        mutex_unlock(&v9inode->v_mutex);
 351                        goto err_clunk_old_fid;
 352                }
 353                v9inode->writeback_fid = (void *) inode_fid;
 354        }
 355        mutex_unlock(&v9inode->v_mutex);
 356        /* Since we are opening a file, assign the open fid to the file */
 357        err = finish_open(file, dentry, generic_file_open, opened);
 358        if (err)
 359                goto err_clunk_old_fid;
 360        file->private_data = ofid;
 361#ifdef CONFIG_9P_FSCACHE
 362        if (v9ses->cache)
 363                v9fs_cache_inode_set_cookie(inode, file);
 364#endif
 365        *opened |= FILE_CREATED;
 366out:
 367        dput(res);
 368        return err;
 369
 370error:
 371        if (fid)
 372                p9_client_clunk(fid);
 373err_clunk_old_fid:
 374        if (ofid)
 375                p9_client_clunk(ofid);
 376        v9fs_set_create_acl(NULL, &dacl, &pacl);
 377        goto out;
 378}
 379
 380/**
 381 * v9fs_vfs_mkdir_dotl - VFS mkdir hook to create a directory
 382 * @dir:  inode that is being unlinked
 383 * @dentry: dentry that is being unlinked
 384 * @mode: mode for new directory
 385 *
 386 */
 387
 388static int v9fs_vfs_mkdir_dotl(struct inode *dir,
 389                               struct dentry *dentry, umode_t omode)
 390{
 391        int err;
 392        struct v9fs_session_info *v9ses;
 393        struct p9_fid *fid = NULL, *dfid = NULL;
 394        gid_t gid;
 395        char *name;
 396        umode_t mode;
 397        struct inode *inode;
 398        struct p9_qid qid;
 399        struct dentry *dir_dentry;
 400        struct posix_acl *dacl = NULL, *pacl = NULL;
 401
 402        p9_debug(P9_DEBUG_VFS, "name %s\n", dentry->d_name.name);
 403        err = 0;
 404        v9ses = v9fs_inode2v9ses(dir);
 405
 406        omode |= S_IFDIR;
 407        if (dir->i_mode & S_ISGID)
 408                omode |= S_ISGID;
 409
 410        dir_dentry = dentry->d_parent;
 411        dfid = v9fs_fid_lookup(dir_dentry);
 412        if (IS_ERR(dfid)) {
 413                err = PTR_ERR(dfid);
 414                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
 415                dfid = NULL;
 416                goto error;
 417        }
 418
 419        gid = v9fs_get_fsgid_for_create(dir);
 420        mode = omode;
 421        /* Update mode based on ACL value */
 422        err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
 423        if (err) {
 424                p9_debug(P9_DEBUG_VFS, "Failed to get acl values in mkdir %d\n",
 425                         err);
 426                goto error;
 427        }
 428        name = (char *) dentry->d_name.name;
 429        err = p9_client_mkdir_dotl(dfid, name, mode, gid, &qid);
 430        if (err < 0)
 431                goto error;
 432
 433        /* instantiate inode and assign the unopened fid to the dentry */
 434        if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
 435                fid = p9_client_walk(dfid, 1, &name, 1);
 436                if (IS_ERR(fid)) {
 437                        err = PTR_ERR(fid);
 438                        p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
 439                                 err);
 440                        fid = NULL;
 441                        goto error;
 442                }
 443
 444                inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
 445                if (IS_ERR(inode)) {
 446                        err = PTR_ERR(inode);
 447                        p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
 448                                 err);
 449                        goto error;
 450                }
 451                err = v9fs_fid_add(dentry, fid);
 452                if (err < 0)
 453                        goto error;
 454                d_instantiate(dentry, inode);
 455                fid = NULL;
 456        } else {
 457                /*
 458                 * Not in cached mode. No need to populate
 459                 * inode with stat. We need to get an inode
 460                 * so that we can set the acl with dentry
 461                 */
 462                inode = v9fs_get_inode(dir->i_sb, mode, 0);
 463                if (IS_ERR(inode)) {
 464                        err = PTR_ERR(inode);
 465                        goto error;
 466                }
 467                d_instantiate(dentry, inode);
 468        }
 469        /* Now set the ACL based on the default value */
 470        v9fs_set_create_acl(dentry, &dacl, &pacl);
 471        inc_nlink(dir);
 472        v9fs_invalidate_inode_attr(dir);
 473error:
 474        if (fid)
 475                p9_client_clunk(fid);
 476        v9fs_set_create_acl(NULL, &dacl, &pacl);
 477        return err;
 478}
 479
 480static int
 481v9fs_vfs_getattr_dotl(struct vfsmount *mnt, struct dentry *dentry,
 482                 struct kstat *stat)
 483{
 484        int err;
 485        struct v9fs_session_info *v9ses;
 486        struct p9_fid *fid;
 487        struct p9_stat_dotl *st;
 488
 489        p9_debug(P9_DEBUG_VFS, "dentry: %p\n", dentry);
 490        err = -EPERM;
 491        v9ses = v9fs_dentry2v9ses(dentry);
 492        if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
 493                generic_fillattr(dentry->d_inode, stat);
 494                return 0;
 495        }
 496        fid = v9fs_fid_lookup(dentry);
 497        if (IS_ERR(fid))
 498                return PTR_ERR(fid);
 499
 500        /* Ask for all the fields in stat structure. Server will return
 501         * whatever it supports
 502         */
 503
 504        st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
 505        if (IS_ERR(st))
 506                return PTR_ERR(st);
 507
 508        v9fs_stat2inode_dotl(st, dentry->d_inode);
 509        generic_fillattr(dentry->d_inode, stat);
 510        /* Change block size to what the server returned */
 511        stat->blksize = st->st_blksize;
 512
 513        kfree(st);
 514        return 0;
 515}
 516
 517/*
 518 * Attribute flags.
 519 */
 520#define P9_ATTR_MODE            (1 << 0)
 521#define P9_ATTR_UID             (1 << 1)
 522#define P9_ATTR_GID             (1 << 2)
 523#define P9_ATTR_SIZE            (1 << 3)
 524#define P9_ATTR_ATIME           (1 << 4)
 525#define P9_ATTR_MTIME           (1 << 5)
 526#define P9_ATTR_CTIME           (1 << 6)
 527#define P9_ATTR_ATIME_SET       (1 << 7)
 528#define P9_ATTR_MTIME_SET       (1 << 8)
 529
 530struct dotl_iattr_map {
 531        int iattr_valid;
 532        int p9_iattr_valid;
 533};
 534
 535static int v9fs_mapped_iattr_valid(int iattr_valid)
 536{
 537        int i;
 538        int p9_iattr_valid = 0;
 539        struct dotl_iattr_map dotl_iattr_map[] = {
 540                { ATTR_MODE,            P9_ATTR_MODE },
 541                { ATTR_UID,             P9_ATTR_UID },
 542                { ATTR_GID,             P9_ATTR_GID },
 543                { ATTR_SIZE,            P9_ATTR_SIZE },
 544                { ATTR_ATIME,           P9_ATTR_ATIME },
 545                { ATTR_MTIME,           P9_ATTR_MTIME },
 546                { ATTR_CTIME,           P9_ATTR_CTIME },
 547                { ATTR_ATIME_SET,       P9_ATTR_ATIME_SET },
 548                { ATTR_MTIME_SET,       P9_ATTR_MTIME_SET },
 549        };
 550        for (i = 0; i < ARRAY_SIZE(dotl_iattr_map); i++) {
 551                if (iattr_valid & dotl_iattr_map[i].iattr_valid)
 552                        p9_iattr_valid |= dotl_iattr_map[i].p9_iattr_valid;
 553        }
 554        return p9_iattr_valid;
 555}
 556
 557/**
 558 * v9fs_vfs_setattr_dotl - set file metadata
 559 * @dentry: file whose metadata to set
 560 * @iattr: metadata assignment structure
 561 *
 562 */
 563
 564int v9fs_vfs_setattr_dotl(struct dentry *dentry, struct iattr *iattr)
 565{
 566        int retval;
 567        struct v9fs_session_info *v9ses;
 568        struct p9_fid *fid;
 569        struct p9_iattr_dotl p9attr;
 570
 571        p9_debug(P9_DEBUG_VFS, "\n");
 572
 573        retval = inode_change_ok(dentry->d_inode, iattr);
 574        if (retval)
 575                return retval;
 576
 577        p9attr.valid = v9fs_mapped_iattr_valid(iattr->ia_valid);
 578        p9attr.mode = iattr->ia_mode;
 579        p9attr.uid = iattr->ia_uid;
 580        p9attr.gid = iattr->ia_gid;
 581        p9attr.size = iattr->ia_size;
 582        p9attr.atime_sec = iattr->ia_atime.tv_sec;
 583        p9attr.atime_nsec = iattr->ia_atime.tv_nsec;
 584        p9attr.mtime_sec = iattr->ia_mtime.tv_sec;
 585        p9attr.mtime_nsec = iattr->ia_mtime.tv_nsec;
 586
 587        retval = -EPERM;
 588        v9ses = v9fs_dentry2v9ses(dentry);
 589        fid = v9fs_fid_lookup(dentry);
 590        if (IS_ERR(fid))
 591                return PTR_ERR(fid);
 592
 593        /* Write all dirty data */
 594        if (S_ISREG(dentry->d_inode->i_mode))
 595                filemap_write_and_wait(dentry->d_inode->i_mapping);
 596
 597        retval = p9_client_setattr(fid, &p9attr);
 598        if (retval < 0)
 599                return retval;
 600
 601        if ((iattr->ia_valid & ATTR_SIZE) &&
 602            iattr->ia_size != i_size_read(dentry->d_inode))
 603                truncate_setsize(dentry->d_inode, iattr->ia_size);
 604
 605        v9fs_invalidate_inode_attr(dentry->d_inode);
 606        setattr_copy(dentry->d_inode, iattr);
 607        mark_inode_dirty(dentry->d_inode);
 608        if (iattr->ia_valid & ATTR_MODE) {
 609                /* We also want to update ACL when we update mode bits */
 610                retval = v9fs_acl_chmod(dentry);
 611                if (retval < 0)
 612                        return retval;
 613        }
 614        return 0;
 615}
 616
 617/**
 618 * v9fs_stat2inode_dotl - populate an inode structure with stat info
 619 * @stat: stat structure
 620 * @inode: inode to populate
 621 * @sb: superblock of filesystem
 622 *
 623 */
 624
 625void
 626v9fs_stat2inode_dotl(struct p9_stat_dotl *stat, struct inode *inode)
 627{
 628        umode_t mode;
 629        struct v9fs_inode *v9inode = V9FS_I(inode);
 630
 631        if ((stat->st_result_mask & P9_STATS_BASIC) == P9_STATS_BASIC) {
 632                inode->i_atime.tv_sec = stat->st_atime_sec;
 633                inode->i_atime.tv_nsec = stat->st_atime_nsec;
 634                inode->i_mtime.tv_sec = stat->st_mtime_sec;
 635                inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
 636                inode->i_ctime.tv_sec = stat->st_ctime_sec;
 637                inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
 638                inode->i_uid = stat->st_uid;
 639                inode->i_gid = stat->st_gid;
 640                set_nlink(inode, stat->st_nlink);
 641
 642                mode = stat->st_mode & S_IALLUGO;
 643                mode |= inode->i_mode & ~S_IALLUGO;
 644                inode->i_mode = mode;
 645
 646                i_size_write(inode, stat->st_size);
 647                inode->i_blocks = stat->st_blocks;
 648        } else {
 649                if (stat->st_result_mask & P9_STATS_ATIME) {
 650                        inode->i_atime.tv_sec = stat->st_atime_sec;
 651                        inode->i_atime.tv_nsec = stat->st_atime_nsec;
 652                }
 653                if (stat->st_result_mask & P9_STATS_MTIME) {
 654                        inode->i_mtime.tv_sec = stat->st_mtime_sec;
 655                        inode->i_mtime.tv_nsec = stat->st_mtime_nsec;
 656                }
 657                if (stat->st_result_mask & P9_STATS_CTIME) {
 658                        inode->i_ctime.tv_sec = stat->st_ctime_sec;
 659                        inode->i_ctime.tv_nsec = stat->st_ctime_nsec;
 660                }
 661                if (stat->st_result_mask & P9_STATS_UID)
 662                        inode->i_uid = stat->st_uid;
 663                if (stat->st_result_mask & P9_STATS_GID)
 664                        inode->i_gid = stat->st_gid;
 665                if (stat->st_result_mask & P9_STATS_NLINK)
 666                        set_nlink(inode, stat->st_nlink);
 667                if (stat->st_result_mask & P9_STATS_MODE) {
 668                        inode->i_mode = stat->st_mode;
 669                        if ((S_ISBLK(inode->i_mode)) ||
 670                                                (S_ISCHR(inode->i_mode)))
 671                                init_special_inode(inode, inode->i_mode,
 672                                                                inode->i_rdev);
 673                }
 674                if (stat->st_result_mask & P9_STATS_RDEV)
 675                        inode->i_rdev = new_decode_dev(stat->st_rdev);
 676                if (stat->st_result_mask & P9_STATS_SIZE)
 677                        i_size_write(inode, stat->st_size);
 678                if (stat->st_result_mask & P9_STATS_BLOCKS)
 679                        inode->i_blocks = stat->st_blocks;
 680        }
 681        if (stat->st_result_mask & P9_STATS_GEN)
 682                inode->i_generation = stat->st_gen;
 683
 684        /* Currently we don't support P9_STATS_BTIME and P9_STATS_DATA_VERSION
 685         * because the inode structure does not have fields for them.
 686         */
 687        v9inode->cache_validity &= ~V9FS_INO_INVALID_ATTR;
 688}
 689
 690static int
 691v9fs_vfs_symlink_dotl(struct inode *dir, struct dentry *dentry,
 692                const char *symname)
 693{
 694        int err;
 695        gid_t gid;
 696        char *name;
 697        struct p9_qid qid;
 698        struct inode *inode;
 699        struct p9_fid *dfid;
 700        struct p9_fid *fid = NULL;
 701        struct v9fs_session_info *v9ses;
 702
 703        name = (char *) dentry->d_name.name;
 704        p9_debug(P9_DEBUG_VFS, "%lu,%s,%s\n", dir->i_ino, name, symname);
 705        v9ses = v9fs_inode2v9ses(dir);
 706
 707        dfid = v9fs_fid_lookup(dentry->d_parent);
 708        if (IS_ERR(dfid)) {
 709                err = PTR_ERR(dfid);
 710                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
 711                return err;
 712        }
 713
 714        gid = v9fs_get_fsgid_for_create(dir);
 715
 716        /* Server doesn't alter fid on TSYMLINK. Hence no need to clone it. */
 717        err = p9_client_symlink(dfid, name, (char *)symname, gid, &qid);
 718
 719        if (err < 0) {
 720                p9_debug(P9_DEBUG_VFS, "p9_client_symlink failed %d\n", err);
 721                goto error;
 722        }
 723
 724        v9fs_invalidate_inode_attr(dir);
 725        if (v9ses->cache) {
 726                /* Now walk from the parent so we can get an unopened fid. */
 727                fid = p9_client_walk(dfid, 1, &name, 1);
 728                if (IS_ERR(fid)) {
 729                        err = PTR_ERR(fid);
 730                        p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
 731                                 err);
 732                        fid = NULL;
 733                        goto error;
 734                }
 735
 736                /* instantiate inode and assign the unopened fid to dentry */
 737                inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
 738                if (IS_ERR(inode)) {
 739                        err = PTR_ERR(inode);
 740                        p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
 741                                 err);
 742                        goto error;
 743                }
 744                err = v9fs_fid_add(dentry, fid);
 745                if (err < 0)
 746                        goto error;
 747                d_instantiate(dentry, inode);
 748                fid = NULL;
 749        } else {
 750                /* Not in cached mode. No need to populate inode with stat */
 751                inode = v9fs_get_inode(dir->i_sb, S_IFLNK, 0);
 752                if (IS_ERR(inode)) {
 753                        err = PTR_ERR(inode);
 754                        goto error;
 755                }
 756                d_instantiate(dentry, inode);
 757        }
 758
 759error:
 760        if (fid)
 761                p9_client_clunk(fid);
 762
 763        return err;
 764}
 765
 766/**
 767 * v9fs_vfs_link_dotl - create a hardlink for dotl
 768 * @old_dentry: dentry for file to link to
 769 * @dir: inode destination for new link
 770 * @dentry: dentry for link
 771 *
 772 */
 773
 774static int
 775v9fs_vfs_link_dotl(struct dentry *old_dentry, struct inode *dir,
 776                struct dentry *dentry)
 777{
 778        int err;
 779        char *name;
 780        struct dentry *dir_dentry;
 781        struct p9_fid *dfid, *oldfid;
 782        struct v9fs_session_info *v9ses;
 783
 784        p9_debug(P9_DEBUG_VFS, "dir ino: %lu, old_name: %s, new_name: %s\n",
 785                 dir->i_ino, old_dentry->d_name.name, dentry->d_name.name);
 786
 787        v9ses = v9fs_inode2v9ses(dir);
 788        dir_dentry = dentry->d_parent;
 789        dfid = v9fs_fid_lookup(dir_dentry);
 790        if (IS_ERR(dfid))
 791                return PTR_ERR(dfid);
 792
 793        oldfid = v9fs_fid_lookup(old_dentry);
 794        if (IS_ERR(oldfid))
 795                return PTR_ERR(oldfid);
 796
 797        name = (char *) dentry->d_name.name;
 798
 799        err = p9_client_link(dfid, oldfid, (char *)dentry->d_name.name);
 800
 801        if (err < 0) {
 802                p9_debug(P9_DEBUG_VFS, "p9_client_link failed %d\n", err);
 803                return err;
 804        }
 805
 806        v9fs_invalidate_inode_attr(dir);
 807        if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
 808                /* Get the latest stat info from server. */
 809                struct p9_fid *fid;
 810                fid = v9fs_fid_lookup(old_dentry);
 811                if (IS_ERR(fid))
 812                        return PTR_ERR(fid);
 813
 814                v9fs_refresh_inode_dotl(fid, old_dentry->d_inode);
 815        }
 816        ihold(old_dentry->d_inode);
 817        d_instantiate(dentry, old_dentry->d_inode);
 818
 819        return err;
 820}
 821
 822/**
 823 * v9fs_vfs_mknod_dotl - create a special file
 824 * @dir: inode destination for new link
 825 * @dentry: dentry for file
 826 * @mode: mode for creation
 827 * @rdev: device associated with special file
 828 *
 829 */
 830static int
 831v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
 832                dev_t rdev)
 833{
 834        int err;
 835        gid_t gid;
 836        char *name;
 837        umode_t mode;
 838        struct v9fs_session_info *v9ses;
 839        struct p9_fid *fid = NULL, *dfid = NULL;
 840        struct inode *inode;
 841        struct p9_qid qid;
 842        struct dentry *dir_dentry;
 843        struct posix_acl *dacl = NULL, *pacl = NULL;
 844
 845        p9_debug(P9_DEBUG_VFS, " %lu,%s mode: %hx MAJOR: %u MINOR: %u\n",
 846                 dir->i_ino, dentry->d_name.name, omode,
 847                 MAJOR(rdev), MINOR(rdev));
 848
 849        if (!new_valid_dev(rdev))
 850                return -EINVAL;
 851
 852        v9ses = v9fs_inode2v9ses(dir);
 853        dir_dentry = dentry->d_parent;
 854        dfid = v9fs_fid_lookup(dir_dentry);
 855        if (IS_ERR(dfid)) {
 856                err = PTR_ERR(dfid);
 857                p9_debug(P9_DEBUG_VFS, "fid lookup failed %d\n", err);
 858                dfid = NULL;
 859                goto error;
 860        }
 861
 862        gid = v9fs_get_fsgid_for_create(dir);
 863        mode = omode;
 864        /* Update mode based on ACL value */
 865        err = v9fs_acl_mode(dir, &mode, &dacl, &pacl);
 866        if (err) {
 867                p9_debug(P9_DEBUG_VFS, "Failed to get acl values in mknod %d\n",
 868                         err);
 869                goto error;
 870        }
 871        name = (char *) dentry->d_name.name;
 872
 873        err = p9_client_mknod_dotl(dfid, name, mode, rdev, gid, &qid);
 874        if (err < 0)
 875                goto error;
 876
 877        v9fs_invalidate_inode_attr(dir);
 878        /* instantiate inode and assign the unopened fid to the dentry */
 879        if (v9ses->cache == CACHE_LOOSE || v9ses->cache == CACHE_FSCACHE) {
 880                fid = p9_client_walk(dfid, 1, &name, 1);
 881                if (IS_ERR(fid)) {
 882                        err = PTR_ERR(fid);
 883                        p9_debug(P9_DEBUG_VFS, "p9_client_walk failed %d\n",
 884                                 err);
 885                        fid = NULL;
 886                        goto error;
 887                }
 888
 889                inode = v9fs_get_new_inode_from_fid(v9ses, fid, dir->i_sb);
 890                if (IS_ERR(inode)) {
 891                        err = PTR_ERR(inode);
 892                        p9_debug(P9_DEBUG_VFS, "inode creation failed %d\n",
 893                                 err);
 894                        goto error;
 895                }
 896                err = v9fs_fid_add(dentry, fid);
 897                if (err < 0)
 898                        goto error;
 899                d_instantiate(dentry, inode);
 900                fid = NULL;
 901        } else {
 902                /*
 903                 * Not in cached mode. No need to populate inode with stat.
 904                 * socket syscall returns a fd, so we need instantiate
 905                 */
 906                inode = v9fs_get_inode(dir->i_sb, mode, rdev);
 907                if (IS_ERR(inode)) {
 908                        err = PTR_ERR(inode);
 909                        goto error;
 910                }
 911                d_instantiate(dentry, inode);
 912        }
 913        /* Now set the ACL based on the default value */
 914        v9fs_set_create_acl(dentry, &dacl, &pacl);
 915error:
 916        if (fid)
 917                p9_client_clunk(fid);
 918        v9fs_set_create_acl(NULL, &dacl, &pacl);
 919        return err;
 920}
 921
 922/**
 923 * v9fs_vfs_follow_link_dotl - follow a symlink path
 924 * @dentry: dentry for symlink
 925 * @nd: nameidata
 926 *
 927 */
 928
 929static void *
 930v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd)
 931{
 932        int retval;
 933        struct p9_fid *fid;
 934        char *link = __getname();
 935        char *target;
 936
 937        p9_debug(P9_DEBUG_VFS, "%s\n", dentry->d_name.name);
 938
 939        if (!link) {
 940                link = ERR_PTR(-ENOMEM);
 941                goto ndset;
 942        }
 943        fid = v9fs_fid_lookup(dentry);
 944        if (IS_ERR(fid)) {
 945                __putname(link);
 946                link = ERR_CAST(fid);
 947                goto ndset;
 948        }
 949        retval = p9_client_readlink(fid, &target);
 950        if (!retval) {
 951                strcpy(link, target);
 952                kfree(target);
 953                goto ndset;
 954        }
 955        __putname(link);
 956        link = ERR_PTR(retval);
 957ndset:
 958        nd_set_link(nd, link);
 959        return NULL;
 960}
 961
 962int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
 963{
 964        loff_t i_size;
 965        struct p9_stat_dotl *st;
 966        struct v9fs_session_info *v9ses;
 967
 968        v9ses = v9fs_inode2v9ses(inode);
 969        st = p9_client_getattr_dotl(fid, P9_STATS_ALL);
 970        if (IS_ERR(st))
 971                return PTR_ERR(st);
 972        /*
 973         * Don't update inode if the file type is different
 974         */
 975        if ((inode->i_mode & S_IFMT) != (st->st_mode & S_IFMT))
 976                goto out;
 977
 978        spin_lock(&inode->i_lock);
 979        /*
 980         * We don't want to refresh inode->i_size,
 981         * because we may have cached data
 982         */
 983        i_size = inode->i_size;
 984        v9fs_stat2inode_dotl(st, inode);
 985        if (v9ses->cache)
 986                inode->i_size = i_size;
 987        spin_unlock(&inode->i_lock);
 988out:
 989        kfree(st);
 990        return 0;
 991}
 992
 993const struct inode_operations v9fs_dir_inode_operations_dotl = {
 994        .create = v9fs_vfs_create_dotl,
 995        .atomic_open = v9fs_vfs_atomic_open_dotl,
 996        .lookup = v9fs_vfs_lookup,
 997        .link = v9fs_vfs_link_dotl,
 998        .symlink = v9fs_vfs_symlink_dotl,
 999        .unlink = v9fs_vfs_unlink,
1000        .mkdir = v9fs_vfs_mkdir_dotl,
1001        .rmdir = v9fs_vfs_rmdir,
1002        .mknod = v9fs_vfs_mknod_dotl,
1003        .rename = v9fs_vfs_rename,
1004        .getattr = v9fs_vfs_getattr_dotl,
1005        .setattr = v9fs_vfs_setattr_dotl,
1006        .setxattr = generic_setxattr,
1007        .getxattr = generic_getxattr,
1008        .removexattr = generic_removexattr,
1009        .listxattr = v9fs_listxattr,
1010        .get_acl = v9fs_iop_get_acl,
1011};
1012
1013const struct inode_operations v9fs_file_inode_operations_dotl = {
1014        .getattr = v9fs_vfs_getattr_dotl,
1015        .setattr = v9fs_vfs_setattr_dotl,
1016        .setxattr = generic_setxattr,
1017        .getxattr = generic_getxattr,
1018        .removexattr = generic_removexattr,
1019        .listxattr = v9fs_listxattr,
1020        .get_acl = v9fs_iop_get_acl,
1021};
1022
1023const struct inode_operations v9fs_symlink_inode_operations_dotl = {
1024        .readlink = generic_readlink,
1025        .follow_link = v9fs_vfs_follow_link_dotl,
1026        .put_link = v9fs_vfs_put_link,
1027        .getattr = v9fs_vfs_getattr_dotl,
1028        .setattr = v9fs_vfs_setattr_dotl,
1029        .setxattr = generic_setxattr,
1030        .getxattr = generic_getxattr,
1031        .removexattr = generic_removexattr,
1032        .listxattr = v9fs_listxattr,
1033};
1034
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.