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