📄 file.c
字号:
/* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*- * vim:expandtab:shiftwidth=8:tabstop=8: * * Copyright (c) 2002, 2003 Cluster File Systems, Inc. * Author: Peter Braam <braam@clusterfs.com> * Author: Phil Schwan <phil@clusterfs.com> * Author: Andreas Dilger <adilger@clusterfs.com> * * This file is part of Lustre, http://www.lustre.org. * * Lustre is free software; you can redistribute it and/or * modify it under the terms of version 2 of the GNU General Public * License as published by the Free Software Foundation. * * Lustre is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Lustre; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#define DEBUG_SUBSYSTEM S_LLITE#include <lustre_dlm.h>#include <lustre_lite.h>#include <linux/pagemap.h>#include <linux/file.h>#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))#include <linux/lustre_compat25.h>#endif#include "llite_internal.h"/* also used by llite/special.c:ll_special_open() */struct ll_file_data *ll_file_data_get(void){ struct ll_file_data *fd; OBD_SLAB_ALLOC_PTR(fd, ll_file_data_slab); return fd;}static void ll_file_data_put(struct ll_file_data *fd){ if (fd != NULL) OBD_SLAB_FREE_PTR(fd, ll_file_data_slab);}static int ll_close_inode_openhandle(struct inode *inode, struct obd_client_handle *och){ struct ptlrpc_request *req = NULL; struct obd_device *obd; struct obdo *oa; int rc; ENTRY; obd = class_exp2obd(ll_i2mdcexp(inode)); if (obd == NULL) { CERROR("Invalid MDC connection handle "LPX64"\n", ll_i2mdcexp(inode)->exp_handle.h_cookie); GOTO(out, rc = 0); } /* * here we check if this is forced umount. If so this is called on * canceling "open lock" and we do not call mdc_close() in this case, as * it will not be successful, as import is already deactivated. */ if (obd->obd_force) GOTO(out, rc = 0); OBDO_ALLOC(oa); if (!oa) RETURN(-ENOMEM); // XXX We leak openhandle and request here. oa->o_id = inode->i_ino; oa->o_valid = OBD_MD_FLID; obdo_from_inode(oa, inode, OBD_MD_FLTYPE | OBD_MD_FLMODE | OBD_MD_FLSIZE | OBD_MD_FLBLOCKS | OBD_MD_FLATIME | OBD_MD_FLMTIME | OBD_MD_FLCTIME); if (ll_is_inode_dirty(inode)) { oa->o_flags = MDS_BFLAG_UNCOMMITTED_WRITES; oa->o_valid |= OBD_MD_FLFLAGS; } rc = mdc_close(ll_i2mdcexp(inode), oa, och, &req); if (rc == EAGAIN) { /* We are the last writer, so the MDS has instructed us to get * the file size and any write cookies, then close again. */ ll_queue_done_writing(inode); rc = 0; } else if (rc) { CERROR("inode %lu mdc close failed: rc = %d\n", inode->i_ino, rc); } OBDO_FREE(oa); if (rc == 0) { rc = ll_objects_destroy(req, inode); if (rc) CERROR("inode %lu ll_objects destroy: rc = %d\n", inode->i_ino, rc); } ptlrpc_req_finished(req); /* This is close request */ EXIT;out: mdc_clear_open_replay_data(och); return rc;}int ll_mdc_real_close(struct inode *inode, int flags){ struct ll_inode_info *lli = ll_i2info(inode); int rc = 0; struct obd_client_handle **och_p; struct obd_client_handle *och; __u64 *och_usecount; ENTRY; if (flags & FMODE_WRITE) { och_p = &lli->lli_mds_write_och; och_usecount = &lli->lli_open_fd_write_count; } else if (flags & FMODE_EXEC) { och_p = &lli->lli_mds_exec_och; och_usecount = &lli->lli_open_fd_exec_count; } else { LASSERT(flags & FMODE_READ); och_p = &lli->lli_mds_read_och; och_usecount = &lli->lli_open_fd_read_count; } down(&lli->lli_och_sem); if (*och_usecount) { /* There are still users of this handle, so skip freeing it. */ up(&lli->lli_och_sem); RETURN(0); } och=*och_p; *och_p = NULL; up(&lli->lli_och_sem); if (och) { /* There might be a race and somebody have freed this och already */ rc = ll_close_inode_openhandle(inode, och); och->och_fh.cookie = DEAD_HANDLE_MAGIC; OBD_FREE(och, sizeof *och); } RETURN(rc);}int ll_mdc_close(struct obd_export *mdc_exp, struct inode *inode, struct file *file){ struct ll_file_data *fd = LUSTRE_FPRIVATE(file); struct ll_inode_info *lli = ll_i2info(inode); int rc = 0; ENTRY; /* clear group lock, if present */ if (unlikely(fd->fd_flags & LL_FILE_GROUP_LOCKED)) { struct lov_stripe_md *lsm = ll_i2info(inode)->lli_smd; fd->fd_flags &= ~(LL_FILE_GROUP_LOCKED|LL_FILE_IGNORE_LOCK); rc = ll_extent_unlock(fd, inode, lsm, LCK_GROUP, &fd->fd_cwlockh); } /* Let's see if we have good enough OPEN lock on the file and if we can skip talking to MDS */ if (file->f_dentry->d_inode) { /* Can this ever be false? */ int lockmode; int flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_TEST_LOCK; struct lustre_handle lockh; struct inode *inode = file->f_dentry->d_inode; struct ldlm_res_id file_res_id = {.name={inode->i_ino, inode->i_generation}}; ldlm_policy_data_t policy = {.l_inodebits={MDS_INODELOCK_OPEN}}; down(&lli->lli_och_sem); if (fd->fd_omode & FMODE_WRITE) { lockmode = LCK_CW; LASSERT(lli->lli_open_fd_write_count); lli->lli_open_fd_write_count--; } else if (fd->fd_omode & FMODE_EXEC) { lockmode = LCK_PR; LASSERT(lli->lli_open_fd_exec_count); lli->lli_open_fd_exec_count--; } else { lockmode = LCK_CR; LASSERT(lli->lli_open_fd_read_count); lli->lli_open_fd_read_count--; } up(&lli->lli_och_sem); if (!ldlm_lock_match(mdc_exp->exp_obd->obd_namespace, flags, &file_res_id, LDLM_IBITS, &policy,lockmode, &lockh)) { rc = ll_mdc_real_close(file->f_dentry->d_inode, fd->fd_omode); } } else { CERROR("Releasing a file %p with negative dentry %p. Name %s", file, file->f_dentry, file->f_dentry->d_name.name); } LUSTRE_FPRIVATE(file) = NULL; ll_file_data_put(fd); RETURN(rc);}int lov_test_and_clear_async_rc(struct lov_stripe_md *lsm);/* While this returns an error code, fput() the caller does not, so we need * to make every effort to clean up all of our state here. Also, applications * rarely check close errors and even if an error is returned they will not * re-try the close call. */int ll_file_release(struct inode *inode, struct file *file){ struct ll_file_data *fd; struct ll_sb_info *sbi = ll_i2sbi(inode); struct ll_inode_info *lli = ll_i2info(inode); struct lov_stripe_md *lsm = lli->lli_smd; int rc; ENTRY; CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p)\n", inode->i_ino, inode->i_generation, inode); if (inode->i_sb->s_root != file->f_dentry) ll_stats_ops_tally(sbi, LPROC_LL_RELEASE, 1); fd = LUSTRE_FPRIVATE(file); LASSERT(fd != NULL); /* * The last ref on @file, maybe not the the owner pid of statahead. * Different processes can open the same dir, "ll_opendir_key" means: * it is me that should stop the statahead thread. */ if (lli->lli_opendir_key == fd) ll_stop_statahead(inode, fd); if (inode->i_sb->s_root == file->f_dentry) { LUSTRE_FPRIVATE(file) = NULL; ll_file_data_put(fd); RETURN(0); } if (lsm) lov_test_and_clear_async_rc(lsm); lli->lli_async_rc = 0; rc = ll_mdc_close(sbi->ll_mdc_exp, inode, file); RETURN(rc);}static int ll_intent_file_open(struct file *file, void *lmm, int lmmsize, struct lookup_intent *itp){ struct ll_sb_info *sbi = ll_i2sbi(file->f_dentry->d_inode); struct mdc_op_data data; struct dentry *parent = file->f_dentry->d_parent; const char *name = file->f_dentry->d_name.name; const int len = file->f_dentry->d_name.len; struct inode *inode = file->f_dentry->d_inode; struct ptlrpc_request *req; int rc; ENTRY; if (!parent) RETURN(-ENOENT); ll_prepare_mdc_op_data(&data, parent->d_inode, inode, name, len, O_RDWR, NULL); /* Usually we come here only for NFSD, and we want open lock. But we can also get here with pre 2.6.15 patchless kernels, and in that case that lock is also ok */ /* We can also get here if there was cached open handle in revalidate_it * but it disappeared while we were getting from there to ll_file_open. * But this means this file was closed and immediatelly opened which * makes a good candidate for using OPEN lock */ /* If lmmsize & lmm are not 0, we are just setting stripe info * parameters. No need for the open lock */ if (!lmm && !lmmsize) itp->it_flags |= MDS_OPEN_LOCK; rc = mdc_intent_lock(sbi->ll_mdc_exp, &data, lmm, lmmsize, itp, 0 /*unused */, &req, ll_mdc_blocking_ast, 0); if (rc == -ESTALE) { /* reason for keep own exit path - don`t flood log * with messages with -ESTALE errors. */ if (!it_disposition(itp, DISP_OPEN_OPEN) || it_open_error(DISP_OPEN_OPEN, itp)) GOTO(out, rc); ll_release_openhandle(file->f_dentry, itp); GOTO(out_stale, rc); } if (rc != 0 || it_open_error(DISP_OPEN_OPEN, itp)) { rc = rc ? rc : it_open_error(DISP_OPEN_OPEN, itp); CDEBUG(D_VFSTRACE, "lock enqueue: err: %d\n", rc); GOTO(out, rc); } if (itp->d.lustre.it_lock_mode) mdc_set_lock_data(&itp->d.lustre.it_lock_handle, inode); rc = ll_prep_inode(sbi->ll_osc_exp, &file->f_dentry->d_inode, req, DLM_REPLY_REC_OFF, NULL);out: ptlrpc_req_finished(itp->d.lustre.it_data);out_stale: it_clear_disposition(itp, DISP_ENQ_COMPLETE); ll_intent_drop_lock(itp); RETURN(rc);}static void ll_och_fill(struct ll_inode_info *lli, struct lookup_intent *it, struct obd_client_handle *och){ struct ptlrpc_request *req = it->d.lustre.it_data; struct mds_body *body; LASSERT(och); body = lustre_msg_buf(req->rq_repmsg, DLM_REPLY_REC_OFF, sizeof(*body)); LASSERT(body != NULL); /* reply already checked out */ /* and swabbed in mdc_enqueue */ LASSERT(lustre_rep_swabbed(req, DLM_REPLY_REC_OFF)); memcpy(&och->och_fh, &body->handle, sizeof(body->handle)); och->och_magic = OBD_CLIENT_HANDLE_MAGIC; lli->lli_io_epoch = body->io_epoch; mdc_set_open_replay_data(och, it->d.lustre.it_data);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -