]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - fs/orangefs/dir.c
orangefs: rewrite readdir to fix several bugs
[mirror_ubuntu-artful-kernel.git] / fs / orangefs / dir.c
CommitLineData
5db11c21 1/*
382f4581 2 * Copyright 2017 Omnibond Systems, L.L.C.
5db11c21
MM
3 */
4
5#include "protocol.h"
575e9461
MM
6#include "orangefs-kernel.h"
7#include "orangefs-bufmap.h"
5db11c21 8
5db11c21 9/*
382f4581
MB
10 * There can be up to 512 directory entries. Each entry is encoded as
11 * follows:
12 * 4 bytes: string size (n)
13 * n bytes: string
14 * 1 byte: trailing zero
15 * padding to 8 bytes
16 * 16 bytes: khandle
17 * padding to 8 bytes
5db11c21 18 */
382f4581 19#define MAX_DIRECTORY ((4 + 257 + 3 + 16)*512)
1808f8cc 20
382f4581
MB
21struct orangefs_dir {
22 __u64 token;
23 void *directory;
24 size_t i, len;
25 int error;
26};
5db11c21 27
5db11c21 28/*
382f4581
MB
29 * The userspace component sends several directory entries of the
30 * following format. The first four bytes are the string length not
31 * including a trailing zero byte. This is followed by the string and a
32 * trailing zero padded to the next four byte boundry. This is followed
33 * by the sixteen byte khandle padded to the next eight byte boundry.
34 *
35 * The trailer_buf starts with a struct orangefs_readdir_response_s
36 * which must be skipped to get to the directory data.
5db11c21 37 */
5db11c21 38
382f4581
MB
39static int orangefs_dir_more(struct orangefs_inode_s *oi,
40 struct orangefs_dir *od, struct dentry *dentry)
41{
42 const size_t offset =
43 sizeof(struct orangefs_readdir_response_s);
44 struct orangefs_readdir_response_s *resp;
45 struct orangefs_kernel_op_s *op;
46 int bufi, r;
47
48 op = op_alloc(ORANGEFS_VFS_OP_READDIR);
49 if (!op) {
50 od->error = -ENOMEM;
5db11c21 51 return -ENOMEM;
382f4581 52 }
5db11c21 53
ee3b8d37 54 /*
382f4581
MB
55 * Despite the badly named field, readdir does not use shared
56 * memory. However, there are a limited number of readdir
57 * slots, which must be allocated here. This flag simply tells
58 * the op scheduler to return the op here for retry.
ee3b8d37 59 */
382f4581
MB
60 op->uses_shared_memory = 1;
61 op->upcall.req.readdir.refn = oi->refn;
62 op->upcall.req.readdir.token = od->token;
63 op->upcall.req.readdir.max_dirent_count =
7d221485 64 ORANGEFS_MAX_DIRENT_COUNT_READDIR;
5db11c21 65
382f4581
MB
66again:
67 bufi = orangefs_readdir_index_get();
68 if (bufi < 0) {
69 op_release(op);
70 od->error = bufi;
71 return bufi;
5db11c21 72 }
5db11c21 73
382f4581 74 op->upcall.req.readdir.buf_index = bufi;
5db11c21 75
382f4581
MB
76 r = service_operation(op, "orangefs_readdir",
77 get_interruptible_flag(dentry->d_inode));
5db11c21 78
382f4581 79 orangefs_readdir_index_put(bufi);
ee3b8d37 80
382f4581
MB
81 if (op_state_purged(op)) {
82 if (r == -EAGAIN) {
83 vfree(op->downcall.trailer_buf);
84 goto again;
85 } else if (r == -EIO) {
86 vfree(op->downcall.trailer_buf);
87 op_release(op);
88 od->error = r;
89 return r;
90 }
5db11c21
MM
91 }
92
382f4581
MB
93 if (r < 0) {
94 vfree(op->downcall.trailer_buf);
95 op_release(op);
96 od->error = r;
97 return r;
98 } else if (op->downcall.status) {
99 vfree(op->downcall.trailer_buf);
100 op_release(op);
101 od->error = op->downcall.status;
102 return op->downcall.status;
103 }
104
105 resp = (struct orangefs_readdir_response_s *)
106 op->downcall.trailer_buf;
107 od->token = resp->token;
108
109 if (od->len + op->downcall.trailer_size - offset <=
110 MAX_DIRECTORY) {
111 memcpy(od->directory + od->len,
112 op->downcall.trailer_buf + offset,
113 op->downcall.trailer_size - offset);
114 od->len += op->downcall.trailer_size - offset;
115 } else {
116 /* This limit was chosen based on protocol limits. */
117 gossip_err("orangefs_dir_more: userspace sent too much data\n");
118 vfree(op->downcall.trailer_buf);
119 op_release(op);
120 od->error = -EIO;
121 return -EIO;
122 }
123
124 vfree(op->downcall.trailer_buf);
125 op_release(op);
126 return 0;
127}
9f5e2f7f 128
382f4581
MB
129static int orangefs_dir_fill(struct orangefs_inode_s *oi,
130 struct orangefs_dir *od, struct dentry *dentry,
131 struct dir_context *ctx)
132{
133 struct orangefs_khandle *khandle;
134 __u32 *len, padlen;
135 char *s;
136 while (od->i < od->len) {
137 if (od->len < od->i + sizeof *len)
138 goto eio;
139 len = od->directory + od->i;
140 /*
141 * len is the size of the string itself. padlen is the
142 * total size of the encoded string.
143 */
144 padlen = (sizeof *len + *len + 1) +
145 (4 - (sizeof *len + *len + 1)%8)%8;
146 if (od->len < od->i + padlen + sizeof *khandle)
147 goto eio;
148 s = od->directory + od->i + sizeof *len;
149 if (s[*len] != 0)
150 goto eio;
151 khandle = od->directory + od->i + padlen;
152
153 if (!dir_emit(ctx, s, *len,
154 orangefs_khandle_to_ino(khandle), DT_UNKNOWN))
155 return 0;
156 od->i += padlen + sizeof *khandle;
157 od->i = od->i + (8 - od->i%8)%8;
158 ctx->pos = 2 + od->i;
159 }
160 BUG_ON(od->i > od->len);
161 return 0;
162eio:
163 gossip_err("orangefs_dir_fill: userspace returns corrupt data\n");
164 od->error = -EIO;
165 return -EIO;
166}
5db11c21 167
382f4581
MB
168static int orangefs_dir_iterate(struct file *file,
169 struct dir_context *ctx)
170{
171 struct orangefs_inode_s *oi;
172 struct orangefs_dir *od;
173 struct dentry *dentry;
174 int r;
5db11c21 175
382f4581
MB
176 dentry = file->f_path.dentry;
177 oi = ORANGEFS_I(dentry->d_inode);
178 od = file->private_data;
5db11c21 179
382f4581
MB
180 if (od->error)
181 return od->error;
5db11c21 182
382f4581
MB
183 if (ctx->pos == 0) {
184 if (!dir_emit_dot(file, ctx))
185 return 0;
186 ctx->pos++;
5db11c21 187 }
382f4581
MB
188 if (ctx->pos == 1) {
189 if (!dir_emit_dotdot(file, ctx))
190 return 0;
5db11c21 191 ctx->pos++;
5db11c21
MM
192 }
193
382f4581
MB
194 r = 0;
195
196 if (od->i < od->len) {
197 r = orangefs_dir_fill(oi, od, dentry, ctx);
198 if (r)
199 return r;
5db11c21
MM
200 }
201
382f4581
MB
202 if (od->token != ORANGEFS_READDIR_END) {
203 r = orangefs_dir_more(oi, od, dentry);
204 if (r)
205 return r;
206 r = orangefs_dir_fill(oi, od, dentry, ctx);
5db11c21
MM
207 }
208
382f4581 209 return r;
5db11c21
MM
210}
211
8bb8aefd 212static int orangefs_dir_open(struct inode *inode, struct file *file)
5db11c21 213{
382f4581
MB
214 struct orangefs_dir *od;
215 file->private_data = kmalloc(sizeof(struct orangefs_dir),
216 GFP_KERNEL);
5db11c21
MM
217 if (!file->private_data)
218 return -ENOMEM;
382f4581
MB
219 od = file->private_data;
220 od->token = ORANGEFS_READDIR_START;
221 /*
222 * XXX: It seems wasteful to allocate such a large buffer for
223 * each request. Most will be much smaller.
224 */
225 od->directory = alloc_pages_exact(MAX_DIRECTORY, GFP_KERNEL);
226 if (!od->directory) {
227 kfree(file->private_data);
228 return -ENOMEM;
229 }
230 od->i = 0;
231 od->len = 0;
232 od->error = 0;
5db11c21
MM
233 return 0;
234}
235
8bb8aefd 236static int orangefs_dir_release(struct inode *inode, struct file *file)
5db11c21 237{
382f4581 238 struct orangefs_dir *od = file->private_data;
8bb8aefd 239 orangefs_flush_inode(inode);
382f4581
MB
240 free_pages_exact(od->directory, MAX_DIRECTORY);
241 kfree(od);
5db11c21
MM
242 return 0;
243}
244
8bb8aefd 245const struct file_operations orangefs_dir_operations = {
5db11c21 246 .read = generic_read_dir,
382f4581 247 .iterate = orangefs_dir_iterate,
8bb8aefd 248 .open = orangefs_dir_open,
382f4581 249 .release = orangefs_dir_release
5db11c21 250};