blob: 9744fb3ad144f1ee74dc7b0a028fc17d25a14c36 [file] [log] [blame]
Mike Marshall5db11c22015-07-17 10:38:12 -04001/*
Martin Brandenburg382f4582017-04-25 15:37:59 -04002 * Copyright 2017 Omnibond Systems, L.L.C.
Mike Marshall5db11c22015-07-17 10:38:12 -04003 */
4
5#include "protocol.h"
Mike Marshall575e9462015-12-04 12:56:14 -05006#include "orangefs-kernel.h"
7#include "orangefs-bufmap.h"
Mike Marshall5db11c22015-07-17 10:38:12 -04008
Mike Marshall5db11c22015-07-17 10:38:12 -04009/*
Martin Brandenburg382f4582017-04-25 15:37:59 -040010 * 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
Mike Marshall5db11c22015-07-17 10:38:12 -040018 */
Martin Brandenburg382f4582017-04-25 15:37:59 -040019#define MAX_DIRECTORY ((4 + 257 + 3 + 16)*512)
Mike Marshall5db11c22015-07-17 10:38:12 -040020
Martin Brandenburg382f4582017-04-25 15:37:59 -040021struct orangefs_dir {
22 __u64 token;
23 void *directory;
Martin Brandenburg72f66b82017-04-25 15:38:00 -040024 size_t len;
Martin Brandenburg382f4582017-04-25 15:37:59 -040025 int error;
26};
Mike Marshall5db11c22015-07-17 10:38:12 -040027
Mike Marshall5db11c22015-07-17 10:38:12 -040028/*
Martin Brandenburg382f4582017-04-25 15:37:59 -040029 * 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.
Mike Marshall5db11c22015-07-17 10:38:12 -040037 */
Martin Brandenburg382f4582017-04-25 15:37:59 -040038
39static int orangefs_dir_more(struct orangefs_inode_s *oi,
40 struct orangefs_dir *od, struct dentry *dentry)
Mike Marshall5db11c22015-07-17 10:38:12 -040041{
Martin Brandenburg382f4582017-04-25 15:37:59 -040042 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;
Mike Marshall5db11c22015-07-17 10:38:12 -040047
Martin Brandenburg382f4582017-04-25 15:37:59 -040048 op = op_alloc(ORANGEFS_VFS_OP_READDIR);
49 if (!op) {
50 od->error = -ENOMEM;
51 return -ENOMEM;
Mike Marshall5db11c22015-07-17 10:38:12 -040052 }
53
Martin Brandenburgee3b8d32016-02-17 12:55:42 -050054 /*
Martin Brandenburg382f4582017-04-25 15:37:59 -040055 * 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.
Martin Brandenburgee3b8d32016-02-17 12:55:42 -050059 */
Martin Brandenburg382f4582017-04-25 15:37:59 -040060 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 =
Martin Brandenburg7d221482016-01-04 15:05:28 -050064 ORANGEFS_MAX_DIRENT_COUNT_READDIR;
Mike Marshall5db11c22015-07-17 10:38:12 -040065
Martin Brandenburg382f4582017-04-25 15:37:59 -040066again:
67 bufi = orangefs_readdir_index_get();
68 if (bufi < 0) {
69 op_release(op);
70 od->error = bufi;
71 return bufi;
Mike Marshall5db11c22015-07-17 10:38:12 -040072 }
73
Martin Brandenburg382f4582017-04-25 15:37:59 -040074 op->upcall.req.readdir.buf_index = bufi;
75
76 r = service_operation(op, "orangefs_readdir",
77 get_interruptible_flag(dentry->d_inode));
78
79 orangefs_readdir_index_put(bufi);
80
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 }
Mike Marshall5db11c22015-07-17 10:38:12 -040091 }
92
Martin Brandenburg382f4582017-04-25 15:37:59 -040093 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;
Mike Marshall5db11c22015-07-17 10:38:12 -0400103 }
104
Martin Brandenburg382f4582017-04-25 15:37:59 -0400105 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;
Al Viro9f5e2f72016-02-16 19:54:13 -0500122 }
123
Martin Brandenburg382f4582017-04-25 15:37:59 -0400124 vfree(op->downcall.trailer_buf);
125 op_release(op);
126 return 0;
127}
Mike Marshall5db11c22015-07-17 10:38:12 -0400128
Martin Brandenburg382f4582017-04-25 15:37:59 -0400129static 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;
Martin Brandenburg72f66b82017-04-25 15:38:00 -0400135 loff_t i;
Martin Brandenburg382f4582017-04-25 15:37:59 -0400136 char *s;
Martin Brandenburg72f66b82017-04-25 15:38:00 -0400137 i = ctx->pos - 2;
138 while (i < od->len) {
139 if (od->len < i + sizeof *len)
Martin Brandenburg382f4582017-04-25 15:37:59 -0400140 goto eio;
Martin Brandenburg72f66b82017-04-25 15:38:00 -0400141 len = od->directory + i;
Mike Marshall88309aa2015-09-23 16:48:40 -0400142 /*
Martin Brandenburg382f4582017-04-25 15:37:59 -0400143 * len is the size of the string itself. padlen is the
144 * total size of the encoded string.
Mike Marshall88309aa2015-09-23 16:48:40 -0400145 */
Martin Brandenburg382f4582017-04-25 15:37:59 -0400146 padlen = (sizeof *len + *len + 1) +
147 (4 - (sizeof *len + *len + 1)%8)%8;
Martin Brandenburg72f66b82017-04-25 15:38:00 -0400148 if (od->len < i + padlen + sizeof *khandle)
Martin Brandenburg382f4582017-04-25 15:37:59 -0400149 goto eio;
Martin Brandenburg72f66b82017-04-25 15:38:00 -0400150 s = od->directory + i + sizeof *len;
Martin Brandenburg382f4582017-04-25 15:37:59 -0400151 if (s[*len] != 0)
152 goto eio;
Martin Brandenburg72f66b82017-04-25 15:38:00 -0400153 khandle = od->directory + i + padlen;
Martin Brandenburg382f4582017-04-25 15:37:59 -0400154
155 if (!dir_emit(ctx, s, *len,
156 orangefs_khandle_to_ino(khandle), DT_UNKNOWN))
157 return 0;
Martin Brandenburg72f66b82017-04-25 15:38:00 -0400158 i += padlen + sizeof *khandle;
159 i = i + (8 - i%8)%8;
160 ctx->pos = i + 2;
Martin Brandenburg382f4582017-04-25 15:37:59 -0400161 }
Martin Brandenburg72f66b82017-04-25 15:38:00 -0400162 BUG_ON(i > od->len);
Martin Brandenburg382f4582017-04-25 15:37:59 -0400163 return 0;
164eio:
Martin Brandenburg72f66b82017-04-25 15:38:00 -0400165 /*
166 * Here either data from userspace is corrupt or the application
167 * has sought to an invalid location.
168 */
Martin Brandenburg382f4582017-04-25 15:37:59 -0400169 od->error = -EIO;
170 return -EIO;
171}
172
173static int orangefs_dir_iterate(struct file *file,
174 struct dir_context *ctx)
175{
176 struct orangefs_inode_s *oi;
177 struct orangefs_dir *od;
178 struct dentry *dentry;
179 int r;
180
181 dentry = file->f_path.dentry;
182 oi = ORANGEFS_I(dentry->d_inode);
183 od = file->private_data;
184
185 if (od->error)
186 return od->error;
187
188 if (ctx->pos == 0) {
189 if (!dir_emit_dot(file, ctx))
190 return 0;
Mike Marshall5db11c22015-07-17 10:38:12 -0400191 ctx->pos++;
Martin Brandenburg382f4582017-04-25 15:37:59 -0400192 }
193 if (ctx->pos == 1) {
194 if (!dir_emit_dotdot(file, ctx))
195 return 0;
196 ctx->pos++;
Mike Marshall5db11c22015-07-17 10:38:12 -0400197 }
198
Martin Brandenburg382f4582017-04-25 15:37:59 -0400199 r = 0;
200
Martin Brandenburg72f66b82017-04-25 15:38:00 -0400201 /*
202 * Must read more if the user has sought past what has been read
203 * so far. Stop a user who has sought past the end.
204 */
205 while (od->token != ORANGEFS_READDIR_END && ctx->pos - 2 >
206 od->len) {
207 r = orangefs_dir_more(oi, od, dentry);
208 if (r)
209 return r;
210 }
211 if (od->token == ORANGEFS_READDIR_END && ctx->pos - 2 >
212 od->len) {
213 return -EIO;
214 }
215
216 /* Then try to fill if there's any left in the buffer. */
217 if (ctx->pos - 2 < od->len) {
Martin Brandenburg382f4582017-04-25 15:37:59 -0400218 r = orangefs_dir_fill(oi, od, dentry, ctx);
219 if (r)
220 return r;
Mike Marshall5db11c22015-07-17 10:38:12 -0400221 }
222
Martin Brandenburg72f66b82017-04-25 15:38:00 -0400223 /* Finally get some more and try to fill. */
Martin Brandenburg382f4582017-04-25 15:37:59 -0400224 if (od->token != ORANGEFS_READDIR_END) {
225 r = orangefs_dir_more(oi, od, dentry);
226 if (r)
227 return r;
228 r = orangefs_dir_fill(oi, od, dentry, ctx);
Mike Marshall5db11c22015-07-17 10:38:12 -0400229 }
230
Martin Brandenburg382f4582017-04-25 15:37:59 -0400231 return r;
Mike Marshall5db11c22015-07-17 10:38:12 -0400232}
233
Yi Liu8bb8aef2015-11-24 15:12:14 -0500234static int orangefs_dir_open(struct inode *inode, struct file *file)
Mike Marshall5db11c22015-07-17 10:38:12 -0400235{
Martin Brandenburg382f4582017-04-25 15:37:59 -0400236 struct orangefs_dir *od;
237 file->private_data = kmalloc(sizeof(struct orangefs_dir),
238 GFP_KERNEL);
Mike Marshall5db11c22015-07-17 10:38:12 -0400239 if (!file->private_data)
240 return -ENOMEM;
Martin Brandenburg382f4582017-04-25 15:37:59 -0400241 od = file->private_data;
242 od->token = ORANGEFS_READDIR_START;
243 /*
244 * XXX: It seems wasteful to allocate such a large buffer for
245 * each request. Most will be much smaller.
246 */
247 od->directory = alloc_pages_exact(MAX_DIRECTORY, GFP_KERNEL);
248 if (!od->directory) {
249 kfree(file->private_data);
250 return -ENOMEM;
251 }
Martin Brandenburg382f4582017-04-25 15:37:59 -0400252 od->len = 0;
253 od->error = 0;
Mike Marshall5db11c22015-07-17 10:38:12 -0400254 return 0;
255}
256
Yi Liu8bb8aef2015-11-24 15:12:14 -0500257static int orangefs_dir_release(struct inode *inode, struct file *file)
Mike Marshall5db11c22015-07-17 10:38:12 -0400258{
Martin Brandenburg382f4582017-04-25 15:37:59 -0400259 struct orangefs_dir *od = file->private_data;
Yi Liu8bb8aef2015-11-24 15:12:14 -0500260 orangefs_flush_inode(inode);
Martin Brandenburg382f4582017-04-25 15:37:59 -0400261 free_pages_exact(od->directory, MAX_DIRECTORY);
262 kfree(od);
Mike Marshall5db11c22015-07-17 10:38:12 -0400263 return 0;
264}
265
Yi Liu8bb8aef2015-11-24 15:12:14 -0500266const struct file_operations orangefs_dir_operations = {
Martin Brandenburg72f66b82017-04-25 15:38:00 -0400267 .llseek = default_llseek,
Mike Marshall5db11c22015-07-17 10:38:12 -0400268 .read = generic_read_dir,
Martin Brandenburg382f4582017-04-25 15:37:59 -0400269 .iterate = orangefs_dir_iterate,
Yi Liu8bb8aef2015-11-24 15:12:14 -0500270 .open = orangefs_dir_open,
Martin Brandenburg382f4582017-04-25 15:37:59 -0400271 .release = orangefs_dir_release
Mike Marshall5db11c22015-07-17 10:38:12 -0400272};