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