0001
0002
0003
0004
0005
0006 #include "protocol.h"
0007 #include "orangefs-kernel.h"
0008 #include "orangefs-bufmap.h"
0009
0010 struct orangefs_dir_part {
0011 struct orangefs_dir_part *next;
0012 size_t len;
0013 };
0014
0015 struct orangefs_dir {
0016 __u64 token;
0017 struct orangefs_dir_part *part;
0018 loff_t end;
0019 int error;
0020 };
0021
0022 #define PART_SHIFT (24)
0023 #define PART_SIZE (1<<24)
0024 #define PART_MASK (~(PART_SIZE - 1))
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061 static int do_readdir(struct orangefs_inode_s *oi,
0062 struct orangefs_dir *od, struct dentry *dentry,
0063 struct orangefs_kernel_op_s *op)
0064 {
0065 struct orangefs_readdir_response_s *resp;
0066 int bufi, r;
0067
0068
0069
0070
0071
0072
0073
0074 op->uses_shared_memory = 1;
0075 op->upcall.req.readdir.refn = oi->refn;
0076 op->upcall.req.readdir.token = od->token;
0077 op->upcall.req.readdir.max_dirent_count =
0078 ORANGEFS_MAX_DIRENT_COUNT_READDIR;
0079
0080 again:
0081 bufi = orangefs_readdir_index_get();
0082 if (bufi < 0) {
0083 od->error = bufi;
0084 return bufi;
0085 }
0086
0087 op->upcall.req.readdir.buf_index = bufi;
0088
0089 r = service_operation(op, "orangefs_readdir",
0090 get_interruptible_flag(dentry->d_inode));
0091
0092 orangefs_readdir_index_put(bufi);
0093
0094 if (op_state_purged(op)) {
0095 if (r == -EAGAIN) {
0096 vfree(op->downcall.trailer_buf);
0097 goto again;
0098 } else if (r == -EIO) {
0099 vfree(op->downcall.trailer_buf);
0100 od->error = r;
0101 return r;
0102 }
0103 }
0104
0105 if (r < 0) {
0106 vfree(op->downcall.trailer_buf);
0107 od->error = r;
0108 return r;
0109 } else if (op->downcall.status) {
0110 vfree(op->downcall.trailer_buf);
0111 od->error = op->downcall.status;
0112 return op->downcall.status;
0113 }
0114
0115
0116
0117
0118
0119 if (op->downcall.trailer_size > PART_SIZE) {
0120 vfree(op->downcall.trailer_buf);
0121 od->error = -EIO;
0122 return -EIO;
0123 }
0124
0125 resp = (struct orangefs_readdir_response_s *)
0126 op->downcall.trailer_buf;
0127 od->token = resp->token;
0128 return 0;
0129 }
0130
0131 static int parse_readdir(struct orangefs_dir *od,
0132 struct orangefs_kernel_op_s *op)
0133 {
0134 struct orangefs_dir_part *part, *new;
0135 size_t count;
0136
0137 count = 1;
0138 part = od->part;
0139 while (part) {
0140 count++;
0141 if (part->next)
0142 part = part->next;
0143 else
0144 break;
0145 }
0146
0147 new = (void *)op->downcall.trailer_buf;
0148 new->next = NULL;
0149 new->len = op->downcall.trailer_size -
0150 sizeof(struct orangefs_readdir_response_s);
0151 if (!od->part)
0152 od->part = new;
0153 else
0154 part->next = new;
0155 count++;
0156 od->end = count << PART_SHIFT;
0157
0158 return 0;
0159 }
0160
0161 static int orangefs_dir_more(struct orangefs_inode_s *oi,
0162 struct orangefs_dir *od, struct dentry *dentry)
0163 {
0164 struct orangefs_kernel_op_s *op;
0165 int r;
0166
0167 op = op_alloc(ORANGEFS_VFS_OP_READDIR);
0168 if (!op) {
0169 od->error = -ENOMEM;
0170 return -ENOMEM;
0171 }
0172 r = do_readdir(oi, od, dentry, op);
0173 if (r) {
0174 od->error = r;
0175 goto out;
0176 }
0177 r = parse_readdir(od, op);
0178 if (r) {
0179 od->error = r;
0180 goto out;
0181 }
0182
0183 od->error = 0;
0184 out:
0185 op_release(op);
0186 return od->error;
0187 }
0188
0189 static int fill_from_part(struct orangefs_dir_part *part,
0190 struct dir_context *ctx)
0191 {
0192 const int offset = sizeof(struct orangefs_readdir_response_s);
0193 struct orangefs_khandle *khandle;
0194 __u32 *len, padlen;
0195 loff_t i;
0196 char *s;
0197 i = ctx->pos & ~PART_MASK;
0198
0199
0200 if (i > part->len)
0201 return 1;
0202
0203
0204
0205
0206
0207 if (i % 8)
0208 i = i + (8 - i%8)%8;
0209
0210 while (i < part->len) {
0211 if (part->len < i + sizeof *len)
0212 break;
0213 len = (void *)part + offset + i;
0214
0215
0216
0217
0218 padlen = (sizeof *len + *len + 1) +
0219 (8 - (sizeof *len + *len + 1)%8)%8;
0220 if (part->len < i + padlen + sizeof *khandle)
0221 goto next;
0222 s = (void *)part + offset + i + sizeof *len;
0223 if (s[*len] != 0)
0224 goto next;
0225 khandle = (void *)part + offset + i + padlen;
0226 if (!dir_emit(ctx, s, *len,
0227 orangefs_khandle_to_ino(khandle),
0228 DT_UNKNOWN))
0229 return 0;
0230 i += padlen + sizeof *khandle;
0231 i = i + (8 - i%8)%8;
0232 BUG_ON(i > part->len);
0233 ctx->pos = (ctx->pos & PART_MASK) | i;
0234 continue;
0235 next:
0236 i += 8;
0237 }
0238 return 1;
0239 }
0240
0241 static int orangefs_dir_fill(struct orangefs_inode_s *oi,
0242 struct orangefs_dir *od, struct dentry *dentry,
0243 struct dir_context *ctx)
0244 {
0245 struct orangefs_dir_part *part;
0246 size_t count;
0247
0248 count = ((ctx->pos & PART_MASK) >> PART_SHIFT) - 1;
0249
0250 part = od->part;
0251 while (part->next && count) {
0252 count--;
0253 part = part->next;
0254 }
0255
0256 if (count) {
0257 od->error = -EIO;
0258 return -EIO;
0259 }
0260
0261 while (part && part->len) {
0262 int r;
0263 r = fill_from_part(part, ctx);
0264 if (r < 0) {
0265 od->error = r;
0266 return r;
0267 } else if (r == 0) {
0268
0269 break;
0270 } else {
0271
0272
0273
0274 ctx->pos = (ctx->pos & PART_MASK) +
0275 (1 << PART_SHIFT);
0276 part = part->next;
0277 }
0278 }
0279 return 0;
0280 }
0281
0282 static loff_t orangefs_dir_llseek(struct file *file, loff_t offset,
0283 int whence)
0284 {
0285 struct orangefs_dir *od = file->private_data;
0286
0287
0288
0289
0290 if (!whence && offset < od->end) {
0291 struct orangefs_dir_part *part = od->part;
0292 while (part) {
0293 struct orangefs_dir_part *next = part->next;
0294 vfree(part);
0295 part = next;
0296 }
0297 od->token = ORANGEFS_ITERATE_START;
0298 od->part = NULL;
0299 od->end = 1 << PART_SHIFT;
0300 }
0301 return default_llseek(file, offset, whence);
0302 }
0303
0304 static int orangefs_dir_iterate(struct file *file,
0305 struct dir_context *ctx)
0306 {
0307 struct orangefs_inode_s *oi;
0308 struct orangefs_dir *od;
0309 struct dentry *dentry;
0310 int r;
0311
0312 dentry = file->f_path.dentry;
0313 oi = ORANGEFS_I(dentry->d_inode);
0314 od = file->private_data;
0315
0316 if (od->error)
0317 return od->error;
0318
0319 if (ctx->pos == 0) {
0320 if (!dir_emit_dot(file, ctx))
0321 return 0;
0322 ctx->pos++;
0323 }
0324 if (ctx->pos == 1) {
0325 if (!dir_emit_dotdot(file, ctx))
0326 return 0;
0327 ctx->pos = 1 << PART_SHIFT;
0328 }
0329
0330
0331
0332
0333
0334 if ((ctx->pos & PART_MASK) == 0)
0335 return -EIO;
0336
0337 r = 0;
0338
0339
0340
0341
0342
0343 while (od->token != ORANGEFS_ITERATE_END &&
0344 ctx->pos > od->end) {
0345 r = orangefs_dir_more(oi, od, dentry);
0346 if (r)
0347 return r;
0348 }
0349 if (od->token == ORANGEFS_ITERATE_END && ctx->pos > od->end)
0350 return -EIO;
0351
0352
0353 if (ctx->pos < od->end) {
0354 r = orangefs_dir_fill(oi, od, dentry, ctx);
0355 if (r)
0356 return r;
0357 }
0358
0359
0360 if (od->token != ORANGEFS_ITERATE_END) {
0361 r = orangefs_dir_more(oi, od, dentry);
0362 if (r)
0363 return r;
0364 r = orangefs_dir_fill(oi, od, dentry, ctx);
0365 }
0366
0367 return r;
0368 }
0369
0370 static int orangefs_dir_open(struct inode *inode, struct file *file)
0371 {
0372 struct orangefs_dir *od;
0373 file->private_data = kmalloc(sizeof(struct orangefs_dir),
0374 GFP_KERNEL);
0375 if (!file->private_data)
0376 return -ENOMEM;
0377 od = file->private_data;
0378 od->token = ORANGEFS_ITERATE_START;
0379 od->part = NULL;
0380 od->end = 1 << PART_SHIFT;
0381 od->error = 0;
0382 return 0;
0383 }
0384
0385 static int orangefs_dir_release(struct inode *inode, struct file *file)
0386 {
0387 struct orangefs_dir *od = file->private_data;
0388 struct orangefs_dir_part *part = od->part;
0389 while (part) {
0390 struct orangefs_dir_part *next = part->next;
0391 vfree(part);
0392 part = next;
0393 }
0394 kfree(od);
0395 return 0;
0396 }
0397
0398 const struct file_operations orangefs_dir_operations = {
0399 .llseek = orangefs_dir_llseek,
0400 .read = generic_read_dir,
0401 .iterate = orangefs_dir_iterate,
0402 .open = orangefs_dir_open,
0403 .release = orangefs_dir_release
0404 };