Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (C) Sistina Software, Inc.  1997-2003 All rights reserved.
0004  * Copyright (C) 2004-2006 Red Hat, Inc.  All rights reserved.
0005  */
0006 
0007 #include <linux/spinlock.h>
0008 #include <linux/completion.h>
0009 #include <linux/buffer_head.h>
0010 #include <linux/exportfs.h>
0011 #include <linux/gfs2_ondisk.h>
0012 #include <linux/crc32.h>
0013 
0014 #include "gfs2.h"
0015 #include "incore.h"
0016 #include "dir.h"
0017 #include "glock.h"
0018 #include "glops.h"
0019 #include "inode.h"
0020 #include "super.h"
0021 #include "rgrp.h"
0022 #include "util.h"
0023 
0024 #define GFS2_SMALL_FH_SIZE 4
0025 #define GFS2_LARGE_FH_SIZE 8
0026 #define GFS2_OLD_FH_SIZE 10
0027 
0028 static int gfs2_encode_fh(struct inode *inode, __u32 *p, int *len,
0029               struct inode *parent)
0030 {
0031     __be32 *fh = (__force __be32 *)p;
0032     struct super_block *sb = inode->i_sb;
0033     struct gfs2_inode *ip = GFS2_I(inode);
0034 
0035     if (parent && (*len < GFS2_LARGE_FH_SIZE)) {
0036         *len = GFS2_LARGE_FH_SIZE;
0037         return FILEID_INVALID;
0038     } else if (*len < GFS2_SMALL_FH_SIZE) {
0039         *len = GFS2_SMALL_FH_SIZE;
0040         return FILEID_INVALID;
0041     }
0042 
0043     fh[0] = cpu_to_be32(ip->i_no_formal_ino >> 32);
0044     fh[1] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);
0045     fh[2] = cpu_to_be32(ip->i_no_addr >> 32);
0046     fh[3] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF);
0047     *len = GFS2_SMALL_FH_SIZE;
0048 
0049     if (!parent || inode == d_inode(sb->s_root))
0050         return *len;
0051 
0052     ip = GFS2_I(parent);
0053 
0054     fh[4] = cpu_to_be32(ip->i_no_formal_ino >> 32);
0055     fh[5] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF);
0056     fh[6] = cpu_to_be32(ip->i_no_addr >> 32);
0057     fh[7] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF);
0058     *len = GFS2_LARGE_FH_SIZE;
0059 
0060     return *len;
0061 }
0062 
0063 struct get_name_filldir {
0064     struct dir_context ctx;
0065     struct gfs2_inum_host inum;
0066     char *name;
0067 };
0068 
0069 static int get_name_filldir(struct dir_context *ctx, const char *name,
0070                 int length, loff_t offset, u64 inum,
0071                 unsigned int type)
0072 {
0073     struct get_name_filldir *gnfd =
0074         container_of(ctx, struct get_name_filldir, ctx);
0075 
0076     if (inum != gnfd->inum.no_addr)
0077         return 0;
0078 
0079     memcpy(gnfd->name, name, length);
0080     gnfd->name[length] = 0;
0081 
0082     return 1;
0083 }
0084 
0085 static int gfs2_get_name(struct dentry *parent, char *name,
0086              struct dentry *child)
0087 {
0088     struct inode *dir = d_inode(parent);
0089     struct inode *inode = d_inode(child);
0090     struct gfs2_inode *dip, *ip;
0091     struct get_name_filldir gnfd = {
0092         .ctx.actor = get_name_filldir,
0093         .name = name
0094     };
0095     struct gfs2_holder gh;
0096     int error;
0097     struct file_ra_state f_ra = { .start = 0 };
0098 
0099     if (!dir)
0100         return -EINVAL;
0101 
0102     if (!S_ISDIR(dir->i_mode) || !inode)
0103         return -EINVAL;
0104 
0105     dip = GFS2_I(dir);
0106     ip = GFS2_I(inode);
0107 
0108     *name = 0;
0109     gnfd.inum.no_addr = ip->i_no_addr;
0110     gnfd.inum.no_formal_ino = ip->i_no_formal_ino;
0111 
0112     error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh);
0113     if (error)
0114         return error;
0115 
0116     error = gfs2_dir_read(dir, &gnfd.ctx, &f_ra);
0117 
0118     gfs2_glock_dq_uninit(&gh);
0119 
0120     if (!error && !*name)
0121         error = -ENOENT;
0122 
0123     return error;
0124 }
0125 
0126 static struct dentry *gfs2_get_parent(struct dentry *child)
0127 {
0128     return d_obtain_alias(gfs2_lookupi(d_inode(child), &gfs2_qdotdot, 1));
0129 }
0130 
0131 static struct dentry *gfs2_get_dentry(struct super_block *sb,
0132                       struct gfs2_inum_host *inum)
0133 {
0134     struct gfs2_sbd *sdp = sb->s_fs_info;
0135     struct inode *inode;
0136 
0137     if (!inum->no_formal_ino)
0138         return ERR_PTR(-ESTALE);
0139     inode = gfs2_lookup_by_inum(sdp, inum->no_addr, inum->no_formal_ino,
0140                     GFS2_BLKST_DINODE);
0141     if (IS_ERR(inode))
0142         return ERR_CAST(inode);
0143     return d_obtain_alias(inode);
0144 }
0145 
0146 static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid,
0147         int fh_len, int fh_type)
0148 {
0149     struct gfs2_inum_host this;
0150     __be32 *fh = (__force __be32 *)fid->raw;
0151 
0152     switch (fh_type) {
0153     case GFS2_SMALL_FH_SIZE:
0154     case GFS2_LARGE_FH_SIZE:
0155     case GFS2_OLD_FH_SIZE:
0156         if (fh_len < GFS2_SMALL_FH_SIZE)
0157             return NULL;
0158         this.no_formal_ino = ((u64)be32_to_cpu(fh[0])) << 32;
0159         this.no_formal_ino |= be32_to_cpu(fh[1]);
0160         this.no_addr = ((u64)be32_to_cpu(fh[2])) << 32;
0161         this.no_addr |= be32_to_cpu(fh[3]);
0162         return gfs2_get_dentry(sb, &this);
0163     default:
0164         return NULL;
0165     }
0166 }
0167 
0168 static struct dentry *gfs2_fh_to_parent(struct super_block *sb, struct fid *fid,
0169         int fh_len, int fh_type)
0170 {
0171     struct gfs2_inum_host parent;
0172     __be32 *fh = (__force __be32 *)fid->raw;
0173 
0174     switch (fh_type) {
0175     case GFS2_LARGE_FH_SIZE:
0176     case GFS2_OLD_FH_SIZE:
0177         if (fh_len < GFS2_LARGE_FH_SIZE)
0178             return NULL;
0179         parent.no_formal_ino = ((u64)be32_to_cpu(fh[4])) << 32;
0180         parent.no_formal_ino |= be32_to_cpu(fh[5]);
0181         parent.no_addr = ((u64)be32_to_cpu(fh[6])) << 32;
0182         parent.no_addr |= be32_to_cpu(fh[7]);
0183         return gfs2_get_dentry(sb, &parent);
0184     default:
0185         return NULL;
0186     }
0187 }
0188 
0189 const struct export_operations gfs2_export_ops = {
0190     .encode_fh = gfs2_encode_fh,
0191     .fh_to_dentry = gfs2_fh_to_dentry,
0192     .fh_to_parent = gfs2_fh_to_parent,
0193     .get_name = gfs2_get_name,
0194     .get_parent = gfs2_get_parent,
0195 };
0196