18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2017 Omnibond Systems, L.L.C. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#include "protocol.h" 78c2ecf20Sopenharmony_ci#include "orangefs-kernel.h" 88c2ecf20Sopenharmony_ci#include "orangefs-bufmap.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_cistruct orangefs_dir_part { 118c2ecf20Sopenharmony_ci struct orangefs_dir_part *next; 128c2ecf20Sopenharmony_ci size_t len; 138c2ecf20Sopenharmony_ci}; 148c2ecf20Sopenharmony_ci 158c2ecf20Sopenharmony_cistruct orangefs_dir { 168c2ecf20Sopenharmony_ci __u64 token; 178c2ecf20Sopenharmony_ci struct orangefs_dir_part *part; 188c2ecf20Sopenharmony_ci loff_t end; 198c2ecf20Sopenharmony_ci int error; 208c2ecf20Sopenharmony_ci}; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci#define PART_SHIFT (24) 238c2ecf20Sopenharmony_ci#define PART_SIZE (1<<24) 248c2ecf20Sopenharmony_ci#define PART_MASK (~(PART_SIZE - 1)) 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_ci/* 278c2ecf20Sopenharmony_ci * There can be up to 512 directory entries. Each entry is encoded as 288c2ecf20Sopenharmony_ci * follows: 298c2ecf20Sopenharmony_ci * 4 bytes: string size (n) 308c2ecf20Sopenharmony_ci * n bytes: string 318c2ecf20Sopenharmony_ci * 1 byte: trailing zero 328c2ecf20Sopenharmony_ci * padding to 8 bytes 338c2ecf20Sopenharmony_ci * 16 bytes: khandle 348c2ecf20Sopenharmony_ci * padding to 8 bytes 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * The trailer_buf starts with a struct orangefs_readdir_response_s 378c2ecf20Sopenharmony_ci * which must be skipped to get to the directory data. 388c2ecf20Sopenharmony_ci * 398c2ecf20Sopenharmony_ci * The data which is received from the userspace daemon is termed a 408c2ecf20Sopenharmony_ci * part and is stored in a linked list in case more than one part is 418c2ecf20Sopenharmony_ci * needed for a large directory. 428c2ecf20Sopenharmony_ci * 438c2ecf20Sopenharmony_ci * The position pointer (ctx->pos) encodes the part and offset on which 448c2ecf20Sopenharmony_ci * to begin reading at. Bits above PART_SHIFT encode the part and bits 458c2ecf20Sopenharmony_ci * below PART_SHIFT encode the offset. Parts are stored in a linked 468c2ecf20Sopenharmony_ci * list which grows as data is received from the server. The overhead 478c2ecf20Sopenharmony_ci * associated with managing the list is presumed to be small compared to 488c2ecf20Sopenharmony_ci * the overhead of communicating with the server. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * As data is received from the server, it is placed at the end of the 518c2ecf20Sopenharmony_ci * part list. Data is parsed from the current position as it is needed. 528c2ecf20Sopenharmony_ci * When data is determined to be corrupt, it is either because the 538c2ecf20Sopenharmony_ci * userspace component has sent back corrupt data or because the file 548c2ecf20Sopenharmony_ci * pointer has been moved to an invalid location. Since the two cannot 558c2ecf20Sopenharmony_ci * be differentiated, return EIO. 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * Part zero is synthesized to contains `.' and `..'. Part one is the 588c2ecf20Sopenharmony_ci * first part of the part list. 598c2ecf20Sopenharmony_ci */ 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_cistatic int do_readdir(struct orangefs_inode_s *oi, 628c2ecf20Sopenharmony_ci struct orangefs_dir *od, struct dentry *dentry, 638c2ecf20Sopenharmony_ci struct orangefs_kernel_op_s *op) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci struct orangefs_readdir_response_s *resp; 668c2ecf20Sopenharmony_ci int bufi, r; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci /* 698c2ecf20Sopenharmony_ci * Despite the badly named field, readdir does not use shared 708c2ecf20Sopenharmony_ci * memory. However, there are a limited number of readdir 718c2ecf20Sopenharmony_ci * slots, which must be allocated here. This flag simply tells 728c2ecf20Sopenharmony_ci * the op scheduler to return the op here for retry. 738c2ecf20Sopenharmony_ci */ 748c2ecf20Sopenharmony_ci op->uses_shared_memory = 1; 758c2ecf20Sopenharmony_ci op->upcall.req.readdir.refn = oi->refn; 768c2ecf20Sopenharmony_ci op->upcall.req.readdir.token = od->token; 778c2ecf20Sopenharmony_ci op->upcall.req.readdir.max_dirent_count = 788c2ecf20Sopenharmony_ci ORANGEFS_MAX_DIRENT_COUNT_READDIR; 798c2ecf20Sopenharmony_ci 808c2ecf20Sopenharmony_ciagain: 818c2ecf20Sopenharmony_ci bufi = orangefs_readdir_index_get(); 828c2ecf20Sopenharmony_ci if (bufi < 0) { 838c2ecf20Sopenharmony_ci od->error = bufi; 848c2ecf20Sopenharmony_ci return bufi; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci op->upcall.req.readdir.buf_index = bufi; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci r = service_operation(op, "orangefs_readdir", 908c2ecf20Sopenharmony_ci get_interruptible_flag(dentry->d_inode)); 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci orangefs_readdir_index_put(bufi); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci if (op_state_purged(op)) { 958c2ecf20Sopenharmony_ci if (r == -EAGAIN) { 968c2ecf20Sopenharmony_ci vfree(op->downcall.trailer_buf); 978c2ecf20Sopenharmony_ci goto again; 988c2ecf20Sopenharmony_ci } else if (r == -EIO) { 998c2ecf20Sopenharmony_ci vfree(op->downcall.trailer_buf); 1008c2ecf20Sopenharmony_ci od->error = r; 1018c2ecf20Sopenharmony_ci return r; 1028c2ecf20Sopenharmony_ci } 1038c2ecf20Sopenharmony_ci } 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci if (r < 0) { 1068c2ecf20Sopenharmony_ci vfree(op->downcall.trailer_buf); 1078c2ecf20Sopenharmony_ci od->error = r; 1088c2ecf20Sopenharmony_ci return r; 1098c2ecf20Sopenharmony_ci } else if (op->downcall.status) { 1108c2ecf20Sopenharmony_ci vfree(op->downcall.trailer_buf); 1118c2ecf20Sopenharmony_ci od->error = op->downcall.status; 1128c2ecf20Sopenharmony_ci return op->downcall.status; 1138c2ecf20Sopenharmony_ci } 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* 1168c2ecf20Sopenharmony_ci * The maximum size is size per entry times the 512 entries plus 1178c2ecf20Sopenharmony_ci * the header. This is well under the limit. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_ci if (op->downcall.trailer_size > PART_SIZE) { 1208c2ecf20Sopenharmony_ci vfree(op->downcall.trailer_buf); 1218c2ecf20Sopenharmony_ci od->error = -EIO; 1228c2ecf20Sopenharmony_ci return -EIO; 1238c2ecf20Sopenharmony_ci } 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci resp = (struct orangefs_readdir_response_s *) 1268c2ecf20Sopenharmony_ci op->downcall.trailer_buf; 1278c2ecf20Sopenharmony_ci od->token = resp->token; 1288c2ecf20Sopenharmony_ci return 0; 1298c2ecf20Sopenharmony_ci} 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_cistatic int parse_readdir(struct orangefs_dir *od, 1328c2ecf20Sopenharmony_ci struct orangefs_kernel_op_s *op) 1338c2ecf20Sopenharmony_ci{ 1348c2ecf20Sopenharmony_ci struct orangefs_dir_part *part, *new; 1358c2ecf20Sopenharmony_ci size_t count; 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci count = 1; 1388c2ecf20Sopenharmony_ci part = od->part; 1398c2ecf20Sopenharmony_ci while (part) { 1408c2ecf20Sopenharmony_ci count++; 1418c2ecf20Sopenharmony_ci if (part->next) 1428c2ecf20Sopenharmony_ci part = part->next; 1438c2ecf20Sopenharmony_ci else 1448c2ecf20Sopenharmony_ci break; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci new = (void *)op->downcall.trailer_buf; 1488c2ecf20Sopenharmony_ci new->next = NULL; 1498c2ecf20Sopenharmony_ci new->len = op->downcall.trailer_size - 1508c2ecf20Sopenharmony_ci sizeof(struct orangefs_readdir_response_s); 1518c2ecf20Sopenharmony_ci if (!od->part) 1528c2ecf20Sopenharmony_ci od->part = new; 1538c2ecf20Sopenharmony_ci else 1548c2ecf20Sopenharmony_ci part->next = new; 1558c2ecf20Sopenharmony_ci count++; 1568c2ecf20Sopenharmony_ci od->end = count << PART_SHIFT; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci return 0; 1598c2ecf20Sopenharmony_ci} 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_cistatic int orangefs_dir_more(struct orangefs_inode_s *oi, 1628c2ecf20Sopenharmony_ci struct orangefs_dir *od, struct dentry *dentry) 1638c2ecf20Sopenharmony_ci{ 1648c2ecf20Sopenharmony_ci struct orangefs_kernel_op_s *op; 1658c2ecf20Sopenharmony_ci int r; 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci op = op_alloc(ORANGEFS_VFS_OP_READDIR); 1688c2ecf20Sopenharmony_ci if (!op) { 1698c2ecf20Sopenharmony_ci od->error = -ENOMEM; 1708c2ecf20Sopenharmony_ci return -ENOMEM; 1718c2ecf20Sopenharmony_ci } 1728c2ecf20Sopenharmony_ci r = do_readdir(oi, od, dentry, op); 1738c2ecf20Sopenharmony_ci if (r) { 1748c2ecf20Sopenharmony_ci od->error = r; 1758c2ecf20Sopenharmony_ci goto out; 1768c2ecf20Sopenharmony_ci } 1778c2ecf20Sopenharmony_ci r = parse_readdir(od, op); 1788c2ecf20Sopenharmony_ci if (r) { 1798c2ecf20Sopenharmony_ci od->error = r; 1808c2ecf20Sopenharmony_ci goto out; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci od->error = 0; 1848c2ecf20Sopenharmony_ciout: 1858c2ecf20Sopenharmony_ci op_release(op); 1868c2ecf20Sopenharmony_ci return od->error; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_cistatic int fill_from_part(struct orangefs_dir_part *part, 1908c2ecf20Sopenharmony_ci struct dir_context *ctx) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci const int offset = sizeof(struct orangefs_readdir_response_s); 1938c2ecf20Sopenharmony_ci struct orangefs_khandle *khandle; 1948c2ecf20Sopenharmony_ci __u32 *len, padlen; 1958c2ecf20Sopenharmony_ci loff_t i; 1968c2ecf20Sopenharmony_ci char *s; 1978c2ecf20Sopenharmony_ci i = ctx->pos & ~PART_MASK; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* The file offset from userspace is too large. */ 2008c2ecf20Sopenharmony_ci if (i > part->len) 2018c2ecf20Sopenharmony_ci return 1; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci /* 2048c2ecf20Sopenharmony_ci * If the seek pointer is positioned just before an entry it 2058c2ecf20Sopenharmony_ci * should find the next entry. 2068c2ecf20Sopenharmony_ci */ 2078c2ecf20Sopenharmony_ci if (i % 8) 2088c2ecf20Sopenharmony_ci i = i + (8 - i%8)%8; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci while (i < part->len) { 2118c2ecf20Sopenharmony_ci if (part->len < i + sizeof *len) 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci len = (void *)part + offset + i; 2148c2ecf20Sopenharmony_ci /* 2158c2ecf20Sopenharmony_ci * len is the size of the string itself. padlen is the 2168c2ecf20Sopenharmony_ci * total size of the encoded string. 2178c2ecf20Sopenharmony_ci */ 2188c2ecf20Sopenharmony_ci padlen = (sizeof *len + *len + 1) + 2198c2ecf20Sopenharmony_ci (8 - (sizeof *len + *len + 1)%8)%8; 2208c2ecf20Sopenharmony_ci if (part->len < i + padlen + sizeof *khandle) 2218c2ecf20Sopenharmony_ci goto next; 2228c2ecf20Sopenharmony_ci s = (void *)part + offset + i + sizeof *len; 2238c2ecf20Sopenharmony_ci if (s[*len] != 0) 2248c2ecf20Sopenharmony_ci goto next; 2258c2ecf20Sopenharmony_ci khandle = (void *)part + offset + i + padlen; 2268c2ecf20Sopenharmony_ci if (!dir_emit(ctx, s, *len, 2278c2ecf20Sopenharmony_ci orangefs_khandle_to_ino(khandle), 2288c2ecf20Sopenharmony_ci DT_UNKNOWN)) 2298c2ecf20Sopenharmony_ci return 0; 2308c2ecf20Sopenharmony_ci i += padlen + sizeof *khandle; 2318c2ecf20Sopenharmony_ci i = i + (8 - i%8)%8; 2328c2ecf20Sopenharmony_ci BUG_ON(i > part->len); 2338c2ecf20Sopenharmony_ci ctx->pos = (ctx->pos & PART_MASK) | i; 2348c2ecf20Sopenharmony_ci continue; 2358c2ecf20Sopenharmony_cinext: 2368c2ecf20Sopenharmony_ci i += 8; 2378c2ecf20Sopenharmony_ci } 2388c2ecf20Sopenharmony_ci return 1; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic int orangefs_dir_fill(struct orangefs_inode_s *oi, 2428c2ecf20Sopenharmony_ci struct orangefs_dir *od, struct dentry *dentry, 2438c2ecf20Sopenharmony_ci struct dir_context *ctx) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci struct orangefs_dir_part *part; 2468c2ecf20Sopenharmony_ci size_t count; 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci count = ((ctx->pos & PART_MASK) >> PART_SHIFT) - 1; 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_ci part = od->part; 2518c2ecf20Sopenharmony_ci while (part->next && count) { 2528c2ecf20Sopenharmony_ci count--; 2538c2ecf20Sopenharmony_ci part = part->next; 2548c2ecf20Sopenharmony_ci } 2558c2ecf20Sopenharmony_ci /* This means the userspace file offset is invalid. */ 2568c2ecf20Sopenharmony_ci if (count) { 2578c2ecf20Sopenharmony_ci od->error = -EIO; 2588c2ecf20Sopenharmony_ci return -EIO; 2598c2ecf20Sopenharmony_ci } 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci while (part && part->len) { 2628c2ecf20Sopenharmony_ci int r; 2638c2ecf20Sopenharmony_ci r = fill_from_part(part, ctx); 2648c2ecf20Sopenharmony_ci if (r < 0) { 2658c2ecf20Sopenharmony_ci od->error = r; 2668c2ecf20Sopenharmony_ci return r; 2678c2ecf20Sopenharmony_ci } else if (r == 0) { 2688c2ecf20Sopenharmony_ci /* Userspace buffer is full. */ 2698c2ecf20Sopenharmony_ci break; 2708c2ecf20Sopenharmony_ci } else { 2718c2ecf20Sopenharmony_ci /* 2728c2ecf20Sopenharmony_ci * The part ran out of data. Move to the next 2738c2ecf20Sopenharmony_ci * part. */ 2748c2ecf20Sopenharmony_ci ctx->pos = (ctx->pos & PART_MASK) + 2758c2ecf20Sopenharmony_ci (1 << PART_SHIFT); 2768c2ecf20Sopenharmony_ci part = part->next; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci return 0; 2808c2ecf20Sopenharmony_ci} 2818c2ecf20Sopenharmony_ci 2828c2ecf20Sopenharmony_cistatic loff_t orangefs_dir_llseek(struct file *file, loff_t offset, 2838c2ecf20Sopenharmony_ci int whence) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct orangefs_dir *od = file->private_data; 2868c2ecf20Sopenharmony_ci /* 2878c2ecf20Sopenharmony_ci * Delete the stored data so userspace sees new directory 2888c2ecf20Sopenharmony_ci * entries. 2898c2ecf20Sopenharmony_ci */ 2908c2ecf20Sopenharmony_ci if (!whence && offset < od->end) { 2918c2ecf20Sopenharmony_ci struct orangefs_dir_part *part = od->part; 2928c2ecf20Sopenharmony_ci while (part) { 2938c2ecf20Sopenharmony_ci struct orangefs_dir_part *next = part->next; 2948c2ecf20Sopenharmony_ci vfree(part); 2958c2ecf20Sopenharmony_ci part = next; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci od->token = ORANGEFS_ITERATE_START; 2988c2ecf20Sopenharmony_ci od->part = NULL; 2998c2ecf20Sopenharmony_ci od->end = 1 << PART_SHIFT; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci return default_llseek(file, offset, whence); 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_cistatic int orangefs_dir_iterate(struct file *file, 3058c2ecf20Sopenharmony_ci struct dir_context *ctx) 3068c2ecf20Sopenharmony_ci{ 3078c2ecf20Sopenharmony_ci struct orangefs_inode_s *oi; 3088c2ecf20Sopenharmony_ci struct orangefs_dir *od; 3098c2ecf20Sopenharmony_ci struct dentry *dentry; 3108c2ecf20Sopenharmony_ci int r; 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_ci dentry = file->f_path.dentry; 3138c2ecf20Sopenharmony_ci oi = ORANGEFS_I(dentry->d_inode); 3148c2ecf20Sopenharmony_ci od = file->private_data; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (od->error) 3178c2ecf20Sopenharmony_ci return od->error; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (ctx->pos == 0) { 3208c2ecf20Sopenharmony_ci if (!dir_emit_dot(file, ctx)) 3218c2ecf20Sopenharmony_ci return 0; 3228c2ecf20Sopenharmony_ci ctx->pos++; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci if (ctx->pos == 1) { 3258c2ecf20Sopenharmony_ci if (!dir_emit_dotdot(file, ctx)) 3268c2ecf20Sopenharmony_ci return 0; 3278c2ecf20Sopenharmony_ci ctx->pos = 1 << PART_SHIFT; 3288c2ecf20Sopenharmony_ci } 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci /* 3318c2ecf20Sopenharmony_ci * The seek position is in the first synthesized part but is not 3328c2ecf20Sopenharmony_ci * valid. 3338c2ecf20Sopenharmony_ci */ 3348c2ecf20Sopenharmony_ci if ((ctx->pos & PART_MASK) == 0) 3358c2ecf20Sopenharmony_ci return -EIO; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci r = 0; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci /* 3408c2ecf20Sopenharmony_ci * Must read more if the user has sought past what has been read 3418c2ecf20Sopenharmony_ci * so far. Stop a user who has sought past the end. 3428c2ecf20Sopenharmony_ci */ 3438c2ecf20Sopenharmony_ci while (od->token != ORANGEFS_ITERATE_END && 3448c2ecf20Sopenharmony_ci ctx->pos > od->end) { 3458c2ecf20Sopenharmony_ci r = orangefs_dir_more(oi, od, dentry); 3468c2ecf20Sopenharmony_ci if (r) 3478c2ecf20Sopenharmony_ci return r; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci if (od->token == ORANGEFS_ITERATE_END && ctx->pos > od->end) 3508c2ecf20Sopenharmony_ci return -EIO; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* Then try to fill if there's any left in the buffer. */ 3538c2ecf20Sopenharmony_ci if (ctx->pos < od->end) { 3548c2ecf20Sopenharmony_ci r = orangefs_dir_fill(oi, od, dentry, ctx); 3558c2ecf20Sopenharmony_ci if (r) 3568c2ecf20Sopenharmony_ci return r; 3578c2ecf20Sopenharmony_ci } 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci /* Finally get some more and try to fill. */ 3608c2ecf20Sopenharmony_ci if (od->token != ORANGEFS_ITERATE_END) { 3618c2ecf20Sopenharmony_ci r = orangefs_dir_more(oi, od, dentry); 3628c2ecf20Sopenharmony_ci if (r) 3638c2ecf20Sopenharmony_ci return r; 3648c2ecf20Sopenharmony_ci r = orangefs_dir_fill(oi, od, dentry, ctx); 3658c2ecf20Sopenharmony_ci } 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci return r; 3688c2ecf20Sopenharmony_ci} 3698c2ecf20Sopenharmony_ci 3708c2ecf20Sopenharmony_cistatic int orangefs_dir_open(struct inode *inode, struct file *file) 3718c2ecf20Sopenharmony_ci{ 3728c2ecf20Sopenharmony_ci struct orangefs_dir *od; 3738c2ecf20Sopenharmony_ci file->private_data = kmalloc(sizeof(struct orangefs_dir), 3748c2ecf20Sopenharmony_ci GFP_KERNEL); 3758c2ecf20Sopenharmony_ci if (!file->private_data) 3768c2ecf20Sopenharmony_ci return -ENOMEM; 3778c2ecf20Sopenharmony_ci od = file->private_data; 3788c2ecf20Sopenharmony_ci od->token = ORANGEFS_ITERATE_START; 3798c2ecf20Sopenharmony_ci od->part = NULL; 3808c2ecf20Sopenharmony_ci od->end = 1 << PART_SHIFT; 3818c2ecf20Sopenharmony_ci od->error = 0; 3828c2ecf20Sopenharmony_ci return 0; 3838c2ecf20Sopenharmony_ci} 3848c2ecf20Sopenharmony_ci 3858c2ecf20Sopenharmony_cistatic int orangefs_dir_release(struct inode *inode, struct file *file) 3868c2ecf20Sopenharmony_ci{ 3878c2ecf20Sopenharmony_ci struct orangefs_dir *od = file->private_data; 3888c2ecf20Sopenharmony_ci struct orangefs_dir_part *part = od->part; 3898c2ecf20Sopenharmony_ci while (part) { 3908c2ecf20Sopenharmony_ci struct orangefs_dir_part *next = part->next; 3918c2ecf20Sopenharmony_ci vfree(part); 3928c2ecf20Sopenharmony_ci part = next; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci kfree(od); 3958c2ecf20Sopenharmony_ci return 0; 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ciconst struct file_operations orangefs_dir_operations = { 3998c2ecf20Sopenharmony_ci .llseek = orangefs_dir_llseek, 4008c2ecf20Sopenharmony_ci .read = generic_read_dir, 4018c2ecf20Sopenharmony_ci .iterate = orangefs_dir_iterate, 4028c2ecf20Sopenharmony_ci .open = orangefs_dir_open, 4038c2ecf20Sopenharmony_ci .release = orangefs_dir_release 4048c2ecf20Sopenharmony_ci}; 405