Blame view
fs/gfs2/export.c
4.64 KB
7336d0e65
|
1 |
// SPDX-License-Identifier: GPL-2.0-only |
b3b94faa5
|
2 3 |
/* * Copyright (C) Sistina Software, Inc. 1997-2003 All rights reserved. |
3a8a9a103
|
4 |
* Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved. |
b3b94faa5
|
5 |
*/ |
b3b94faa5
|
6 7 8 |
#include <linux/spinlock.h> #include <linux/completion.h> #include <linux/buffer_head.h> |
a56942551
|
9 |
#include <linux/exportfs.h> |
5c676f6d3
|
10 |
#include <linux/gfs2_ondisk.h> |
71b86f562
|
11 |
#include <linux/crc32.h> |
b3b94faa5
|
12 13 |
#include "gfs2.h" |
5c676f6d3
|
14 |
#include "incore.h" |
b3b94faa5
|
15 16 17 18 |
#include "dir.h" #include "glock.h" #include "glops.h" #include "inode.h" |
b27605837
|
19 |
#include "super.h" |
b3b94faa5
|
20 |
#include "rgrp.h" |
c752666c1
|
21 |
#include "util.h" |
b3b94faa5
|
22 |
|
bb8d8a6f5
|
23 |
#define GFS2_SMALL_FH_SIZE 4 |
35dcc52e3
|
24 |
#define GFS2_LARGE_FH_SIZE 8 |
3ebf44902
|
25 |
#define GFS2_OLD_FH_SIZE 10 |
bb8d8a6f5
|
26 |
|
b0b0382bb
|
27 28 |
static int gfs2_encode_fh(struct inode *inode, __u32 *p, int *len, struct inode *parent) |
b3b94faa5
|
29 |
{ |
b44b84d76
|
30 |
__be32 *fh = (__force __be32 *)p; |
c9fd43078
|
31 |
struct super_block *sb = inode->i_sb; |
feaa7bba0
|
32 |
struct gfs2_inode *ip = GFS2_I(inode); |
b3b94faa5
|
33 |
|
b0b0382bb
|
34 |
if (parent && (*len < GFS2_LARGE_FH_SIZE)) { |
5fe0c2378
|
35 |
*len = GFS2_LARGE_FH_SIZE; |
94e07a759
|
36 |
return FILEID_INVALID; |
5fe0c2378
|
37 38 |
} else if (*len < GFS2_SMALL_FH_SIZE) { *len = GFS2_SMALL_FH_SIZE; |
94e07a759
|
39 |
return FILEID_INVALID; |
5fe0c2378
|
40 |
} |
b3b94faa5
|
41 |
|
dbb7cae2a
|
42 43 44 45 |
fh[0] = cpu_to_be32(ip->i_no_formal_ino >> 32); fh[1] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF); fh[2] = cpu_to_be32(ip->i_no_addr >> 32); fh[3] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF); |
5acd39673
|
46 |
*len = GFS2_SMALL_FH_SIZE; |
b3b94faa5
|
47 |
|
2b0143b5c
|
48 |
if (!parent || inode == d_inode(sb->s_root)) |
b3b94faa5
|
49 |
return *len; |
b0b0382bb
|
50 |
ip = GFS2_I(parent); |
b3b94faa5
|
51 |
|
dbb7cae2a
|
52 53 54 55 |
fh[4] = cpu_to_be32(ip->i_no_formal_ino >> 32); fh[5] = cpu_to_be32(ip->i_no_formal_ino & 0xFFFFFFFF); fh[6] = cpu_to_be32(ip->i_no_addr >> 32); fh[7] = cpu_to_be32(ip->i_no_addr & 0xFFFFFFFF); |
5acd39673
|
56 |
*len = GFS2_LARGE_FH_SIZE; |
b3b94faa5
|
57 |
|
b3b94faa5
|
58 59 60 61 |
return *len; } struct get_name_filldir { |
d81a8ef59
|
62 |
struct dir_context ctx; |
629a21e7e
|
63 |
struct gfs2_inum_host inum; |
b3b94faa5
|
64 65 |
char *name; }; |
ac7576f4b
|
66 67 68 |
static int get_name_filldir(struct dir_context *ctx, const char *name, int length, loff_t offset, u64 inum, unsigned int type) |
b3b94faa5
|
69 |
{ |
ac7576f4b
|
70 71 |
struct get_name_filldir *gnfd = container_of(ctx, struct get_name_filldir, ctx); |
b3b94faa5
|
72 |
|
3699e3a44
|
73 |
if (inum != gnfd->inum.no_addr) |
b3b94faa5
|
74 75 76 77 78 79 80 81 82 83 84 |
return 0; memcpy(gnfd->name, name, length); gnfd->name[length] = 0; return 1; } static int gfs2_get_name(struct dentry *parent, char *name, struct dentry *child) { |
2b0143b5c
|
85 86 |
struct inode *dir = d_inode(parent); struct inode *inode = d_inode(child); |
b3b94faa5
|
87 |
struct gfs2_inode *dip, *ip; |
ac6614b76
|
88 89 90 91 |
struct get_name_filldir gnfd = { .ctx.actor = get_name_filldir, .name = name }; |
b3b94faa5
|
92 |
struct gfs2_holder gh; |
b3b94faa5
|
93 |
int error; |
dfe4d34b3
|
94 |
struct file_ra_state f_ra = { .start = 0 }; |
b3b94faa5
|
95 96 97 |
if (!dir) return -EINVAL; |
b3b94faa5
|
98 99 |
if (!S_ISDIR(dir->i_mode) || !inode) return -EINVAL; |
feaa7bba0
|
100 101 |
dip = GFS2_I(dir); ip = GFS2_I(inode); |
b3b94faa5
|
102 103 |
*name = 0; |
dbb7cae2a
|
104 105 |
gnfd.inum.no_addr = ip->i_no_addr; gnfd.inum.no_formal_ino = ip->i_no_formal_ino; |
b3b94faa5
|
106 107 108 109 |
error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0, &gh); if (error) return error; |
d81a8ef59
|
110 |
error = gfs2_dir_read(dir, &gnfd.ctx, &f_ra); |
b3b94faa5
|
111 112 113 114 115 116 117 118 119 120 121 |
gfs2_glock_dq_uninit(&gh); if (!error && !*name) error = -ENOENT; return error; } static struct dentry *gfs2_get_parent(struct dentry *child) { |
2b0143b5c
|
122 |
return d_obtain_alias(gfs2_lookupi(d_inode(child), &gfs2_qdotdot, 1)); |
b3b94faa5
|
123 |
} |
34c0d1542
|
124 |
static struct dentry *gfs2_get_dentry(struct super_block *sb, |
acf7e2444
|
125 |
struct gfs2_inum_host *inum) |
b3b94faa5
|
126 |
{ |
5c676f6d3
|
127 |
struct gfs2_sbd *sdp = sb->s_fs_info; |
b3b94faa5
|
128 |
struct inode *inode; |
b3b94faa5
|
129 |
|
6bdcadea7
|
130 131 132 |
if (!inum->no_formal_ino) return ERR_PTR(-ESTALE); inode = gfs2_lookup_by_inum(sdp, inum->no_addr, inum->no_formal_ino, |
044b9414c
|
133 134 135 |
GFS2_BLKST_DINODE); if (IS_ERR(inode)) return ERR_CAST(inode); |
41ced6dcf
|
136 |
return d_obtain_alias(inode); |
b3b94faa5
|
137 |
} |
34c0d1542
|
138 139 140 141 142 143 144 145 146 147 |
static struct dentry *gfs2_fh_to_dentry(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) { struct gfs2_inum_host this; __be32 *fh = (__force __be32 *)fid->raw; switch (fh_type) { case GFS2_SMALL_FH_SIZE: case GFS2_LARGE_FH_SIZE: case GFS2_OLD_FH_SIZE: |
35c2a7f49
|
148 149 |
if (fh_len < GFS2_SMALL_FH_SIZE) return NULL; |
34c0d1542
|
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
this.no_formal_ino = ((u64)be32_to_cpu(fh[0])) << 32; this.no_formal_ino |= be32_to_cpu(fh[1]); this.no_addr = ((u64)be32_to_cpu(fh[2])) << 32; this.no_addr |= be32_to_cpu(fh[3]); return gfs2_get_dentry(sb, &this); default: return NULL; } } static struct dentry *gfs2_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type) { struct gfs2_inum_host parent; __be32 *fh = (__force __be32 *)fid->raw; switch (fh_type) { case GFS2_LARGE_FH_SIZE: case GFS2_OLD_FH_SIZE: |
35c2a7f49
|
169 170 |
if (fh_len < GFS2_LARGE_FH_SIZE) return NULL; |
34c0d1542
|
171 172 173 174 175 176 177 178 179 |
parent.no_formal_ino = ((u64)be32_to_cpu(fh[4])) << 32; parent.no_formal_ino |= be32_to_cpu(fh[5]); parent.no_addr = ((u64)be32_to_cpu(fh[6])) << 32; parent.no_addr |= be32_to_cpu(fh[7]); return gfs2_get_dentry(sb, &parent); default: return NULL; } } |
396551644
|
180 |
const struct export_operations gfs2_export_ops = { |
b3b94faa5
|
181 |
.encode_fh = gfs2_encode_fh, |
34c0d1542
|
182 183 |
.fh_to_dentry = gfs2_fh_to_dentry, .fh_to_parent = gfs2_fh_to_parent, |
b3b94faa5
|
184 185 |
.get_name = gfs2_get_name, .get_parent = gfs2_get_parent, |
b3b94faa5
|
186 |
}; |