linux/fs/nfsd/nfsfh.h
<<
>>
Prefs
   1/* SPDX-License-Identifier: GPL-2.0 */
   2/*
   3 * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
   4 *
   5 * This file describes the layout of the file handles as passed
   6 * over the wire.
   7 */
   8#ifndef _LINUX_NFSD_NFSFH_H
   9#define _LINUX_NFSD_NFSFH_H
  10
  11#include <linux/crc32.h>
  12#include <linux/sunrpc/svc.h>
  13#include <uapi/linux/nfsd/nfsfh.h>
  14#include <linux/iversion.h>
  15#include <linux/exportfs.h>
  16
  17static inline __u32 ino_t_to_u32(ino_t ino)
  18{
  19        return (__u32) ino;
  20}
  21
  22static inline ino_t u32_to_ino_t(__u32 uino)
  23{
  24        return (ino_t) uino;
  25}
  26
  27/*
  28 * This is the internal representation of an NFS handle used in knfsd.
  29 * pre_mtime/post_version will be used to support wcc_attr's in NFSv3.
  30 */
  31typedef struct svc_fh {
  32        struct knfsd_fh         fh_handle;      /* FH data */
  33        int                     fh_maxsize;     /* max size for fh_handle */
  34        struct dentry *         fh_dentry;      /* validated dentry */
  35        struct svc_export *     fh_export;      /* export pointer */
  36
  37        bool                    fh_locked;      /* inode locked by us */
  38        bool                    fh_want_write;  /* remount protection taken */
  39        bool                    fh_no_wcc;      /* no wcc data needed */
  40        bool                    fh_no_atomic_attr;
  41                                                /*
  42                                                 * wcc data is not atomic with
  43                                                 * operation
  44                                                 */
  45        int                     fh_flags;       /* FH flags */
  46#ifdef CONFIG_NFSD_V3
  47        bool                    fh_post_saved;  /* post-op attrs saved */
  48        bool                    fh_pre_saved;   /* pre-op attrs saved */
  49
  50        /* Pre-op attributes saved during fh_lock */
  51        __u64                   fh_pre_size;    /* size before operation */
  52        struct timespec64       fh_pre_mtime;   /* mtime before oper */
  53        struct timespec64       fh_pre_ctime;   /* ctime before oper */
  54        /*
  55         * pre-op nfsv4 change attr: note must check IS_I_VERSION(inode)
  56         *  to find out if it is valid.
  57         */
  58        u64                     fh_pre_change;
  59
  60        /* Post-op attributes saved in fh_unlock */
  61        struct kstat            fh_post_attr;   /* full attrs after operation */
  62        u64                     fh_post_change; /* nfsv4 change; see above */
  63#endif /* CONFIG_NFSD_V3 */
  64} svc_fh;
  65#define NFSD4_FH_FOREIGN (1<<0)
  66#define SET_FH_FLAG(c, f) ((c)->fh_flags |= (f))
  67#define HAS_FH_FLAG(c, f) ((c)->fh_flags & (f))
  68
  69enum nfsd_fsid {
  70        FSID_DEV = 0,
  71        FSID_NUM,
  72        FSID_MAJOR_MINOR,
  73        FSID_ENCODE_DEV,
  74        FSID_UUID4_INUM,
  75        FSID_UUID8,
  76        FSID_UUID16,
  77        FSID_UUID16_INUM,
  78};
  79
  80enum fsid_source {
  81        FSIDSOURCE_DEV,
  82        FSIDSOURCE_FSID,
  83        FSIDSOURCE_UUID,
  84};
  85extern enum fsid_source fsid_source(const struct svc_fh *fhp);
  86
  87
  88/*
  89 * This might look a little large to "inline" but in all calls except
  90 * one, 'vers' is constant so moste of the function disappears.
  91 *
  92 * In some cases the values are considered to be host endian and in
  93 * others, net endian. fsidv is always considered to be u32 as the
  94 * callers don't know which it will be. So we must use __force to keep
  95 * sparse from complaining. Since these values are opaque to the
  96 * client, that shouldn't be a problem.
  97 */
  98static inline void mk_fsid(int vers, u32 *fsidv, dev_t dev, ino_t ino,
  99                           u32 fsid, unsigned char *uuid)
 100{
 101        u32 *up;
 102        switch(vers) {
 103        case FSID_DEV:
 104                fsidv[0] = (__force __u32)htonl((MAJOR(dev)<<16) |
 105                                 MINOR(dev));
 106                fsidv[1] = ino_t_to_u32(ino);
 107                break;
 108        case FSID_NUM:
 109                fsidv[0] = fsid;
 110                break;
 111        case FSID_MAJOR_MINOR:
 112                fsidv[0] = (__force __u32)htonl(MAJOR(dev));
 113                fsidv[1] = (__force __u32)htonl(MINOR(dev));
 114                fsidv[2] = ino_t_to_u32(ino);
 115                break;
 116
 117        case FSID_ENCODE_DEV:
 118                fsidv[0] = new_encode_dev(dev);
 119                fsidv[1] = ino_t_to_u32(ino);
 120                break;
 121
 122        case FSID_UUID4_INUM:
 123                /* 4 byte fsid and inode number */
 124                up = (u32*)uuid;
 125                fsidv[0] = ino_t_to_u32(ino);
 126                fsidv[1] = up[0] ^ up[1] ^ up[2] ^ up[3];
 127                break;
 128
 129        case FSID_UUID8:
 130                /* 8 byte fsid  */
 131                up = (u32*)uuid;
 132                fsidv[0] = up[0] ^ up[2];
 133                fsidv[1] = up[1] ^ up[3];
 134                break;
 135
 136        case FSID_UUID16:
 137                /* 16 byte fsid - NFSv3+ only */
 138                memcpy(fsidv, uuid, 16);
 139                break;
 140
 141        case FSID_UUID16_INUM:
 142                /* 8 byte inode and 16 byte fsid */
 143                *(u64*)fsidv = (u64)ino;
 144                memcpy(fsidv+2, uuid, 16);
 145                break;
 146        default: BUG();
 147        }
 148}
 149
 150static inline int key_len(int type)
 151{
 152        switch(type) {
 153        case FSID_DEV:          return 8;
 154        case FSID_NUM:          return 4;
 155        case FSID_MAJOR_MINOR:  return 12;
 156        case FSID_ENCODE_DEV:   return 8;
 157        case FSID_UUID4_INUM:   return 8;
 158        case FSID_UUID8:        return 8;
 159        case FSID_UUID16:       return 16;
 160        case FSID_UUID16_INUM:  return 24;
 161        default: return 0;
 162        }
 163}
 164
 165/*
 166 * Shorthand for dprintk()'s
 167 */
 168extern char * SVCFH_fmt(struct svc_fh *fhp);
 169
 170/*
 171 * Function prototypes
 172 */
 173__be32  fh_verify(struct svc_rqst *, struct svc_fh *, umode_t, int);
 174__be32  fh_compose(struct svc_fh *, struct svc_export *, struct dentry *, struct svc_fh *);
 175__be32  fh_update(struct svc_fh *);
 176void    fh_put(struct svc_fh *);
 177
 178static __inline__ struct svc_fh *
 179fh_copy(struct svc_fh *dst, struct svc_fh *src)
 180{
 181        WARN_ON(src->fh_dentry || src->fh_locked);
 182                        
 183        *dst = *src;
 184        return dst;
 185}
 186
 187static inline void
 188fh_copy_shallow(struct knfsd_fh *dst, struct knfsd_fh *src)
 189{
 190        dst->fh_size = src->fh_size;
 191        memcpy(&dst->fh_base, &src->fh_base, src->fh_size);
 192}
 193
 194static __inline__ struct svc_fh *
 195fh_init(struct svc_fh *fhp, int maxsize)
 196{
 197        memset(fhp, 0, sizeof(*fhp));
 198        fhp->fh_maxsize = maxsize;
 199        return fhp;
 200}
 201
 202static inline bool fh_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
 203{
 204        if (fh1->fh_size != fh2->fh_size)
 205                return false;
 206        if (memcmp(fh1->fh_base.fh_pad, fh2->fh_base.fh_pad, fh1->fh_size) != 0)
 207                return false;
 208        return true;
 209}
 210
 211static inline bool fh_fsid_match(struct knfsd_fh *fh1, struct knfsd_fh *fh2)
 212{
 213        if (fh1->fh_fsid_type != fh2->fh_fsid_type)
 214                return false;
 215        if (memcmp(fh1->fh_fsid, fh2->fh_fsid, key_len(fh1->fh_fsid_type)) != 0)
 216                return false;
 217        return true;
 218}
 219
 220#ifdef CONFIG_CRC32
 221/**
 222 * knfsd_fh_hash - calculate the crc32 hash for the filehandle
 223 * @fh - pointer to filehandle
 224 *
 225 * returns a crc32 hash for the filehandle that is compatible with
 226 * the one displayed by "wireshark".
 227 */
 228static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh)
 229{
 230        return ~crc32_le(0xFFFFFFFF, (unsigned char *)&fh->fh_base, fh->fh_size);
 231}
 232#else
 233static inline u32 knfsd_fh_hash(const struct knfsd_fh *fh)
 234{
 235        return 0;
 236}
 237#endif
 238
 239#ifdef CONFIG_NFSD_V3
 240/*
 241 * The wcc data stored in current_fh should be cleared
 242 * between compound ops.
 243 */
 244static inline void
 245fh_clear_wcc(struct svc_fh *fhp)
 246{
 247        fhp->fh_post_saved = false;
 248        fhp->fh_pre_saved = false;
 249}
 250
 251/*
 252 * We could use i_version alone as the change attribute.  However,
 253 * i_version can go backwards after a reboot.  On its own that doesn't
 254 * necessarily cause a problem, but if i_version goes backwards and then
 255 * is incremented again it could reuse a value that was previously used
 256 * before boot, and a client who queried the two values might
 257 * incorrectly assume nothing changed.
 258 *
 259 * By using both ctime and the i_version counter we guarantee that as
 260 * long as time doesn't go backwards we never reuse an old value.
 261 */
 262static inline u64 nfsd4_change_attribute(struct kstat *stat,
 263                                         struct inode *inode)
 264{
 265        if (inode->i_sb->s_export_op->fetch_iversion)
 266                return inode->i_sb->s_export_op->fetch_iversion(inode);
 267        else if (IS_I_VERSION(inode)) {
 268                u64 chattr;
 269
 270                chattr =  stat->ctime.tv_sec;
 271                chattr <<= 30;
 272                chattr += stat->ctime.tv_nsec;
 273                chattr += inode_query_iversion(inode);
 274                return chattr;
 275        } else
 276                return time_to_chattr(&stat->ctime);
 277}
 278
 279extern void fill_pre_wcc(struct svc_fh *fhp);
 280extern void fill_post_wcc(struct svc_fh *fhp);
 281#else
 282#define fh_clear_wcc(ignored)
 283#define fill_pre_wcc(ignored)
 284#define fill_post_wcc(notused)
 285#endif /* CONFIG_NFSD_V3 */
 286
 287
 288/*
 289 * Lock a file handle/inode
 290 * NOTE: both fh_lock and fh_unlock are done "by hand" in
 291 * vfs.c:nfsd_rename as it needs to grab 2 i_mutex's at once
 292 * so, any changes here should be reflected there.
 293 */
 294
 295static inline void
 296fh_lock_nested(struct svc_fh *fhp, unsigned int subclass)
 297{
 298        struct dentry   *dentry = fhp->fh_dentry;
 299        struct inode    *inode;
 300
 301        BUG_ON(!dentry);
 302
 303        if (fhp->fh_locked) {
 304                printk(KERN_WARNING "fh_lock: %pd2 already locked!\n",
 305                        dentry);
 306                return;
 307        }
 308
 309        inode = d_inode(dentry);
 310        inode_lock_nested(inode, subclass);
 311        fill_pre_wcc(fhp);
 312        fhp->fh_locked = true;
 313}
 314
 315static inline void
 316fh_lock(struct svc_fh *fhp)
 317{
 318        fh_lock_nested(fhp, I_MUTEX_NORMAL);
 319}
 320
 321/*
 322 * Unlock a file handle/inode
 323 */
 324static inline void
 325fh_unlock(struct svc_fh *fhp)
 326{
 327        if (fhp->fh_locked) {
 328                fill_post_wcc(fhp);
 329                inode_unlock(d_inode(fhp->fh_dentry));
 330                fhp->fh_locked = false;
 331        }
 332}
 333
 334#endif /* _LINUX_NFSD_NFSFH_H */
 335