X-Git-Url: https://git.whamcloud.com/?p=fs%2Flustre-release.git;a=blobdiff_plain;f=lustre%2Fllite%2Fdir.c;h=961a00ebb22d3d6ff2411b0c56b1b9b390a0a043;hp=456f6f1091c9aba57f69565556270a8fb466708c;hb=7ce2000eb0f4e7b7ea1f362c17099881098cfef7;hpb=e1d6fea43563624277b5cc1c91c084a6b52db7fe diff --git a/lustre/llite/dir.c b/lustre/llite/dir.c index 456f6f1..961a00e 100644 --- a/lustre/llite/dir.c +++ b/lustre/llite/dir.c @@ -22,7 +22,7 @@ * and moved here. AV * * Adapted for Lustre Light - * Copyright (C) 2002, Cluster File Systems, Inc. + * Copyright (C) 2002-2003, Cluster File Systems, Inc. * */ @@ -30,8 +30,14 @@ #include #include #include -#include +#include +#include #include +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)) +# include // for wait_on_buffer +#else +# include // for wait_on_buffer +#endif #define DEBUG_SUBSYSTEM S_LLITE @@ -42,97 +48,51 @@ #include #include #include +#include "llite_internal.h" typedef struct ext2_dir_entry_2 ext2_dirent; #define PageChecked(page) test_bit(PG_checked, &(page)->flags) #define SetPageChecked(page) set_bit(PG_checked, &(page)->flags) - -static int ll_dir_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) -{ - return 0; -} - /* returns the page unlocked, but with a reference */ static int ll_dir_readpage(struct file *file, struct page *page) { struct inode *inode = page->mapping->host; - struct ll_sb_info *sbi = ll_i2sbi(inode); - char *buf; + struct ll_fid mdc_fid; __u64 offset; - int rc = 0; struct ptlrpc_request *request; - struct lustre_handle lockh; struct mds_body *body; - struct lookup_intent it = {IT_READDIR}; - + int rc = 0; ENTRY; - if ((inode->i_size + PAGE_CACHE_SIZE - 1) >> PAGE_SHIFT <= page->index){ - memset(kmap(page), 0, PAGE_CACHE_SIZE); - kunmap(page); - GOTO(readpage_out, rc); - } - - rc = ll_lock(inode, NULL, &it, &lockh); - request = (struct ptlrpc_request *)it.it_data; - ptlrpc_free_req(request); - if (rc != ELDLM_OK) { - CERROR("lock enqueue: err: %d\n", rc); - UnlockPage(page); - RETURN(rc); - } - ldlm_lock_dump((void *)(unsigned long)lockh.addr); + CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n", inode->i_ino, + inode->i_generation, inode); - if (Page_Uptodate(page)) { - CERROR("Explain this please?\n"); - GOTO(readpage_out, rc); - } + mdc_pack_fid(&mdc_fid, inode->i_ino, inode->i_generation, S_IFDIR); offset = page->index << PAGE_SHIFT; - buf = kmap(page); - rc = mdc_readpage(&sbi->ll_mdc_conn, inode->i_ino, - S_IFDIR, offset, buf, &request); - kunmap(page); - body = lustre_msg_buf(request->rq_repmsg, 0); - if (!body) - rc = -EINVAL; - if (body) - inode->i_size = body->size; - ptlrpc_free_req(request); - EXIT; + rc = mdc_readpage(ll_i2sbi(inode)->ll_mdc_exp, &mdc_fid, + offset, page, &request); + if (!rc) { + body = lustre_msg_buf(request->rq_repmsg, 0, sizeof (*body)); + LASSERT (body != NULL); /* checked by mdc_readpage() */ + LASSERT_REPSWABBED (request, 0); /* swabbed by mdc_readpage() */ - readpage_out: - if ( !rc ) + inode->i_size = body->size; SetPageUptodate(page); + } + ptlrpc_req_finished(request); - UnlockPage(page); - rc = ll_unlock(LCK_PR, &lockh); - if (rc != ELDLM_OK) - CERROR("ll_unlock: err: %d\n", rc); + unlock_page(page); + EXIT; return rc; -} /* ll_dir_readpage */ +} struct address_space_operations ll_dir_aops = { - readpage: ll_dir_readpage, - prepare_write: ll_dir_prepare_write + .readpage = ll_dir_readpage, }; -int waitfor_one_page(struct page *page) -{ - int error = 0; - struct buffer_head *bh, *head = page->buffers; - - bh = head; - do { - wait_on_buffer(bh); - if (buffer_req(bh) && !buffer_uptodate(bh)) - error = -EIO; - } while ((bh = bh->b_this_page) != head); - return error; -} - /* * ext2 uses block-sized chunks. Arguably, sector-sized ones would be * more robust, but we have what we have @@ -153,25 +113,6 @@ static inline unsigned long dir_pages(struct inode *inode) return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; } -extern void set_page_clean(struct page *page); - -static int ext2_commit_chunk(struct page *page, unsigned from, unsigned to) -{ - struct inode *dir = page->mapping->host; - loff_t new_size = (page->index << PAGE_CACHE_SHIFT) + to; - int err = 0; - - dir->i_version = ++event; - if (new_size > dir->i_size) - dir->i_size = new_size; - SetPageUptodate(page); - set_page_clean(page); - - //page->mapping->a_ops->commit_write(NULL, page, from, to); - //if (IS_SYNC(dir)) - // err = waitfor_one_page(page); - return err; -} static void ext2_check_page(struct page *page) { @@ -188,7 +129,7 @@ static void ext2_check_page(struct page *page) limit = dir->i_size & ~PAGE_CACHE_MASK; if (limit & (chunk_size - 1)) { CERROR("limit %d dir size %lld index %ld\n", - limit, dir->i_size, page->index); + limit, dir->i_size, page->index); goto Ebadsize; } for (offs = limit; offsi_ino, error, (page->index<i_ino, error, (page->index<inode), rec_len, p->name_len); goto fail; @@ -260,44 +201,63 @@ Eend: fail: SetPageChecked(page); SetPageError(page); - LBUG(); } -static struct page * ext2_get_page(struct inode *dir, unsigned long n) +static struct page *ll_get_dir_page(struct inode *dir, unsigned long n) { + struct ldlm_res_id res_id = + { .name = { dir->i_ino, (__u64)dir->i_generation} }; + struct lustre_handle lockh; + struct obd_device *obddev = class_exp2obd(ll_i2sbi(dir)->ll_mdc_exp); struct address_space *mapping = dir->i_mapping; - struct page *page = read_cache_page(mapping, n, - (filler_t*)mapping->a_ops->readpage, NULL); + struct page *page; + ldlm_policy_data_t policy = { .l_inodebits = { MDS_INODELOCK_UPDATE } }; + int rc; + + rc = ldlm_lock_match(obddev->obd_namespace, LDLM_FL_BLOCK_GRANTED, + &res_id, LDLM_IBITS, &policy, LCK_PR, &lockh); + if (!rc) { + struct lookup_intent it = { .it_op = IT_READDIR }; + struct ptlrpc_request *request; + struct mdc_op_data data; + + ll_prepare_mdc_op_data(&data, dir, NULL, NULL, 0, 0); + + rc = mdc_enqueue(ll_i2sbi(dir)->ll_mdc_exp, LDLM_IBITS, &it, + LCK_PR, &data, &lockh, NULL, 0, + ldlm_completion_ast, ll_mdc_blocking_ast, dir); + + request = (struct ptlrpc_request *)it.d.lustre.it_data; + if (request) + ptlrpc_req_finished(request); + if (rc < 0) { + CERROR("lock enqueue: rc: %d\n", rc); + return ERR_PTR(rc); + } + } + ldlm_lock_dump_handle(D_OTHER, &lockh); + + page = read_cache_page(mapping, n, + (filler_t*)mapping->a_ops->readpage, NULL); if (!IS_ERR(page)) { wait_on_page(page); - kmap(page); - if (!Page_Uptodate(page)) + (void)kmap(page); + if (!PageUptodate(page)) goto fail; if (!PageChecked(page)) ext2_check_page(page); if (PageError(page)) goto fail; } + +out_unlock: + ldlm_lock_decref(&lockh, LCK_PR); return page; fail: ext2_put_page(page); - return ERR_PTR(-EIO); -} - -/* - * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure. - * - * len <= EXT2_NAME_LEN and de != NULL are guaranteed by caller. - */ -static inline int ext2_match (int len, const char * const name, - struct ext2_dir_entry_2 * de) -{ - if (len != de->name_len) - return 0; - if (!de->inode) - return 0; - return !memcmp(name, de->name, len); + page = ERR_PTR(-EIO); + goto out_unlock; } /* @@ -329,38 +289,11 @@ static unsigned char ext2_filetype_table[EXT2_FT_MAX] = { [EXT2_FT_SYMLINK] DT_LNK, }; -static unsigned int ll_dt2fmt[DT_WHT + 1] = { - [EXT2_FT_UNKNOWN] 0, - [EXT2_FT_REG_FILE] S_IFREG, - [EXT2_FT_DIR] S_IFDIR, - [EXT2_FT_CHRDEV] S_IFCHR, - [EXT2_FT_BLKDEV] S_IFBLK, - [EXT2_FT_FIFO] S_IFIFO, - [EXT2_FT_SOCK] S_IFSOCK, - [EXT2_FT_SYMLINK] S_IFLNK -}; - -#define S_SHIFT 12 -static unsigned char ext2_type_by_mode[S_IFMT >> S_SHIFT] = { - [S_IFREG >> S_SHIFT] EXT2_FT_REG_FILE, - [S_IFDIR >> S_SHIFT] EXT2_FT_DIR, - [S_IFCHR >> S_SHIFT] EXT2_FT_CHRDEV, - [S_IFBLK >> S_SHIFT] EXT2_FT_BLKDEV, - [S_IFIFO >> S_SHIFT] EXT2_FT_FIFO, - [S_IFSOCK >> S_SHIFT] EXT2_FT_SOCK, - [S_IFLNK >> S_SHIFT] EXT2_FT_SYMLINK, -}; - -static inline void ext2_set_de_type(ext2_dirent *de, struct inode *inode) -{ - mode_t mode = inode->i_mode; - de->file_type = ext2_type_by_mode[(mode & S_IFMT)>>S_SHIFT]; -} int ll_readdir(struct file * filp, void * dirent, filldir_t filldir) { - loff_t pos = filp->f_pos; struct inode *inode = filp->f_dentry->d_inode; + loff_t pos = filp->f_pos; // XXX struct super_block *sb = inode->i_sb; unsigned offset = pos & ~PAGE_CACHE_MASK; unsigned long n = pos >> PAGE_CACHE_SHIFT; @@ -368,23 +301,37 @@ int ll_readdir(struct file * filp, void * dirent, filldir_t filldir) unsigned chunk_mask = ~(ext2_chunk_size(inode)-1); unsigned char *types = NULL; int need_revalidate = (filp->f_version != inode->i_version); + int rc = 0; ENTRY; + CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p) pos %llu/%llu\n", + inode->i_ino, inode->i_generation, inode, pos, inode->i_size); + if (pos > inode->i_size - EXT2_DIR_REC_LEN(1)) - GOTO(done, 0); + RETURN(0); types = ext2_filetype_table; for ( ; n < npages; n++, offset = 0) { char *kaddr, *limit; ext2_dirent *de; - struct page *page = ext2_get_page(inode, n); + struct page *page; + + CDEBUG(D_EXT2,"read %lu of dir %lu/%u page %lu/%lu size %llu\n", + PAGE_CACHE_SIZE, inode->i_ino, inode->i_generation, + n, npages, inode->i_size); + page = ll_get_dir_page(inode, n); /* size might have been updated by mdc_readpage */ npages = dir_pages(inode); - if (IS_ERR(page)) + if (IS_ERR(page)) { + rc = PTR_ERR(page); + CERROR("error reading dir %lu/%u page %lu: rc %d\n", + inode->i_ino, inode->i_generation, n, rc); continue; + } + kaddr = page_address(page); if (need_revalidate) { offset = ext2_validate_entry(kaddr, offset, chunk_mask); @@ -392,340 +339,317 @@ int ll_readdir(struct file * filp, void * dirent, filldir_t filldir) } de = (ext2_dirent *)(kaddr+offset); limit = kaddr + PAGE_CACHE_SIZE - EXT2_DIR_REC_LEN(1); - for ( ;(char*)de <= limit; de = ext2_next_entry(de)) + for ( ;(char*)de <= limit; de = ext2_next_entry(de)) { if (de->inode) { int over; unsigned char d_type = DT_UNKNOWN; + rc = 0; /* no error if we return something */ if (types && de->file_type < EXT2_FT_MAX) d_type = types[de->file_type]; offset = (char *)de - kaddr; over = filldir(dirent, de->name, de->name_len, - (n<inode), d_type); + (n<inode), d_type); if (over) { ext2_put_page(page); - GOTO(done,0); + GOTO(done, rc); } } + } ext2_put_page(page); } done: filp->f_pos = (n << PAGE_CACHE_SHIFT) | offset; filp->f_version = inode->i_version; - UPDATE_ATIME(inode); - RETURN(0); + update_atime(inode); + RETURN(rc); } -/* - * ext2_find_entry() - * - * finds an entry in the specified directory with the wanted name. It - * returns the page in which the entry was found, and the entry itself - * (as a parameter - res_dir). Page is returned mapped and unlocked. - * Entry is guaranteed to be valid. - */ -struct ext2_dir_entry_2 * ext2_find_entry (struct inode * dir, - struct dentry *dentry, struct page ** res_page) +static int ll_dir_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) { - const char *name = dentry->d_name.name; - int namelen = dentry->d_name.len; - unsigned reclen = EXT2_DIR_REC_LEN(namelen); - unsigned long start, n; - unsigned long npages = dir_pages(dir); - struct page *page = NULL; - ext2_dirent * de; - - /* OFFSET_CACHE */ - *res_page = NULL; - - // start = dir->u.ext2_i.i_dir_start_lookup; - start = 0; - if (start >= npages) - start = 0; - n = start; - do { - char *kaddr; - page = ext2_get_page(dir, n); - if (!IS_ERR(page)) { - kaddr = page_address(page); - de = (ext2_dirent *) kaddr; - kaddr += PAGE_CACHE_SIZE - reclen; - while ((char *) de <= kaddr) { - if (ext2_match (namelen, name, de)) - goto found; - de = ext2_next_entry(de); - } - ext2_put_page(page); + struct ll_sb_info *sbi = ll_i2sbi(inode); + struct obd_ioctl_data *data; + ENTRY; + + CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), cmd=%#x\n", + inode->i_ino, inode->i_generation, inode, cmd); + + if (_IOC_TYPE(cmd) == 'T') /* tty ioctls */ + return -ENOTTY; + + lprocfs_counter_incr(ll_i2sbi(inode)->ll_stats, LPROC_LL_IOCTL); + switch(cmd) { + case EXT3_IOC_GETFLAGS: + case EXT3_IOC_SETFLAGS: + RETURN(ll_iocontrol(inode, file, cmd, arg)); + case IOC_MDC_LOOKUP: { + struct ptlrpc_request *request = NULL; + struct ll_fid fid; + char *buf = NULL; + char *filename; + int namelen, rc, len = 0; + unsigned long valid; + + rc = obd_ioctl_getdata(&buf, &len, (void *)arg); + if (rc) + RETURN(rc); + data = (void *)buf; + + filename = data->ioc_inlbuf1; + namelen = data->ioc_inllen1; + + if (namelen < 1) { + CDEBUG(D_INFO, "IOC_MDC_LOOKUP missing filename\n"); + GOTO(out, rc = -EINVAL); } - if (++n >= npages) - n = 0; - } while (n != start); - return NULL; - -found: - *res_page = page; - // dir->u.ext2_i.i_dir_start_lookup = n; - return de; -} -struct ext2_dir_entry_2 * ext2_dotdot (struct inode *dir, struct page **p) -{ - struct page *page = ext2_get_page(dir, 0); - ext2_dirent *de = NULL; + valid = OBD_MD_FLID; + ll_inode2fid(&fid, inode); + rc = mdc_getattr_name(sbi->ll_mdc_exp, &fid, + filename, namelen, valid, 0, &request); + if (rc < 0) { + CDEBUG(D_INFO, "mdc_getattr_name: %d\n", rc); + GOTO(out, rc); + } - if (!IS_ERR(page)) { - de = ext2_next_entry((ext2_dirent *) page_address(page)); - *p = page; - } - return de; -} + ptlrpc_req_finished(request); -obd_id ll_inode_by_name(struct inode * dir, struct dentry *dentry, int *type) -{ - obd_id res = 0; - struct ext2_dir_entry_2 * de; - struct page *page; + EXIT; + out: + obd_ioctl_freedata(buf, len); + return rc; + } + case LL_IOC_LOV_SETSTRIPE: { + struct ptlrpc_request *request = NULL; + struct mdc_op_data op_data; + struct iattr attr = { 0 }; + struct lov_user_md lum, *lump = (struct lov_user_md *)arg; + int rc = 0; + + ll_prepare_mdc_op_data(&op_data, inode, NULL, NULL, 0, 0); + + LASSERT(sizeof(lum) == sizeof(*lump)); + LASSERT(sizeof(lum.lmm_objects[0]) == + sizeof(lump->lmm_objects[0])); + rc = copy_from_user(&lum, lump, sizeof(lum)); + if (rc) + return(-EFAULT); + + if (lum.lmm_magic != LOV_USER_MAGIC) + RETURN(-EINVAL); + + rc = mdc_setattr(sbi->ll_mdc_exp, &op_data, + &attr, &lum, sizeof(lum), NULL, 0, &request); + if (rc) { + ptlrpc_req_finished(request); + if (rc != -EPERM && rc != -EACCES) + CERROR("mdc_setattr fails: rc = %d\n", rc); + return rc; + } + ptlrpc_req_finished(request); - de = ext2_find_entry (dir, dentry, &page); - if (de) { - res = le32_to_cpu(de->inode); - *type = ll_dt2fmt[de->file_type]; - kunmap(page); - page_cache_release(page); + return rc; } - return res; -} + case LL_IOC_LOV_GETSTRIPE: { + struct ptlrpc_request *request = NULL; + struct lov_user_md *lump = (struct lov_user_md *)arg; + struct lov_mds_md *lmm; + struct ll_fid fid; + struct mds_body *body; + unsigned long valid = 0; + int rc, lmmsize; + + valid |= OBD_MD_FLDIREA; + + ll_inode2fid(&fid, inode); + rc = mdc_getattr(sbi->ll_mdc_exp, &fid, valid, + obd_size_diskmd(sbi->ll_osc_exp, NULL), + &request); + if (rc < 0) { + CDEBUG(D_INFO, "mdc_getattr failed: rc = %d\n", rc); + RETURN(rc); + } -/* Releases the page */ -void ext2_set_link(struct inode *dir, struct ext2_dir_entry_2 *de, - struct page *page, struct inode *inode) -{ - unsigned from = (char *) de - (char *) page_address(page); - unsigned to = from + le16_to_cpu(de->rec_len); - int err; - - lock_page(page); - err = page->mapping->a_ops->prepare_write(NULL, page, from, to); - if (err) - LBUG(); - de->inode = cpu_to_le32(inode->i_ino); - ext2_set_de_type (de, inode); - dir->i_mtime = dir->i_ctime = CURRENT_TIME; - err = ext2_commit_chunk(page, from, to); - UnlockPage(page); - ext2_put_page(page); -} + body = lustre_msg_buf(request->rq_repmsg, 0, sizeof(*body)); + LASSERT(body != NULL); /* checked by mdc_getattr_name */ + LASSERT_REPSWABBED(request, 0);/* swabbed by mdc_getattr_name */ -/* - * Parent is locked. - */ -int ll_add_link (struct dentry *dentry, struct inode *inode) -{ - struct inode *dir = dentry->d_parent->d_inode; - const char *name = dentry->d_name.name; - int namelen = dentry->d_name.len; - unsigned reclen = EXT2_DIR_REC_LEN(namelen); - unsigned short rec_len, name_len; - struct page *page = NULL; - ext2_dirent * de; - unsigned long npages = dir_pages(dir); - unsigned long n; - char *kaddr; - unsigned from, to; - int err; - - /* We take care of directory expansion in the same loop */ - for (n = 0; n <= npages; n++) { - page = ext2_get_page(dir, n); - err = PTR_ERR(page); - if (IS_ERR(page)) - goto out; - kaddr = page_address(page); - de = (ext2_dirent *)kaddr; - kaddr += PAGE_CACHE_SIZE - reclen; - while ((char *)de <= kaddr) { - err = -EEXIST; - if (ext2_match (namelen, name, de)) - goto out_page; - name_len = EXT2_DIR_REC_LEN(de->name_len); - rec_len = le16_to_cpu(de->rec_len); - if ( n==npages && rec_len == 0) { - CERROR("Fatal dir behaviour\n"); - goto out_page; - } - if (!de->inode && rec_len >= reclen) - goto got_it; - if (rec_len >= name_len + reclen) - goto got_it; - de = (ext2_dirent *) ((char *) de + rec_len); - } - ext2_put_page(page); - } - LBUG(); - return -EINVAL; - -got_it: - from = (char*)de - (char*)page_address(page); - to = from + rec_len; - lock_page(page); - err = page->mapping->a_ops->prepare_write(NULL, page, from, to); - if (err) - goto out_unlock; - if (de->inode) { - ext2_dirent *de1 = (ext2_dirent *) ((char *) de + name_len); - de1->rec_len = cpu_to_le16(rec_len - name_len); - de->rec_len = cpu_to_le16(name_len); - de = de1; + lmmsize = body->eadatasize; + if (lmmsize == 0) + GOTO(out_get, rc = -ENODATA); + + lmm = lustre_msg_buf(request->rq_repmsg, 1, lmmsize); + LASSERT(lmm != NULL); + LASSERT_REPSWABBED(request, 1); + rc = copy_to_user(lump, lmm, lmmsize); + if (rc) + GOTO(out_get, rc = -EFAULT); + + EXIT; + out_get: + ptlrpc_req_finished(request); + RETURN(rc); } - de->name_len = namelen; - memcpy (de->name, name, namelen); - de->inode = cpu_to_le32(inode->i_ino); - ext2_set_de_type (de, inode); - CDEBUG(D_INODE, "type set to %o\n", de->file_type); - dir->i_mtime = dir->i_ctime = CURRENT_TIME; - err = ext2_commit_chunk(page, from, to); + case IOC_MDC_GETSTRIPE: { + struct ptlrpc_request *request = NULL; + struct ll_fid fid; + struct mds_body *body; + struct lov_user_md *lump = (struct lov_user_md *)arg; + struct lov_mds_md *lmm; + char *filename; + int rc, lmmsize; + + filename = getname((const char *)arg); + if (IS_ERR(filename)) + RETURN(PTR_ERR(filename)); + + ll_inode2fid(&fid, inode); + rc = mdc_getattr_name(sbi->ll_mdc_exp, &fid, filename, + strlen(filename)+1, OBD_MD_FLEASIZE, + obd_size_diskmd(sbi->ll_osc_exp, NULL), + &request); + if (rc < 0) { + CDEBUG(D_INFO, "mdc_getattr_name failed on %s: rc %d\n", + filename, rc); + GOTO(out_name, rc); + } - // change_inode happens with the commit_chunk - /* XXX OFFSET_CACHE */ + body = lustre_msg_buf(request->rq_repmsg, 0, sizeof (*body)); + LASSERT(body != NULL); /* checked by mdc_getattr_name */ + LASSERT_REPSWABBED(request, 0);/* swabbed by mdc_getattr_name */ -out_unlock: - UnlockPage(page); -out_page: - ext2_put_page(page); -out: - return err; -} + lmmsize = body->eadatasize; -/* - * ext2_delete_entry deletes a directory entry by merging it with the - * previous entry. Page is up-to-date. Releases the page. - */ -int ext2_delete_entry (struct ext2_dir_entry_2 * dir, struct page * page ) -{ - struct address_space *mapping = page->mapping; - struct inode *inode = mapping->host; - char *kaddr = page_address(page); - unsigned from = ((char*)dir - kaddr) & ~(ext2_chunk_size(inode)-1); - unsigned to = ((char*)dir - kaddr) + le16_to_cpu(dir->rec_len); - ext2_dirent * pde = NULL; - ext2_dirent * de = (ext2_dirent *) (kaddr + from); - int err; - - while ((char*)de < (char*)dir) { - pde = de; - de = ext2_next_entry(de); - } - if (pde) - from = (char*)pde - (char*)page_address(page); - lock_page(page); - err = mapping->a_ops->prepare_write(NULL, page, from, to); - if (err) - LBUG(); - if (pde) - pde->rec_len = cpu_to_le16(to-from); - dir->inode = 0; - inode->i_ctime = inode->i_mtime = CURRENT_TIME; - err = ext2_commit_chunk(page, from, to); - UnlockPage(page); - ext2_put_page(page); - return err; -} + if (!(body->valid & OBD_MD_FLEASIZE) || lmmsize == 0) + GOTO(out_req, rc = -ENODATA); -/* - * Set the first fragment of directory. - */ -int ext2_make_empty(struct inode *inode, struct inode *parent) -{ - struct address_space *mapping = inode->i_mapping; - struct page *page = grab_cache_page(mapping, 0); - unsigned chunk_size = ext2_chunk_size(inode); - struct ext2_dir_entry_2 * de; - char *base; - int err; - ENTRY; + if (lmmsize > 4096) + GOTO(out_req, rc = -EFBIG); - if (!page) - return -ENOMEM; - base = kmap(page); - if (!base) - return -ENOMEM; - - err = mapping->a_ops->prepare_write(NULL, page, 0, chunk_size); - if (err) - goto fail; - - de = (struct ext2_dir_entry_2 *) base; - de->name_len = 1; - de->rec_len = cpu_to_le16(EXT2_DIR_REC_LEN(1)); - memcpy (de->name, ".\0\0", 4); - de->inode = cpu_to_le32(inode->i_ino); - ext2_set_de_type (de, inode); - - de = (struct ext2_dir_entry_2 *) (base + EXT2_DIR_REC_LEN(1)); - de->name_len = 2; - de->rec_len = cpu_to_le16(chunk_size - EXT2_DIR_REC_LEN(1)); - de->inode = cpu_to_le32(parent->i_ino); - memcpy (de->name, "..\0", 4); - ext2_set_de_type (de, inode); - - err = ext2_commit_chunk(page, 0, chunk_size); -fail: - kunmap(page); - UnlockPage(page); - page_cache_release(page); - ENTRY; - return err; -} + lmm = lustre_msg_buf(request->rq_repmsg, 1, lmmsize); + LASSERT(lmm != NULL); + LASSERT_REPSWABBED(request, 1); -/* - * routine to check that the specified directory is empty (for rmdir) - */ -int ext2_empty_dir (struct inode * inode) -{ - struct page *page = NULL; - unsigned long i, npages = dir_pages(inode); + rc = copy_to_user(lump, lmm, lmmsize); + if (rc) + GOTO(out_req, rc = -EFAULT); - for (i = 0; i < npages; i++) { - char *kaddr; - ext2_dirent * de; - page = ext2_get_page(inode, i); + EXIT; + out_req: + ptlrpc_req_finished(request); + out_name: + putname(filename); + return rc; + } + case OBD_IOC_PING: { + struct ptlrpc_request *req = NULL; + char *buf = NULL; + int rc, len=0; + struct client_obd *cli; + struct obd_device *obd; + + rc = obd_ioctl_getdata(&buf, &len, (void *)arg); + if (rc) + RETURN(rc); + data = (void *)buf; + + obd = class_name2obd(data->ioc_inlbuf1); + + if (!obd ) + GOTO(out_ping, rc = -ENODEV); + + if (!obd->obd_attached) { + CERROR("Device %d not attached\n", obd->obd_minor); + GOTO(out_ping, rc = -ENODEV); + } + if (!obd->obd_set_up) { + CERROR("Device %d still not setup\n", obd->obd_minor); + GOTO(out_ping, rc = -ENODEV); + } + cli = &obd->u.cli; + req = ptlrpc_prep_req(cli->cl_import, OBD_PING, 0, NULL, NULL); + if (!req) + GOTO(out_ping, rc = -ENOMEM); - if (IS_ERR(page)) - continue; + req->rq_replen = lustre_msg_size(0, NULL); + req->rq_send_state = LUSTRE_IMP_FULL; - kaddr = page_address(page); - de = (ext2_dirent *)kaddr; - kaddr += PAGE_CACHE_SIZE-EXT2_DIR_REC_LEN(1); - - while ((char *)de <= kaddr) { - if (de->inode != 0) { - /* check for . and .. */ - if (de->name[0] != '.') - goto not_empty; - if (de->name_len > 2) - goto not_empty; - if (de->name_len < 2) { - if (de->inode != - cpu_to_le32(inode->i_ino)) - goto not_empty; - } else if (de->name[1] != '.') - goto not_empty; - } - de = ext2_next_entry(de); + rc = ptlrpc_queue_wait(req); + + ptlrpc_req_finished(req); + out_ping: + obd_ioctl_freedata(buf, len); + return rc; + } + case OBD_IOC_LLOG_CATINFO: { + struct ptlrpc_request *req = NULL; + char *buf = NULL; + int rc, len = 0; + char *bufs[2], *str; + int lens[2], size; + + rc = obd_ioctl_getdata(&buf, &len, (void *)arg); + if (rc) + RETURN(rc); + data = (void *)buf; + + if (!data->ioc_inlbuf1) { + obd_ioctl_freedata(buf, len); + RETURN(-EINVAL); } - ext2_put_page(page); + + lens[0] = data->ioc_inllen1; + bufs[0] = data->ioc_inlbuf1; + if (data->ioc_inllen2) { + lens[1] = data->ioc_inllen2; + bufs[1] = data->ioc_inlbuf2; + } else { + lens[1] = 0; + bufs[1] = NULL; + } + size = data->ioc_plen1; + req = ptlrpc_prep_req(sbi2mdc(sbi)->cl_import, LLOG_CATINFO, + 2, lens, bufs); + if (!req) + GOTO(out_catinfo, rc = -ENOMEM); + req->rq_replen = lustre_msg_size(1, &size); + + rc = ptlrpc_queue_wait(req); + str = lustre_msg_string(req->rq_repmsg, 0, data->ioc_plen1); + if (!rc) + rc = copy_to_user(data->ioc_pbuf1, str, + data->ioc_plen1); + ptlrpc_req_finished(req); + out_catinfo: + obd_ioctl_freedata(buf, len); + RETURN(rc); } - return 1; + default: + return obd_iocontrol(cmd, sbi->ll_osc_exp,0,NULL,(void *)arg); + } +} -not_empty: - ext2_put_page(page); - return 0; +int ll_dir_open(struct inode *inode, struct file *file) +{ + ENTRY; + RETURN(ll_file_open(inode, file)); +} + +int ll_dir_release(struct inode *inode, struct file *file) +{ + ENTRY; + RETURN(ll_file_release(inode, file)); } struct file_operations ll_dir_operations = { - read: generic_read_dir, - readdir: ll_readdir + .open = ll_dir_open, + .release = ll_dir_release, + .read = generic_read_dir, + .readdir = ll_readdir, + .ioctl = ll_dir_ioctl }; +