linux/fs/ocfs2/export.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * export.c
   4 *
   5 * Functions to facilitate NFS exporting
   6 *
   7 * Copyright (C) 2002, 2005 Oracle.  All rights reserved.
   8 */
   9
  10#include <linux/fs.h>
  11#include <linux/types.h>
  12
  13#include <cluster/masklog.h>
  14
  15#include "ocfs2.h"
  16
  17#include "alloc.h"
  18#include "dir.h"
  19#include "dlmglue.h"
  20#include "dcache.h"
  21#include "export.h"
  22#include "inode.h"
  23
  24#include "buffer_head_io.h"
  25#include "suballoc.h"
  26#include "ocfs2_trace.h"
  27
  28struct ocfs2_inode_handle
  29{
  30        u64 ih_blkno;
  31        u32 ih_generation;
  32};
  33
  34static struct dentry *ocfs2_get_dentry(struct super_block *sb,
  35                struct ocfs2_inode_handle *handle)
  36{
  37        struct inode *inode;
  38        struct ocfs2_super *osb = OCFS2_SB(sb);
  39        u64 blkno = handle->ih_blkno;
  40        int status, set;
  41        struct dentry *result;
  42
  43        trace_ocfs2_get_dentry_begin(sb, handle, (unsigned long long)blkno);
  44
  45        if (blkno == 0) {
  46                result = ERR_PTR(-ESTALE);
  47                goto bail;
  48        }
  49
  50        inode = ocfs2_ilookup(sb, blkno);
  51        /*
  52         * If the inode exists in memory, we only need to check it's
  53         * generation number
  54         */
  55        if (inode)
  56                goto check_gen;
  57
  58        /*
  59         * This will synchronize us against ocfs2_delete_inode() on
  60         * all nodes
  61         */
  62        status = ocfs2_nfs_sync_lock(osb, 1);
  63        if (status < 0) {
  64                mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status);
  65                goto check_err;
  66        }
  67
  68        status = ocfs2_test_inode_bit(osb, blkno, &set);
  69        if (status < 0) {
  70                if (status == -EINVAL) {
  71                        /*
  72                         * The blkno NFS gave us doesn't even show up
  73                         * as an inode, we return -ESTALE to be
  74                         * nice
  75                         */
  76                        status = -ESTALE;
  77                } else
  78                        mlog(ML_ERROR, "test inode bit failed %d\n", status);
  79                goto unlock_nfs_sync;
  80        }
  81
  82        trace_ocfs2_get_dentry_test_bit(status, set);
  83        /* If the inode allocator bit is clear, this inode must be stale */
  84        if (!set) {
  85                status = -ESTALE;
  86                goto unlock_nfs_sync;
  87        }
  88
  89        inode = ocfs2_iget(osb, blkno, 0, 0);
  90
  91unlock_nfs_sync:
  92        ocfs2_nfs_sync_unlock(osb, 1);
  93
  94check_err:
  95        if (status < 0) {
  96                if (status == -ESTALE) {
  97                        trace_ocfs2_get_dentry_stale((unsigned long long)blkno,
  98                                                     handle->ih_generation);
  99                }
 100                result = ERR_PTR(status);
 101                goto bail;
 102        }
 103
 104        if (IS_ERR(inode)) {
 105                mlog_errno(PTR_ERR(inode));
 106                result = ERR_CAST(inode);
 107                goto bail;
 108        }
 109
 110check_gen:
 111        if (handle->ih_generation != inode->i_generation) {
 112                trace_ocfs2_get_dentry_generation((unsigned long long)blkno,
 113                                                  handle->ih_generation,
 114                                                  inode->i_generation);
 115                iput(inode);
 116                result = ERR_PTR(-ESTALE);
 117                goto bail;
 118        }
 119
 120        result = d_obtain_alias(inode);
 121        if (IS_ERR(result))
 122                mlog_errno(PTR_ERR(result));
 123
 124bail:
 125        trace_ocfs2_get_dentry_end(result);
 126        return result;
 127}
 128
 129static struct dentry *ocfs2_get_parent(struct dentry *child)
 130{
 131        int status;
 132        u64 blkno;
 133        struct dentry *parent;
 134        struct inode *dir = d_inode(child);
 135        int set;
 136
 137        trace_ocfs2_get_parent(child, child->d_name.len, child->d_name.name,
 138                               (unsigned long long)OCFS2_I(dir)->ip_blkno);
 139
 140        status = ocfs2_nfs_sync_lock(OCFS2_SB(dir->i_sb), 1);
 141        if (status < 0) {
 142                mlog(ML_ERROR, "getting nfs sync lock(EX) failed %d\n", status);
 143                parent = ERR_PTR(status);
 144                goto bail;
 145        }
 146
 147        status = ocfs2_inode_lock(dir, NULL, 0);
 148        if (status < 0) {
 149                if (status != -ENOENT)
 150                        mlog_errno(status);
 151                parent = ERR_PTR(status);
 152                goto unlock_nfs_sync;
 153        }
 154
 155        status = ocfs2_lookup_ino_from_name(dir, "..", 2, &blkno);
 156        if (status < 0) {
 157                parent = ERR_PTR(-ENOENT);
 158                goto bail_unlock;
 159        }
 160
 161        status = ocfs2_test_inode_bit(OCFS2_SB(dir->i_sb), blkno, &set);
 162        if (status < 0) {
 163                if (status == -EINVAL) {
 164                        status = -ESTALE;
 165                } else
 166                        mlog(ML_ERROR, "test inode bit failed %d\n", status);
 167                parent = ERR_PTR(status);
 168                goto bail_unlock;
 169        }
 170
 171        trace_ocfs2_get_dentry_test_bit(status, set);
 172        if (!set) {
 173                status = -ESTALE;
 174                parent = ERR_PTR(status);
 175                goto bail_unlock;
 176        }
 177
 178        parent = d_obtain_alias(ocfs2_iget(OCFS2_SB(dir->i_sb), blkno, 0, 0));
 179
 180bail_unlock:
 181        ocfs2_inode_unlock(dir, 0);
 182
 183unlock_nfs_sync:
 184        ocfs2_nfs_sync_unlock(OCFS2_SB(dir->i_sb), 1);
 185
 186bail:
 187        trace_ocfs2_get_parent_end(parent);
 188
 189        return parent;
 190}
 191
 192static int ocfs2_encode_fh(struct inode *inode, u32 *fh_in, int *max_len,
 193                           struct inode *parent)
 194{
 195        int len = *max_len;
 196        int type = 1;
 197        u64 blkno;
 198        u32 generation;
 199        __le32 *fh = (__force __le32 *) fh_in;
 200
 201#ifdef TRACE_HOOKS_ARE_NOT_BRAINDEAD_IN_YOUR_OPINION
 202#error "You go ahead and fix that mess, then.  Somehow"
 203        trace_ocfs2_encode_fh_begin(dentry, dentry->d_name.len,
 204                                    dentry->d_name.name,
 205                                    fh, len, connectable);
 206#endif
 207
 208        if (parent && (len < 6)) {
 209                *max_len = 6;
 210                type = FILEID_INVALID;
 211                goto bail;
 212        } else if (len < 3) {
 213                *max_len = 3;
 214                type = FILEID_INVALID;
 215                goto bail;
 216        }
 217
 218        blkno = OCFS2_I(inode)->ip_blkno;
 219        generation = inode->i_generation;
 220
 221        trace_ocfs2_encode_fh_self((unsigned long long)blkno, generation);
 222
 223        len = 3;
 224        fh[0] = cpu_to_le32((u32)(blkno >> 32));
 225        fh[1] = cpu_to_le32((u32)(blkno & 0xffffffff));
 226        fh[2] = cpu_to_le32(generation);
 227
 228        if (parent) {
 229                blkno = OCFS2_I(parent)->ip_blkno;
 230                generation = parent->i_generation;
 231
 232                fh[3] = cpu_to_le32((u32)(blkno >> 32));
 233                fh[4] = cpu_to_le32((u32)(blkno & 0xffffffff));
 234                fh[5] = cpu_to_le32(generation);
 235
 236                len = 6;
 237                type = 2;
 238
 239                trace_ocfs2_encode_fh_parent((unsigned long long)blkno,
 240                                             generation);
 241        }
 242
 243        *max_len = len;
 244
 245bail:
 246        trace_ocfs2_encode_fh_type(type);
 247        return type;
 248}
 249
 250static struct dentry *ocfs2_fh_to_dentry(struct super_block *sb,
 251                struct fid *fid, int fh_len, int fh_type)
 252{
 253        struct ocfs2_inode_handle handle;
 254
 255        if (fh_len < 3 || fh_type > 2)
 256                return NULL;
 257
 258        handle.ih_blkno = (u64)le32_to_cpu(fid->raw[0]) << 32;
 259        handle.ih_blkno |= (u64)le32_to_cpu(fid->raw[1]);
 260        handle.ih_generation = le32_to_cpu(fid->raw[2]);
 261        return ocfs2_get_dentry(sb, &handle);
 262}
 263
 264static struct dentry *ocfs2_fh_to_parent(struct super_block *sb,
 265                struct fid *fid, int fh_len, int fh_type)
 266{
 267        struct ocfs2_inode_handle parent;
 268
 269        if (fh_type != 2 || fh_len < 6)
 270                return NULL;
 271
 272        parent.ih_blkno = (u64)le32_to_cpu(fid->raw[3]) << 32;
 273        parent.ih_blkno |= (u64)le32_to_cpu(fid->raw[4]);
 274        parent.ih_generation = le32_to_cpu(fid->raw[5]);
 275        return ocfs2_get_dentry(sb, &parent);
 276}
 277
 278const struct export_operations ocfs2_export_ops = {
 279        .encode_fh      = ocfs2_encode_fh,
 280        .fh_to_dentry   = ocfs2_fh_to_dentry,
 281        .fh_to_parent   = ocfs2_fh_to_parent,
 282        .get_parent     = ocfs2_get_parent,
 283};
 284