15db11c21SMike Marshall /* 2382f4581SMartin Brandenburg * Copyright 2017 Omnibond Systems, L.L.C. 35db11c21SMike Marshall */ 45db11c21SMike Marshall 55db11c21SMike Marshall #include "protocol.h" 6575e9461SMike Marshall #include "orangefs-kernel.h" 7575e9461SMike Marshall #include "orangefs-bufmap.h" 85db11c21SMike Marshall 95db11c21SMike Marshall /* 10382f4581SMartin Brandenburg * There can be up to 512 directory entries. Each entry is encoded as 11382f4581SMartin Brandenburg * follows: 12382f4581SMartin Brandenburg * 4 bytes: string size (n) 13382f4581SMartin Brandenburg * n bytes: string 14382f4581SMartin Brandenburg * 1 byte: trailing zero 15382f4581SMartin Brandenburg * padding to 8 bytes 16382f4581SMartin Brandenburg * 16 bytes: khandle 17382f4581SMartin Brandenburg * padding to 8 bytes 185db11c21SMike Marshall */ 19382f4581SMartin Brandenburg #define MAX_DIRECTORY ((4 + 257 + 3 + 16)*512) 20382f4581SMartin Brandenburg 21382f4581SMartin Brandenburg struct orangefs_dir { 22382f4581SMartin Brandenburg __u64 token; 23382f4581SMartin Brandenburg void *directory; 2472f66b83SMartin Brandenburg size_t len; 25382f4581SMartin Brandenburg int error; 26382f4581SMartin Brandenburg }; 27382f4581SMartin Brandenburg 28382f4581SMartin Brandenburg /* 29382f4581SMartin Brandenburg * The userspace component sends several directory entries of the 30382f4581SMartin Brandenburg * following format. The first four bytes are the string length not 31382f4581SMartin Brandenburg * including a trailing zero byte. This is followed by the string and a 32382f4581SMartin Brandenburg * trailing zero padded to the next four byte boundry. This is followed 33382f4581SMartin Brandenburg * by the sixteen byte khandle padded to the next eight byte boundry. 34382f4581SMartin Brandenburg * 35382f4581SMartin Brandenburg * The trailer_buf starts with a struct orangefs_readdir_response_s 36382f4581SMartin Brandenburg * which must be skipped to get to the directory data. 37382f4581SMartin Brandenburg */ 38382f4581SMartin Brandenburg 39382f4581SMartin Brandenburg static int orangefs_dir_more(struct orangefs_inode_s *oi, 40382f4581SMartin Brandenburg struct orangefs_dir *od, struct dentry *dentry) 415db11c21SMike Marshall { 42382f4581SMartin Brandenburg const size_t offset = 43382f4581SMartin Brandenburg sizeof(struct orangefs_readdir_response_s); 44382f4581SMartin Brandenburg struct orangefs_readdir_response_s *resp; 45382f4581SMartin Brandenburg struct orangefs_kernel_op_s *op; 46382f4581SMartin Brandenburg int bufi, r; 475db11c21SMike Marshall 48382f4581SMartin Brandenburg op = op_alloc(ORANGEFS_VFS_OP_READDIR); 49382f4581SMartin Brandenburg if (!op) { 50382f4581SMartin Brandenburg od->error = -ENOMEM; 51382f4581SMartin Brandenburg return -ENOMEM; 525db11c21SMike Marshall } 535db11c21SMike Marshall 545db11c21SMike Marshall /* 55382f4581SMartin Brandenburg * Despite the badly named field, readdir does not use shared 56382f4581SMartin Brandenburg * memory. However, there are a limited number of readdir 57382f4581SMartin Brandenburg * slots, which must be allocated here. This flag simply tells 58382f4581SMartin Brandenburg * the op scheduler to return the op here for retry. 595db11c21SMike Marshall */ 60382f4581SMartin Brandenburg op->uses_shared_memory = 1; 61382f4581SMartin Brandenburg op->upcall.req.readdir.refn = oi->refn; 62382f4581SMartin Brandenburg op->upcall.req.readdir.token = od->token; 63382f4581SMartin Brandenburg op->upcall.req.readdir.max_dirent_count = 64382f4581SMartin Brandenburg ORANGEFS_MAX_DIRENT_COUNT_READDIR; 655db11c21SMike Marshall 66382f4581SMartin Brandenburg again: 67382f4581SMartin Brandenburg bufi = orangefs_readdir_index_get(); 68382f4581SMartin Brandenburg if (bufi < 0) { 69382f4581SMartin Brandenburg op_release(op); 70382f4581SMartin Brandenburg od->error = bufi; 71382f4581SMartin Brandenburg return bufi; 72382f4581SMartin Brandenburg } 735db11c21SMike Marshall 74382f4581SMartin Brandenburg op->upcall.req.readdir.buf_index = bufi; 755db11c21SMike Marshall 76382f4581SMartin Brandenburg r = service_operation(op, "orangefs_readdir", 77382f4581SMartin Brandenburg get_interruptible_flag(dentry->d_inode)); 78382f4581SMartin Brandenburg 79382f4581SMartin Brandenburg orangefs_readdir_index_put(bufi); 80382f4581SMartin Brandenburg 81382f4581SMartin Brandenburg if (op_state_purged(op)) { 82382f4581SMartin Brandenburg if (r == -EAGAIN) { 83382f4581SMartin Brandenburg vfree(op->downcall.trailer_buf); 84382f4581SMartin Brandenburg goto again; 85382f4581SMartin Brandenburg } else if (r == -EIO) { 86382f4581SMartin Brandenburg vfree(op->downcall.trailer_buf); 87382f4581SMartin Brandenburg op_release(op); 88382f4581SMartin Brandenburg od->error = r; 89382f4581SMartin Brandenburg return r; 90382f4581SMartin Brandenburg } 91382f4581SMartin Brandenburg } 92382f4581SMartin Brandenburg 93382f4581SMartin Brandenburg if (r < 0) { 94382f4581SMartin Brandenburg vfree(op->downcall.trailer_buf); 95382f4581SMartin Brandenburg op_release(op); 96382f4581SMartin Brandenburg od->error = r; 97382f4581SMartin Brandenburg return r; 98382f4581SMartin Brandenburg } else if (op->downcall.status) { 99382f4581SMartin Brandenburg vfree(op->downcall.trailer_buf); 100382f4581SMartin Brandenburg op_release(op); 101382f4581SMartin Brandenburg od->error = op->downcall.status; 102382f4581SMartin Brandenburg return op->downcall.status; 103382f4581SMartin Brandenburg } 104382f4581SMartin Brandenburg 105382f4581SMartin Brandenburg resp = (struct orangefs_readdir_response_s *) 106382f4581SMartin Brandenburg op->downcall.trailer_buf; 107382f4581SMartin Brandenburg od->token = resp->token; 108382f4581SMartin Brandenburg 109382f4581SMartin Brandenburg if (od->len + op->downcall.trailer_size - offset <= 110382f4581SMartin Brandenburg MAX_DIRECTORY) { 111382f4581SMartin Brandenburg memcpy(od->directory + od->len, 112382f4581SMartin Brandenburg op->downcall.trailer_buf + offset, 113382f4581SMartin Brandenburg op->downcall.trailer_size - offset); 114382f4581SMartin Brandenburg od->len += op->downcall.trailer_size - offset; 115382f4581SMartin Brandenburg } else { 116382f4581SMartin Brandenburg /* This limit was chosen based on protocol limits. */ 117382f4581SMartin Brandenburg gossip_err("orangefs_dir_more: userspace sent too much data\n"); 118382f4581SMartin Brandenburg vfree(op->downcall.trailer_buf); 119382f4581SMartin Brandenburg op_release(op); 120382f4581SMartin Brandenburg od->error = -EIO; 121382f4581SMartin Brandenburg return -EIO; 122382f4581SMartin Brandenburg } 123382f4581SMartin Brandenburg 124382f4581SMartin Brandenburg vfree(op->downcall.trailer_buf); 125382f4581SMartin Brandenburg op_release(op); 1265db11c21SMike Marshall return 0; 1275db11c21SMike Marshall } 1285db11c21SMike Marshall 129382f4581SMartin Brandenburg static int orangefs_dir_fill(struct orangefs_inode_s *oi, 130382f4581SMartin Brandenburg struct orangefs_dir *od, struct dentry *dentry, 131382f4581SMartin Brandenburg struct dir_context *ctx) 132382f4581SMartin Brandenburg { 133382f4581SMartin Brandenburg struct orangefs_khandle *khandle; 134382f4581SMartin Brandenburg __u32 *len, padlen; 13572f66b83SMartin Brandenburg loff_t i; 136382f4581SMartin Brandenburg char *s; 13772f66b83SMartin Brandenburg i = ctx->pos - 2; 13872f66b83SMartin Brandenburg while (i < od->len) { 13972f66b83SMartin Brandenburg if (od->len < i + sizeof *len) 140382f4581SMartin Brandenburg goto eio; 14172f66b83SMartin Brandenburg len = od->directory + i; 142ee3b8d37SMartin Brandenburg /* 143382f4581SMartin Brandenburg * len is the size of the string itself. padlen is the 144382f4581SMartin Brandenburg * total size of the encoded string. 145ee3b8d37SMartin Brandenburg */ 146382f4581SMartin Brandenburg padlen = (sizeof *len + *len + 1) + 147382f4581SMartin Brandenburg (4 - (sizeof *len + *len + 1)%8)%8; 14872f66b83SMartin Brandenburg if (od->len < i + padlen + sizeof *khandle) 149382f4581SMartin Brandenburg goto eio; 15072f66b83SMartin Brandenburg s = od->directory + i + sizeof *len; 151382f4581SMartin Brandenburg if (s[*len] != 0) 152382f4581SMartin Brandenburg goto eio; 15372f66b83SMartin Brandenburg khandle = od->directory + i + padlen; 1545db11c21SMike Marshall 155382f4581SMartin Brandenburg if (!dir_emit(ctx, s, *len, 156382f4581SMartin Brandenburg orangefs_khandle_to_ino(khandle), DT_UNKNOWN)) 157382f4581SMartin Brandenburg return 0; 15872f66b83SMartin Brandenburg i += padlen + sizeof *khandle; 15972f66b83SMartin Brandenburg i = i + (8 - i%8)%8; 16072f66b83SMartin Brandenburg ctx->pos = i + 2; 1615db11c21SMike Marshall } 16272f66b83SMartin Brandenburg BUG_ON(i > od->len); 163382f4581SMartin Brandenburg return 0; 164382f4581SMartin Brandenburg eio: 16572f66b83SMartin Brandenburg /* 16672f66b83SMartin Brandenburg * Here either data from userspace is corrupt or the application 16772f66b83SMartin Brandenburg * has sought to an invalid location. 16872f66b83SMartin Brandenburg */ 169382f4581SMartin Brandenburg od->error = -EIO; 170382f4581SMartin Brandenburg return -EIO; 1715db11c21SMike Marshall } 1725db11c21SMike Marshall 173382f4581SMartin Brandenburg static int orangefs_dir_iterate(struct file *file, 174382f4581SMartin Brandenburg struct dir_context *ctx) 175382f4581SMartin Brandenburg { 176382f4581SMartin Brandenburg struct orangefs_inode_s *oi; 177382f4581SMartin Brandenburg struct orangefs_dir *od; 178382f4581SMartin Brandenburg struct dentry *dentry; 179382f4581SMartin Brandenburg int r; 1805db11c21SMike Marshall 181382f4581SMartin Brandenburg dentry = file->f_path.dentry; 182382f4581SMartin Brandenburg oi = ORANGEFS_I(dentry->d_inode); 183382f4581SMartin Brandenburg od = file->private_data; 1845db11c21SMike Marshall 185382f4581SMartin Brandenburg if (od->error) 186382f4581SMartin Brandenburg return od->error; 1879f5e2f7fSAl Viro 188382f4581SMartin Brandenburg if (ctx->pos == 0) { 189382f4581SMartin Brandenburg if (!dir_emit_dot(file, ctx)) 190382f4581SMartin Brandenburg return 0; 1915db11c21SMike Marshall ctx->pos++; 192382f4581SMartin Brandenburg } 193382f4581SMartin Brandenburg if (ctx->pos == 1) { 194382f4581SMartin Brandenburg if (!dir_emit_dotdot(file, ctx)) 195382f4581SMartin Brandenburg return 0; 196382f4581SMartin Brandenburg ctx->pos++; 1975db11c21SMike Marshall } 1985db11c21SMike Marshall 199382f4581SMartin Brandenburg r = 0; 200382f4581SMartin Brandenburg 20172f66b83SMartin Brandenburg /* 20272f66b83SMartin Brandenburg * Must read more if the user has sought past what has been read 20372f66b83SMartin Brandenburg * so far. Stop a user who has sought past the end. 20472f66b83SMartin Brandenburg */ 20572f66b83SMartin Brandenburg while (od->token != ORANGEFS_READDIR_END && ctx->pos - 2 > 20672f66b83SMartin Brandenburg od->len) { 20772f66b83SMartin Brandenburg r = orangefs_dir_more(oi, od, dentry); 20872f66b83SMartin Brandenburg if (r) 20972f66b83SMartin Brandenburg return r; 21072f66b83SMartin Brandenburg } 21172f66b83SMartin Brandenburg if (od->token == ORANGEFS_READDIR_END && ctx->pos - 2 > 21272f66b83SMartin Brandenburg od->len) { 21372f66b83SMartin Brandenburg return -EIO; 21472f66b83SMartin Brandenburg } 21572f66b83SMartin Brandenburg 21672f66b83SMartin Brandenburg /* Then try to fill if there's any left in the buffer. */ 21772f66b83SMartin Brandenburg if (ctx->pos - 2 < od->len) { 218382f4581SMartin Brandenburg r = orangefs_dir_fill(oi, od, dentry, ctx); 219382f4581SMartin Brandenburg if (r) 220382f4581SMartin Brandenburg return r; 2215db11c21SMike Marshall } 2225db11c21SMike Marshall 22372f66b83SMartin Brandenburg /* Finally get some more and try to fill. */ 224382f4581SMartin Brandenburg if (od->token != ORANGEFS_READDIR_END) { 225382f4581SMartin Brandenburg r = orangefs_dir_more(oi, od, dentry); 226382f4581SMartin Brandenburg if (r) 227382f4581SMartin Brandenburg return r; 228382f4581SMartin Brandenburg r = orangefs_dir_fill(oi, od, dentry, ctx); 2295db11c21SMike Marshall } 2305db11c21SMike Marshall 231382f4581SMartin Brandenburg return r; 2325db11c21SMike Marshall } 2335db11c21SMike Marshall 2348bb8aefdSYi Liu static int orangefs_dir_open(struct inode *inode, struct file *file) 2355db11c21SMike Marshall { 236382f4581SMartin Brandenburg struct orangefs_dir *od; 237382f4581SMartin Brandenburg file->private_data = kmalloc(sizeof(struct orangefs_dir), 238382f4581SMartin Brandenburg GFP_KERNEL); 2395db11c21SMike Marshall if (!file->private_data) 2405db11c21SMike Marshall return -ENOMEM; 241382f4581SMartin Brandenburg od = file->private_data; 242382f4581SMartin Brandenburg od->token = ORANGEFS_READDIR_START; 243382f4581SMartin Brandenburg /* 244382f4581SMartin Brandenburg * XXX: It seems wasteful to allocate such a large buffer for 245382f4581SMartin Brandenburg * each request. Most will be much smaller. 246382f4581SMartin Brandenburg */ 247382f4581SMartin Brandenburg od->directory = alloc_pages_exact(MAX_DIRECTORY, GFP_KERNEL); 248382f4581SMartin Brandenburg if (!od->directory) { 249382f4581SMartin Brandenburg kfree(file->private_data); 250382f4581SMartin Brandenburg return -ENOMEM; 251382f4581SMartin Brandenburg } 252382f4581SMartin Brandenburg od->len = 0; 253382f4581SMartin Brandenburg od->error = 0; 2545db11c21SMike Marshall return 0; 2555db11c21SMike Marshall } 2565db11c21SMike Marshall 2578bb8aefdSYi Liu static int orangefs_dir_release(struct inode *inode, struct file *file) 2585db11c21SMike Marshall { 259382f4581SMartin Brandenburg struct orangefs_dir *od = file->private_data; 2608bb8aefdSYi Liu orangefs_flush_inode(inode); 261382f4581SMartin Brandenburg free_pages_exact(od->directory, MAX_DIRECTORY); 262382f4581SMartin Brandenburg kfree(od); 2635db11c21SMike Marshall return 0; 2645db11c21SMike Marshall } 2655db11c21SMike Marshall 2668bb8aefdSYi Liu const struct file_operations orangefs_dir_operations = { 26772f66b83SMartin Brandenburg .llseek = default_llseek, 2685db11c21SMike Marshall .read = generic_read_dir, 269382f4581SMartin Brandenburg .iterate = orangefs_dir_iterate, 2708bb8aefdSYi Liu .open = orangefs_dir_open, 271382f4581SMartin Brandenburg .release = orangefs_dir_release 2725db11c21SMike Marshall }; 273