15db11c21SMike Marshall /* 25db11c21SMike Marshall * (C) 2001 Clemson University and The University of Chicago 35db11c21SMike Marshall * 45db11c21SMike Marshall * See COPYING in top-level directory. 55db11c21SMike Marshall */ 65db11c21SMike Marshall 75db11c21SMike Marshall #include "protocol.h" 85db11c21SMike Marshall #include "pvfs2-kernel.h" 95db11c21SMike Marshall #include "pvfs2-bufmap.h" 105db11c21SMike Marshall 115db11c21SMike Marshall struct readdir_handle_s { 125db11c21SMike Marshall int buffer_index; 135db11c21SMike Marshall struct pvfs2_readdir_response_s readdir_response; 145db11c21SMike Marshall void *dents_buf; 155db11c21SMike Marshall }; 165db11c21SMike Marshall 175db11c21SMike Marshall /* 185db11c21SMike Marshall * decode routine needed by kmod to make sense of the shared page for readdirs. 195db11c21SMike Marshall */ 205db11c21SMike Marshall static long decode_dirents(char *ptr, struct pvfs2_readdir_response_s *readdir) 215db11c21SMike Marshall { 225db11c21SMike Marshall int i; 235db11c21SMike Marshall struct pvfs2_readdir_response_s *rd = 245db11c21SMike Marshall (struct pvfs2_readdir_response_s *) ptr; 255db11c21SMike Marshall char *buf = ptr; 265db11c21SMike Marshall char **pptr = &buf; 275db11c21SMike Marshall 285db11c21SMike Marshall readdir->token = rd->token; 295db11c21SMike Marshall readdir->pvfs_dirent_outcount = rd->pvfs_dirent_outcount; 30ef4af94eSAl Viro readdir->dirent_array = kcalloc(readdir->pvfs_dirent_outcount, 315db11c21SMike Marshall sizeof(*readdir->dirent_array), 325db11c21SMike Marshall GFP_KERNEL); 335db11c21SMike Marshall if (readdir->dirent_array == NULL) 345db11c21SMike Marshall return -ENOMEM; 355db11c21SMike Marshall *pptr += offsetof(struct pvfs2_readdir_response_s, dirent_array); 365db11c21SMike Marshall for (i = 0; i < readdir->pvfs_dirent_outcount; i++) { 375db11c21SMike Marshall dec_string(pptr, &readdir->dirent_array[i].d_name, 385db11c21SMike Marshall &readdir->dirent_array[i].d_length); 395db11c21SMike Marshall readdir->dirent_array[i].khandle = 405db11c21SMike Marshall *(struct pvfs2_khandle *) *pptr; 415db11c21SMike Marshall *pptr += 16; 425db11c21SMike Marshall } 435db11c21SMike Marshall return (unsigned long)*pptr - (unsigned long)ptr; 445db11c21SMike Marshall } 455db11c21SMike Marshall 465db11c21SMike Marshall static long readdir_handle_ctor(struct readdir_handle_s *rhandle, void *buf, 475db11c21SMike Marshall int buffer_index) 485db11c21SMike Marshall { 495db11c21SMike Marshall long ret; 505db11c21SMike Marshall 515db11c21SMike Marshall if (buf == NULL) { 525db11c21SMike Marshall gossip_err 535db11c21SMike Marshall ("Invalid NULL buffer specified in readdir_handle_ctor\n"); 545db11c21SMike Marshall return -ENOMEM; 555db11c21SMike Marshall } 565db11c21SMike Marshall if (buffer_index < 0) { 575db11c21SMike Marshall gossip_err 585db11c21SMike Marshall ("Invalid buffer index specified in readdir_handle_ctor\n"); 595db11c21SMike Marshall return -EINVAL; 605db11c21SMike Marshall } 615db11c21SMike Marshall rhandle->buffer_index = buffer_index; 625db11c21SMike Marshall rhandle->dents_buf = buf; 635db11c21SMike Marshall ret = decode_dirents(buf, &rhandle->readdir_response); 645db11c21SMike Marshall if (ret < 0) { 655db11c21SMike Marshall gossip_err("Could not decode readdir from buffer %ld\n", ret); 665db11c21SMike Marshall rhandle->buffer_index = -1; 675db11c21SMike Marshall gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n", buf); 685db11c21SMike Marshall vfree(buf); 695db11c21SMike Marshall rhandle->dents_buf = NULL; 705db11c21SMike Marshall } 715db11c21SMike Marshall return ret; 725db11c21SMike Marshall } 735db11c21SMike Marshall 745db11c21SMike Marshall static void readdir_handle_dtor(struct pvfs2_bufmap *bufmap, 755db11c21SMike Marshall struct readdir_handle_s *rhandle) 765db11c21SMike Marshall { 775db11c21SMike Marshall if (rhandle == NULL) 785db11c21SMike Marshall return; 795db11c21SMike Marshall 805db11c21SMike Marshall /* kfree(NULL) is safe */ 815db11c21SMike Marshall kfree(rhandle->readdir_response.dirent_array); 825db11c21SMike Marshall rhandle->readdir_response.dirent_array = NULL; 835db11c21SMike Marshall 845db11c21SMike Marshall if (rhandle->buffer_index >= 0) { 855db11c21SMike Marshall readdir_index_put(bufmap, rhandle->buffer_index); 865db11c21SMike Marshall rhandle->buffer_index = -1; 875db11c21SMike Marshall } 885db11c21SMike Marshall if (rhandle->dents_buf) { 895db11c21SMike Marshall gossip_debug(GOSSIP_DIR_DEBUG, "vfree %p\n", 905db11c21SMike Marshall rhandle->dents_buf); 915db11c21SMike Marshall vfree(rhandle->dents_buf); 925db11c21SMike Marshall rhandle->dents_buf = NULL; 935db11c21SMike Marshall } 945db11c21SMike Marshall } 955db11c21SMike Marshall 965db11c21SMike Marshall /* 975db11c21SMike Marshall * Read directory entries from an instance of an open directory. 985db11c21SMike Marshall */ 995db11c21SMike Marshall static int pvfs2_readdir(struct file *file, struct dir_context *ctx) 1005db11c21SMike Marshall { 1015db11c21SMike Marshall struct pvfs2_bufmap *bufmap = NULL; 1025db11c21SMike Marshall int ret = 0; 1035db11c21SMike Marshall int buffer_index; 10488309aaeSMike Marshall /* 10588309aaeSMike Marshall * ptoken supports Orangefs' distributed directory logic, added 10688309aaeSMike Marshall * in 2.9.2. 10788309aaeSMike Marshall */ 1085db11c21SMike Marshall __u64 *ptoken = file->private_data; 1095db11c21SMike Marshall __u64 pos = 0; 1105db11c21SMike Marshall ino_t ino = 0; 1115db11c21SMike Marshall struct dentry *dentry = file->f_path.dentry; 1125db11c21SMike Marshall struct pvfs2_kernel_op_s *new_op = NULL; 1135db11c21SMike Marshall struct pvfs2_inode_s *pvfs2_inode = PVFS2_I(dentry->d_inode); 1145db11c21SMike Marshall int buffer_full = 0; 1155db11c21SMike Marshall struct readdir_handle_s rhandle; 1165db11c21SMike Marshall int i = 0; 1175db11c21SMike Marshall int len = 0; 1185db11c21SMike Marshall ino_t current_ino = 0; 1195db11c21SMike Marshall char *current_entry = NULL; 1205db11c21SMike Marshall long bytes_decoded; 1215db11c21SMike Marshall 12288309aaeSMike Marshall gossip_debug(GOSSIP_DIR_DEBUG, 12388309aaeSMike Marshall "%s: ctx->pos:%lld, ptoken = %llu\n", 1245db11c21SMike Marshall __func__, 1255db11c21SMike Marshall lld(ctx->pos), 1265db11c21SMike Marshall llu(*ptoken)); 1275db11c21SMike Marshall 1285db11c21SMike Marshall pos = (__u64) ctx->pos; 1295db11c21SMike Marshall 1305db11c21SMike Marshall /* are we done? */ 1315db11c21SMike Marshall if (pos == PVFS_READDIR_END) { 1325db11c21SMike Marshall gossip_debug(GOSSIP_DIR_DEBUG, 1335db11c21SMike Marshall "Skipping to termination path\n"); 1345db11c21SMike Marshall return 0; 1355db11c21SMike Marshall } 1365db11c21SMike Marshall 1375db11c21SMike Marshall gossip_debug(GOSSIP_DIR_DEBUG, 1385db11c21SMike Marshall "pvfs2_readdir called on %s (pos=%llu)\n", 1395db11c21SMike Marshall dentry->d_name.name, llu(pos)); 1405db11c21SMike Marshall 1415db11c21SMike Marshall rhandle.buffer_index = -1; 1425db11c21SMike Marshall rhandle.dents_buf = NULL; 1435db11c21SMike Marshall memset(&rhandle.readdir_response, 0, sizeof(rhandle.readdir_response)); 1445db11c21SMike Marshall 1455db11c21SMike Marshall new_op = op_alloc(PVFS2_VFS_OP_READDIR); 1465db11c21SMike Marshall if (!new_op) 1475db11c21SMike Marshall return -ENOMEM; 1485db11c21SMike Marshall 1495db11c21SMike Marshall new_op->uses_shared_memory = 1; 1505db11c21SMike Marshall new_op->upcall.req.readdir.refn = pvfs2_inode->refn; 1515db11c21SMike Marshall new_op->upcall.req.readdir.max_dirent_count = MAX_DIRENT_COUNT_READDIR; 1525db11c21SMike Marshall 1535db11c21SMike Marshall gossip_debug(GOSSIP_DIR_DEBUG, 1545db11c21SMike Marshall "%s: upcall.req.readdir.refn.khandle: %pU\n", 1555db11c21SMike Marshall __func__, 1565db11c21SMike Marshall &new_op->upcall.req.readdir.refn.khandle); 1575db11c21SMike Marshall 1585db11c21SMike Marshall new_op->upcall.req.readdir.token = *ptoken; 1595db11c21SMike Marshall 1605db11c21SMike Marshall get_new_buffer_index: 1615db11c21SMike Marshall ret = readdir_index_get(&bufmap, &buffer_index); 1625db11c21SMike Marshall if (ret < 0) { 1635db11c21SMike Marshall gossip_lerr("pvfs2_readdir: readdir_index_get() failure (%d)\n", 1645db11c21SMike Marshall ret); 1655db11c21SMike Marshall goto out_free_op; 1665db11c21SMike Marshall } 1675db11c21SMike Marshall new_op->upcall.req.readdir.buf_index = buffer_index; 1685db11c21SMike Marshall 1695db11c21SMike Marshall ret = service_operation(new_op, 1705db11c21SMike Marshall "pvfs2_readdir", 1715db11c21SMike Marshall get_interruptible_flag(dentry->d_inode)); 1725db11c21SMike Marshall 1735db11c21SMike Marshall gossip_debug(GOSSIP_DIR_DEBUG, 1745db11c21SMike Marshall "Readdir downcall status is %d. ret:%d\n", 1755db11c21SMike Marshall new_op->downcall.status, 1765db11c21SMike Marshall ret); 1775db11c21SMike Marshall 1785db11c21SMike Marshall if (ret == -EAGAIN && op_state_purged(new_op)) { 1795db11c21SMike Marshall /* 1805db11c21SMike Marshall * readdir shared memory aread has been wiped due to 1815db11c21SMike Marshall * pvfs2-client-core restarting, so we must get a new 1825db11c21SMike Marshall * index into the shared memory. 1835db11c21SMike Marshall */ 1845db11c21SMike Marshall gossip_debug(GOSSIP_DIR_DEBUG, 1855db11c21SMike Marshall "%s: Getting new buffer_index for retry of readdir..\n", 1865db11c21SMike Marshall __func__); 1875db11c21SMike Marshall readdir_index_put(bufmap, buffer_index); 1885db11c21SMike Marshall goto get_new_buffer_index; 1895db11c21SMike Marshall } 1905db11c21SMike Marshall 1915db11c21SMike Marshall if (ret == -EIO && op_state_purged(new_op)) { 1925db11c21SMike Marshall gossip_err("%s: Client is down. Aborting readdir call.\n", 1935db11c21SMike Marshall __func__); 1945db11c21SMike Marshall readdir_index_put(bufmap, buffer_index); 1955db11c21SMike Marshall goto out_free_op; 1965db11c21SMike Marshall } 1975db11c21SMike Marshall 1985db11c21SMike Marshall if (ret < 0 || new_op->downcall.status != 0) { 1995db11c21SMike Marshall gossip_debug(GOSSIP_DIR_DEBUG, 2005db11c21SMike Marshall "Readdir request failed. Status:%d\n", 2015db11c21SMike Marshall new_op->downcall.status); 2025db11c21SMike Marshall readdir_index_put(bufmap, buffer_index); 2035db11c21SMike Marshall if (ret >= 0) 2045db11c21SMike Marshall ret = new_op->downcall.status; 2055db11c21SMike Marshall goto out_free_op; 2065db11c21SMike Marshall } 2075db11c21SMike Marshall 2085db11c21SMike Marshall bytes_decoded = 2095db11c21SMike Marshall readdir_handle_ctor(&rhandle, 2105db11c21SMike Marshall new_op->downcall.trailer_buf, 2115db11c21SMike Marshall buffer_index); 2125db11c21SMike Marshall if (bytes_decoded < 0) { 2135db11c21SMike Marshall gossip_err("pvfs2_readdir: Could not decode trailer buffer into a readdir response %d\n", 2145db11c21SMike Marshall ret); 2155db11c21SMike Marshall ret = bytes_decoded; 2165db11c21SMike Marshall readdir_index_put(bufmap, buffer_index); 2175db11c21SMike Marshall goto out_free_op; 2185db11c21SMike Marshall } 2195db11c21SMike Marshall 2205db11c21SMike Marshall if (bytes_decoded != new_op->downcall.trailer_size) { 22188309aaeSMike Marshall gossip_err("pvfs2_readdir: # bytes decoded (%ld) " 22288309aaeSMike Marshall "!= trailer size (%ld)\n", 2235db11c21SMike Marshall bytes_decoded, 2245db11c21SMike Marshall (long)new_op->downcall.trailer_size); 2255db11c21SMike Marshall ret = -EINVAL; 2265db11c21SMike Marshall goto out_destroy_handle; 2275db11c21SMike Marshall } 2285db11c21SMike Marshall 22988309aaeSMike Marshall /* 23088309aaeSMike Marshall * pvfs2 doesn't actually store dot and dot-dot, but 23188309aaeSMike Marshall * we need to have them represented. 23288309aaeSMike Marshall */ 2335db11c21SMike Marshall if (pos == 0) { 2345db11c21SMike Marshall ino = get_ino_from_khandle(dentry->d_inode); 2355db11c21SMike Marshall gossip_debug(GOSSIP_DIR_DEBUG, 2365db11c21SMike Marshall "%s: calling dir_emit of \".\" with pos = %llu\n", 2375db11c21SMike Marshall __func__, 2385db11c21SMike Marshall llu(pos)); 2395db11c21SMike Marshall ret = dir_emit(ctx, ".", 1, ino, DT_DIR); 24088309aaeSMike Marshall pos += 1; 2415db11c21SMike Marshall } 2425db11c21SMike Marshall 2435db11c21SMike Marshall if (pos == 1) { 2445db11c21SMike Marshall ino = get_parent_ino_from_dentry(dentry); 2455db11c21SMike Marshall gossip_debug(GOSSIP_DIR_DEBUG, 2465db11c21SMike Marshall "%s: calling dir_emit of \"..\" with pos = %llu\n", 2475db11c21SMike Marshall __func__, 2485db11c21SMike Marshall llu(pos)); 2495db11c21SMike Marshall ret = dir_emit(ctx, "..", 2, ino, DT_DIR); 25088309aaeSMike Marshall pos += 1; 2515db11c21SMike Marshall } 2525db11c21SMike Marshall 25388309aaeSMike Marshall /* 25488309aaeSMike Marshall * we stored PVFS_ITERATE_NEXT in ctx->pos last time around 25588309aaeSMike Marshall * to prevent "finding" dot and dot-dot on any iteration 25688309aaeSMike Marshall * other than the first. 25788309aaeSMike Marshall */ 25888309aaeSMike Marshall if (ctx->pos == PVFS_ITERATE_NEXT) 25988309aaeSMike Marshall ctx->pos = 0; 26088309aaeSMike Marshall 26188309aaeSMike Marshall for (i = ctx->pos; 26288309aaeSMike Marshall i < rhandle.readdir_response.pvfs_dirent_outcount; 26388309aaeSMike Marshall i++) { 2645db11c21SMike Marshall len = rhandle.readdir_response.dirent_array[i].d_length; 2655db11c21SMike Marshall current_entry = rhandle.readdir_response.dirent_array[i].d_name; 2665db11c21SMike Marshall current_ino = pvfs2_khandle_to_ino( 2675db11c21SMike Marshall &(rhandle.readdir_response.dirent_array[i].khandle)); 2685db11c21SMike Marshall 2695db11c21SMike Marshall gossip_debug(GOSSIP_DIR_DEBUG, 27088309aaeSMike Marshall "calling dir_emit for %s with len %d" 27188309aaeSMike Marshall ", ctx->pos %ld\n", 2725db11c21SMike Marshall current_entry, 2735db11c21SMike Marshall len, 27488309aaeSMike Marshall (unsigned long)ctx->pos); 27588309aaeSMike Marshall /* 27688309aaeSMike Marshall * type is unknown. We don't return object type 27788309aaeSMike Marshall * in the dirent_array. This leaves getdents 27888309aaeSMike Marshall * clueless about type. 27988309aaeSMike Marshall */ 2805db11c21SMike Marshall ret = 2815db11c21SMike Marshall dir_emit(ctx, current_entry, len, current_ino, DT_UNKNOWN); 28288309aaeSMike Marshall if (!ret) 28388309aaeSMike Marshall break; 2845db11c21SMike Marshall ctx->pos++; 28588309aaeSMike Marshall gossip_debug(GOSSIP_DIR_DEBUG, 2865db11c21SMike Marshall "%s: ctx->pos:%lld\n", 2875db11c21SMike Marshall __func__, 2885db11c21SMike Marshall lld(ctx->pos)); 2895db11c21SMike Marshall 2905db11c21SMike Marshall } 2915db11c21SMike Marshall 29288309aaeSMike Marshall /* 29388309aaeSMike Marshall * we ran all the way through the last batch, set up for 29488309aaeSMike Marshall * getting another batch... 29588309aaeSMike Marshall */ 29688309aaeSMike Marshall if (ret) { 2975db11c21SMike Marshall *ptoken = rhandle.readdir_response.token; 29888309aaeSMike Marshall ctx->pos = PVFS_ITERATE_NEXT; 2995db11c21SMike Marshall } 3005db11c21SMike Marshall 3015db11c21SMike Marshall /* 3025db11c21SMike Marshall * Did we hit the end of the directory? 3035db11c21SMike Marshall */ 3045db11c21SMike Marshall if (rhandle.readdir_response.token == PVFS_READDIR_END && 3055db11c21SMike Marshall !buffer_full) { 30688309aaeSMike Marshall gossip_debug(GOSSIP_DIR_DEBUG, 30788309aaeSMike Marshall "End of dir detected; setting ctx->pos to PVFS_READDIR_END.\n"); 3085db11c21SMike Marshall ctx->pos = PVFS_READDIR_END; 3095db11c21SMike Marshall } 3105db11c21SMike Marshall 3115db11c21SMike Marshall out_destroy_handle: 3125db11c21SMike Marshall readdir_handle_dtor(bufmap, &rhandle); 3135db11c21SMike Marshall out_free_op: 3145db11c21SMike Marshall op_release(new_op); 3155db11c21SMike Marshall gossip_debug(GOSSIP_DIR_DEBUG, "pvfs2_readdir returning %d\n", ret); 3165db11c21SMike Marshall return ret; 3175db11c21SMike Marshall } 3185db11c21SMike Marshall 3195db11c21SMike Marshall static int pvfs2_dir_open(struct inode *inode, struct file *file) 3205db11c21SMike Marshall { 3215db11c21SMike Marshall __u64 *ptoken; 3225db11c21SMike Marshall 3235db11c21SMike Marshall file->private_data = kmalloc(sizeof(__u64), GFP_KERNEL); 3245db11c21SMike Marshall if (!file->private_data) 3255db11c21SMike Marshall return -ENOMEM; 3265db11c21SMike Marshall 3275db11c21SMike Marshall ptoken = file->private_data; 3285db11c21SMike Marshall *ptoken = PVFS_READDIR_START; 3295db11c21SMike Marshall return 0; 3305db11c21SMike Marshall } 3315db11c21SMike Marshall 3325db11c21SMike Marshall static int pvfs2_dir_release(struct inode *inode, struct file *file) 3335db11c21SMike Marshall { 3345db11c21SMike Marshall pvfs2_flush_inode(inode); 3355db11c21SMike Marshall kfree(file->private_data); 3365db11c21SMike Marshall return 0; 3375db11c21SMike Marshall } 3385db11c21SMike Marshall 3395db11c21SMike Marshall /** PVFS2 implementation of VFS directory operations */ 3405db11c21SMike Marshall const struct file_operations pvfs2_dir_operations = { 3415db11c21SMike Marshall .read = generic_read_dir, 3425db11c21SMike Marshall .iterate = pvfs2_readdir, 3435db11c21SMike Marshall .open = pvfs2_dir_open, 3445db11c21SMike Marshall .release = pvfs2_dir_release, 3455db11c21SMike Marshall }; 346