X-Git-Url: https://git.whamcloud.com/?a=blobdiff_plain;f=lustre%2Fllite%2Ffile.c;h=41ff0b8e154dc9a2653f1246e06000d9f19838d7;hb=c0ab3403465d75c80c5486347741172dca9e0f2f;hp=9bcfcaab65dd7c56c9d6d85886db21c009d5d81b;hpb=4df2b143a386492f5478c432102fc5aee08f1849;p=fs%2Flustre-release.git diff --git a/lustre/llite/file.c b/lustre/llite/file.c index 9bcfcaa..41ff0b8 100644 --- a/lustre/llite/file.c +++ b/lustre/llite/file.c @@ -23,79 +23,99 @@ * (jj@sunsite.ms.mff.cuni.cz) */ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - #define DEBUG_SUBSYSTEM S_LLITE -#include +#include #include int ll_inode_setattr(struct inode *inode, struct iattr *attr, int do_trunc); extern int ll_setattr(struct dentry *de, struct iattr *attr); -extern inline struct obdo * ll_oa_from_inode(struct inode *inode, - unsigned long valid); static int ll_file_open(struct inode *inode, struct file *file) { - int rc; + int rc; struct ptlrpc_request *req = NULL; struct ll_file_data *fd; - struct obdo *oa; + struct obdo *oa = NULL; + struct lov_stripe_md *md = NULL; struct ll_sb_info *sbi = ll_i2sbi(inode); + struct ll_inode_info *lli = ll_i2info(inode); ENTRY; - if (file->private_data) + if (file->private_data) LBUG(); - fd = kmem_cache_alloc(ll_file_data_slab, SLAB_KERNEL); + /* delayed create of object (intent created inode) */ + /* XXX object needs to be cleaned up if mdc_open fails */ + /* XXX error handling appropriate here? */ + if (lli->lli_smd == NULL || lli->lli_smd->lmd_object_id == 0) { + struct client_obd *mdc = sbi2mdc(ll_s2sbi(inode->i_sb)); + struct inode * inode = file->f_dentry->d_inode; + + lli->lli_smd = NULL; + oa = obdo_alloc(); + if (!oa) { + RETURN(-ENOMEM); + } + oa->o_valid = OBD_MD_FLMODE; + oa->o_mode = S_IFREG | 0600; + oa->o_easize = mdc->cl_max_mdsize; + rc = obd_create(ll_i2obdconn(inode), oa, &lli->lli_smd); + if (rc) + RETURN(rc); + md = lli->lli_smd; + lli->lli_flags &= ~OBD_FL_CREATEONOPEN; + } + + fd = kmem_cache_alloc(ll_file_data_slab, SLAB_KERNEL); if (!fd) GOTO(out, rc = -ENOMEM); memset(fd, 0, sizeof(*fd)); - rc = mdc_open(&sbi->ll_mds_client, sbi->ll_mds_conn, inode->i_ino, - S_IFREG, file->f_flags, &fd->fd_mdshandle, &req); + rc = mdc_open(&sbi->ll_mdc_conn, inode->i_ino, S_IFREG | inode->i_mode, + file->f_flags, md, + (__u64)(unsigned long)file, &fd->fd_mdshandle, &req); + fd->fd_req = req; + ptlrpc_req_finished(req); + if (rc) + GOTO(out_req, -abs(rc)); + if (!fd->fd_mdshandle) { + CERROR("mdc_open didn't assign fd_mdshandle\n"); + /* XXX handle this how, abort or is it non-fatal? */ + } if (!fd->fd_mdshandle) CERROR("mdc_open didn't assign fd_mdshandle\n"); - ptlrpc_free_req(req); - if (rc) { - if (rc > 0) - rc = -rc; - GOTO(out, rc); + if (oa == NULL) { + oa = obdo_alloc(); + if (!oa) + GOTO(out_mdc, rc = -EINVAL); } - - oa = ll_oa_from_inode(inode, (OBD_MD_FLMODE | OBD_MD_FLID)); - if (oa == NULL) - LBUG(); - rc = obd_open(ll_i2obdconn(inode), oa); + oa->o_id = lli->lli_smd->lmd_object_id; + oa->o_mode = S_IFREG | inode->i_mode; + rc = obd_open(ll_i2obdconn(inode), oa, lli->lli_smd); obdo_free(oa); - if (rc) { - /* XXX: Need to do mdc_close here! */ - if (rc > 0) - rc = -rc; - GOTO(out, rc); - } + oa = NULL; + + if (rc) + GOTO(out_mdc, rc = -abs(rc)); file->private_data = fd; - EXIT; - out: - if (rc && fd) { - kmem_cache_free(ll_file_data_slab, fd); - file->private_data = NULL; - } + EXIT; + return 0; +out_mdc: + mdc_close(&sbi->ll_mdc_conn, inode->i_ino, + S_IFREG, fd->fd_mdshandle, &req); +out_req: + ptlrpc_free_req(req); +//out_fd: + if (oa) + obdo_free(oa); + kmem_cache_free(ll_file_data_slab, fd); + file->private_data = NULL; +out: return rc; } @@ -106,50 +126,58 @@ static int ll_file_release(struct inode *inode, struct file *file) struct ll_file_data *fd; struct obdo *oa; struct ll_sb_info *sbi = ll_i2sbi(inode); - struct iattr iattr; + struct ll_inode_info *lli = ll_i2info(inode); ENTRY; fd = (struct ll_file_data *)file->private_data; - if (!fd || !fd->fd_mdshandle) { + if (!fd || !fd->fd_mdshandle) { LBUG(); GOTO(out, rc = -EINVAL); } - oa = ll_oa_from_inode(inode, (OBD_MD_FLMODE | OBD_MD_FLID)); - if (oa == NULL) + oa = obdo_alloc(); + if (oa == NULL) { LBUG(); - rc = obd_close(ll_i2obdconn(inode), oa); - obdo_free(oa); - if (rc) { - if (rc > 0) - rc = -rc; - GOTO(out, rc); + GOTO(out_fd, rc = -ENOENT); } + rc = obd_close(ll_i2obdconn(inode), oa, lli->lli_smd); + obdo_free(oa); + if (rc) + GOTO(out_fd, abs(rc)); - iattr.ia_valid = ATTR_SIZE; - iattr.ia_size = inode->i_size; - rc = ll_inode_setattr(inode, &iattr, 0); - if (rc) { - CERROR("failed - %d.\n", rc); - rc = -EIO; + if (file->f_mode & FMODE_WRITE) { + struct iattr attr; + attr.ia_valid = ATTR_MTIME | ATTR_CTIME | ATTR_ATIME | ATTR_SIZE; + attr.ia_mtime = inode->i_mtime; + attr.ia_ctime = inode->i_ctime; + attr.ia_atime = inode->i_atime; + attr.ia_size = inode->i_size; + + /* XXX: this introduces a small race that we should evaluate */ + rc = ll_inode_setattr(inode, &attr, 0); + if (rc) { + CERROR("failed - %d.\n", rc); + rc = -EIO; /* XXX - GOTO(out)? -phil */ + } } - rc = mdc_close(&sbi->ll_mds_client, sbi->ll_mds_conn, inode->i_ino, + rc = mdc_close(&sbi->ll_mdc_conn, inode->i_ino, S_IFREG, fd->fd_mdshandle, &req); - ptlrpc_free_req(req); - if (rc) { - if (rc > 0) + ptlrpc_req_finished(req); + if (rc) { + if (rc > 0) rc = -rc; GOTO(out, rc); } - EXIT; + ptlrpc_free_req(fd->fd_req); - out: - if (!rc && fd) { - kmem_cache_free(ll_file_data_slab, fd); - file->private_data = NULL; - } + EXIT; + +out_fd: + kmem_cache_free(ll_file_data_slab, fd); + file->private_data = NULL; +out: return rc; } @@ -169,6 +197,98 @@ static inline void ll_remove_suid(struct inode *inode) } } +static void ll_update_atime(struct inode *inode) +{ + struct iattr attr; + + attr.ia_atime = CURRENT_TIME; + attr.ia_valid = ATTR_ATIME; + + if (inode->i_atime == attr.ia_atime) return; + if (IS_RDONLY(inode)) return; + if (IS_NOATIME(inode)) return; + + /* ll_inode_setattr() sets inode->i_atime from attr.ia_atime */ + ll_inode_setattr(inode, &attr, 0); +} + +static int ll_lock_callback(struct lustre_handle *lockh, + struct ldlm_lock_desc *new, + void *data, __u32 data_len, + struct ptlrpc_request **reqp) +{ + struct inode *inode = data; + ENTRY; + + if (new == NULL) { + /* Completion AST. Do nothing. */ + RETURN(0); + } + + if (data_len != sizeof(struct inode)) + LBUG(); + + /* FIXME: do something better than throwing away everything */ + if (inode == NULL) + LBUG(); + down(&inode->i_sem); + CDEBUG(D_INODE, "invalidating obdo/inode %ld\n", inode->i_ino); + invalidate_inode_pages(inode); + up(&inode->i_sem); + + if (ldlm_cli_cancel(lockh) < 0) + LBUG(); + RETURN(0); +} + +static ssize_t ll_file_read(struct file *filp, char *buf, size_t count, + loff_t *ppos) +{ + struct ll_file_data *fd = (struct ll_file_data *)filp->private_data; + struct inode *inode = filp->f_dentry->d_inode; + struct ll_sb_info *sbi = ll_i2sbi(inode); + struct ldlm_extent extent; + struct lustre_handle lockh; + __u64 res_id[RES_NAME_SIZE] = {inode->i_ino}; + int flags = 0; + ldlm_error_t err; + ssize_t retval; + ENTRY; + + if (!(fd->fd_flags & LL_FILE_IGNORE_LOCK)) { + extent.start = *ppos; + extent.end = *ppos + count; + CDEBUG(D_INFO, "Locking inode %ld, start %Lu end %Lu\n", + inode->i_ino, extent.start, extent.end); + + err = obd_enqueue(&sbi->ll_osc_conn, NULL, res_id, LDLM_EXTENT, + &extent, sizeof(extent), LCK_PR, &flags, + ll_lock_callback, inode, sizeof(*inode), + &lockh); + if (err != ELDLM_OK) { + CERROR("lock enqueue: err: %d\n", err); + RETURN(err); + } + ldlm_lock_dump((void *)(unsigned long)lockh.addr); + } + + CDEBUG(D_INFO, "Reading inode %ld, %d bytes, offset %Ld\n", + inode->i_ino, count, *ppos); + retval = generic_file_read(filp, buf, count, ppos); + + if (retval > 0) + ll_update_atime(inode); + + if (!(fd->fd_flags & LL_FILE_IGNORE_LOCK)) { + err = obd_cancel(&sbi->ll_osc_conn, LCK_PR, &lockh); + if (err != ELDLM_OK) { + CERROR("lock cancel: err: %d\n", err); + RETURN(err); + } + } + + RETURN(retval); +} /* * Write to a file (through the page cache). @@ -176,45 +296,110 @@ static inline void ll_remove_suid(struct inode *inode) static ssize_t ll_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { + struct ll_file_data *fd = (struct ll_file_data *)file->private_data; + struct inode *inode = file->f_dentry->d_inode; + struct ll_sb_info *sbi = ll_i2sbi(inode); + struct ldlm_extent extent; + struct lustre_handle lockh; + __u64 res_id[RES_NAME_SIZE] = {inode->i_ino}; + int flags = 0; + ldlm_error_t err; ssize_t retval; + ENTRY; + + if (!(fd->fd_flags & LL_FILE_IGNORE_LOCK)) { + /* FIXME: this should check whether O_APPEND is set and adjust + * extent.start accordingly */ + extent.start = *ppos; + extent.end = *ppos + count; + CDEBUG(D_INFO, "Locking inode %ld, start %Lu end %Lu\n", + inode->i_ino, extent.start, extent.end); + + err = obd_enqueue(&sbi->ll_osc_conn, NULL, res_id, LDLM_EXTENT, + &extent, sizeof(extent), LCK_PW, &flags, + ll_lock_callback, inode, sizeof(*inode), + &lockh); + if (err != ELDLM_OK) { + CERROR("lock enqueue: err: %d\n", err); + RETURN(err); + } + ldlm_lock_dump((void *)(unsigned long)lockh.addr); + } + CDEBUG(D_INFO, "Writing inode %ld, %ld bytes, offset %Ld\n", - file->f_dentry->d_inode->i_ino, (long)count, *ppos); + inode->i_ino, (long)count, *ppos); retval = generic_file_write(file, buf, count, ppos); - CDEBUG(D_INFO, "Wrote %ld\n", (long)retval); - /* update mtime/ctime/atime here, NOT size */ - if (retval > 0) { - struct iattr attr; - attr.ia_valid = ATTR_MTIME | ATTR_CTIME | ATTR_ATIME; - attr.ia_mtime = attr.ia_ctime = attr.ia_atime = - CURRENT_TIME; - ll_setattr(file->f_dentry, &attr); + if (!(fd->fd_flags & LL_FILE_IGNORE_LOCK)) { + err = obd_cancel(&sbi->ll_osc_conn, LCK_PW, &lockh); + if (err != ELDLM_OK) { + CERROR("lock cancel: err: %d\n", err); + RETURN(err); + } } - EXIT; - return retval; + + RETURN(retval); } +int ll_file_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct ll_file_data *fd = (struct ll_file_data *)file->private_data; + int flags; + + switch(cmd) { + case LL_IOC_GETFLAGS: + /* Get the current value of the file flags */ + return put_user(fd->fd_flags, (int *)arg); + case LL_IOC_SETFLAGS: + case LL_IOC_CLRFLAGS: + /* Set or clear specific file flags */ + /* XXX This probably needs checks to ensure the flags are + * not abused, and to handle any flag side effects. + */ + if (get_user(flags, (int *) arg)) + return -EFAULT; + + if (cmd == LL_IOC_SETFLAGS) + fd->fd_flags |= flags; + else + fd->fd_flags &= ~flags; + return 0; + + /* We need to special case any other ioctls we want to handle, + * to send them to the MDS/OST as appropriate and to properly + * network encode the arg field. + case EXT2_IOC_GETFLAGS: + case EXT2_IOC_SETFLAGS: + case EXT2_IOC_GETVERSION_OLD: + case EXT2_IOC_GETVERSION_NEW: + case EXT2_IOC_SETVERSION_OLD: + case EXT2_IOC_SETVERSION_NEW: + */ + default: + return -ENOTTY; + } +} /* XXX this does not need to do anything for data, it _does_ need to - call setattr */ + call setattr */ int ll_fsync(struct file *file, struct dentry *dentry, int data) { return 0; } struct file_operations ll_file_operations = { - read: generic_file_read, - write: ll_file_write, - open: ll_file_open, - release: ll_file_release, - mmap: generic_file_mmap, - fsync: NULL + read: ll_file_read, + write: ll_file_write, + ioctl: ll_file_ioctl, + open: ll_file_open, + release: ll_file_release, + mmap: generic_file_mmap, + fsync: NULL }; - struct inode_operations ll_file_inode_operations = { truncate: ll_truncate, setattr: ll_setattr }; -