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