📄 file.c
字号:
int ll_local_open(struct file *file, struct lookup_intent *it, struct ll_file_data *fd, struct obd_client_handle *och){ ENTRY; LASSERT(!LUSTRE_FPRIVATE(file)); LASSERT(fd != NULL); if (och) ll_och_fill(ll_i2info(file->f_dentry->d_inode), it, och); LUSTRE_FPRIVATE(file) = fd; ll_readahead_init(file->f_dentry->d_inode, &fd->fd_ras); fd->fd_omode = it->it_flags; RETURN(0);}/* Open a file, and (for the very first open) create objects on the OSTs at * this time. If opened with O_LOV_DELAY_CREATE, then we don't do the object * creation or open until ll_lov_setstripe() ioctl is called. We grab * lli_open_sem to ensure no other process will create objects, send the * stripe MD to the MDS, or try to destroy the objects if that fails. * * If we already have the stripe MD locally then we don't request it in * mdc_open(), by passing a lmm_size = 0. * * It is up to the application to ensure no other processes open this file * in the O_LOV_DELAY_CREATE case, or the default striping pattern will be * used. We might be able to avoid races of that sort by getting lli_open_sem * before returning in the O_LOV_DELAY_CREATE case and dropping it here * or in ll_file_release(), but I'm not sure that is desirable/necessary. */int ll_file_open(struct inode *inode, struct file *file){ struct ll_inode_info *lli = ll_i2info(inode); struct lookup_intent *it, oit = { .it_op = IT_OPEN, .it_flags = file->f_flags }; struct lov_stripe_md *lsm; struct ptlrpc_request *req = NULL; struct obd_client_handle **och_p; __u64 *och_usecount; struct ll_file_data *fd; int rc = 0, opendir_set = 0; ENTRY; CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p), flags %o\n", inode->i_ino, inode->i_generation, inode, file->f_flags);#ifdef HAVE_VFS_INTENT_PATCHES it = file->f_it;#else it = file->private_data; /* XXX: compat macro */ file->private_data = NULL; /* prevent ll_local_open assertion */#endif fd = ll_file_data_get(); if (fd == NULL) RETURN(-ENOMEM); if (S_ISDIR(inode->i_mode)) { spin_lock(&lli->lli_lock); /* * "lli->lli_opendir_pid != 0" means someone has set it. * "lli->lli_sai != NULL" means the previous statahead has not * been cleanup. */ if (lli->lli_opendir_pid == 0 && lli->lli_sai == NULL) { opendir_set = 1; lli->lli_opendir_pid = cfs_curproc_pid(); lli->lli_opendir_key = fd; } else if (unlikely(lli->lli_opendir_pid == cfs_curproc_pid())) { /* Two cases for this: * (1) The same process open such directory many times. * (2) The old process opened the directory, and exited * before its children processes. Then new process * with the same pid opens such directory before the * old process's children processes exit. * Change the owner to the latest one. */ opendir_set = 2; lli->lli_opendir_key = fd; } spin_unlock(&lli->lli_lock); } if (inode->i_sb->s_root == file->f_dentry) { LUSTRE_FPRIVATE(file) = fd; RETURN(0); } if (!it || !it->d.lustre.it_disposition) { /* Convert f_flags into access mode. We cannot use file->f_mode, * because everything but O_ACCMODE mask was stripped from it */ if ((oit.it_flags + 1) & O_ACCMODE) oit.it_flags++; if (file->f_flags & O_TRUNC) oit.it_flags |= FMODE_WRITE; /* kernel only call f_op->open in dentry_open. filp_open calls * dentry_open after call to open_namei that checks permissions. * Only nfsd_open call dentry_open directly without checking * permissions and because of that this code below is safe. */ if (oit.it_flags & FMODE_WRITE) oit.it_flags |= MDS_OPEN_OWNEROVERRIDE; /* We do not want O_EXCL here, presumably we opened the file * already? XXX - NFS implications? */ oit.it_flags &= ~O_EXCL; it = &oit; }restart: /* Let's see if we have file open on MDS already. */ if (it->it_flags & FMODE_WRITE) { och_p = &lli->lli_mds_write_och; och_usecount = &lli->lli_open_fd_write_count; } else if (it->it_flags & FMODE_EXEC) { och_p = &lli->lli_mds_exec_och; och_usecount = &lli->lli_open_fd_exec_count; } else { och_p = &lli->lli_mds_read_och; och_usecount = &lli->lli_open_fd_read_count; } LASSERTF(it->it_flags != 0, "it %p dist %d \n", it, it->d.lustre.it_disposition); down(&lli->lli_och_sem); if (*och_p) { /* Open handle is present */ if (it_disposition(it, DISP_OPEN_OPEN)) { /* Well, there's extra open request that we do not need, let's close it somehow. This will decref request. */ rc = it_open_error(DISP_OPEN_OPEN, it); if (rc) { up(&lli->lli_och_sem); ll_file_data_put(fd); GOTO(out_openerr, rc); } ll_release_openhandle(file->f_dentry, it); lprocfs_counter_incr(ll_i2sbi(inode)->ll_stats, LPROC_LL_OPEN); } (*och_usecount)++; rc = ll_local_open(file, it, fd, NULL); LASSERTF(rc == 0, "rc = %d\n", rc); } else { LASSERT(*och_usecount == 0); if (!it->d.lustre.it_disposition) { /* We cannot just request lock handle now, new ELC code means that one of other OPEN locks for this file could be cancelled, and since blocking ast handler would attempt to grab och_sem as well, that would result in a deadlock */ up(&lli->lli_och_sem); rc = ll_intent_file_open(file, NULL, 0, it); if (rc) { ll_file_data_put(fd); GOTO(out_openerr, rc); } mdc_set_lock_data(&it->d.lustre.it_lock_handle, file->f_dentry->d_inode); goto restart; } OBD_ALLOC(*och_p, sizeof (struct obd_client_handle)); if (!*och_p) { ll_file_data_put(fd); GOTO(out_och_free, rc = -ENOMEM); } (*och_usecount)++; req = it->d.lustre.it_data; /* mdc_intent_lock() didn't get a request ref if there was an * open error, so don't do cleanup on the request here * (bug 3430) */ /* XXX (green): Should not we bail out on any error here, not * just open error? */ rc = it_open_error(DISP_OPEN_OPEN, it); if (rc) { ll_file_data_put(fd); GOTO(out_och_free, rc); } ll_stats_ops_tally(ll_i2sbi(inode), LPROC_LL_OPEN, 1); rc = ll_local_open(file, it, fd, *och_p); LASSERTF(rc == 0, "rc = %d\n", rc); } up(&lli->lli_och_sem); /* Must do this outside lli_och_sem lock to prevent deadlock where different kind of OPEN lock for this same inode gets cancelled by ldlm_cancel_lru */ if (!S_ISREG(inode->i_mode)) GOTO(out, rc); lsm = lli->lli_smd; if (lsm == NULL) { if (file->f_flags & O_LOV_DELAY_CREATE || !(file->f_mode & FMODE_WRITE)) { CDEBUG(D_INODE, "object creation was delayed\n"); GOTO(out, rc); } } file->f_flags &= ~O_LOV_DELAY_CREATE; GOTO(out, rc); out: ptlrpc_req_finished(req); if (req) it_clear_disposition(it, DISP_ENQ_OPEN_REF); if (rc == 0) { ll_open_complete(inode); } else {out_och_free: if (*och_p) { OBD_FREE(*och_p, sizeof (struct obd_client_handle)); *och_p = NULL; /* OBD_FREE writes some magic there */ (*och_usecount)--; } up(&lli->lli_och_sem);out_openerr: if (opendir_set) { lli->lli_opendir_key = NULL; lli->lli_opendir_pid = 0; } else if (unlikely(opendir_set == 2)) { ll_stop_statahead(inode, fd); } } return rc;}/* Fills the obdo with the attributes for the inode defined by lsm */int ll_lsm_getattr(struct obd_export *exp, struct lov_stripe_md *lsm, struct obdo *oa){ struct ptlrpc_request_set *set; struct obd_info oinfo = { { { 0 } } }; int rc; ENTRY; LASSERT(lsm != NULL); memset(oa, 0, sizeof *oa); oinfo.oi_md = lsm; oinfo.oi_oa = oa; oa->o_id = lsm->lsm_object_id; oa->o_mode = S_IFREG; oa->o_valid = OBD_MD_FLID | OBD_MD_FLTYPE | OBD_MD_FLSIZE | OBD_MD_FLBLOCKS | OBD_MD_FLBLKSZ | OBD_MD_FLMTIME | OBD_MD_FLCTIME; set = ptlrpc_prep_set(); if (set == NULL) { rc = -ENOMEM; } else { rc = obd_getattr_async(exp, &oinfo, set); if (rc == 0) rc = ptlrpc_set_wait(set); ptlrpc_set_destroy(set); } if (rc) RETURN(rc); oa->o_valid &= (OBD_MD_FLBLOCKS | OBD_MD_FLBLKSZ | OBD_MD_FLMTIME | OBD_MD_FLCTIME | OBD_MD_FLSIZE); RETURN(0);}static inline void ll_remove_suid(struct inode *inode){ unsigned int mode; /* set S_IGID if S_IXGRP is set, and always set S_ISUID */ mode = (inode->i_mode & S_IXGRP)*(S_ISGID/S_IXGRP) | S_ISUID; /* was any of the uid bits set? */ mode &= inode->i_mode; if (mode && !capable(CAP_FSETID)) { inode->i_mode &= ~mode; // XXX careful here - we cannot change the size }}static int ll_lock_to_stripe_offset(struct inode *inode, struct ldlm_lock *lock){ struct ll_inode_info *lli = ll_i2info(inode); struct lov_stripe_md *lsm = lli->lli_smd; struct obd_export *exp = ll_i2obdexp(inode); struct { char name[16]; struct ldlm_lock *lock; struct lov_stripe_md *lsm; } key = { .name = "lock_to_stripe", .lock = lock, .lsm = lsm }; __u32 stripe, vallen = sizeof(stripe); int rc; ENTRY; if (lsm->lsm_stripe_count == 1) GOTO(check, stripe = 0); /* get our offset in the lov */ rc = obd_get_info(exp, sizeof(key), &key, &vallen, &stripe); if (rc != 0) { CERROR("obd_get_info: rc = %d\n", rc); RETURN(rc); } LASSERT(stripe < lsm->lsm_stripe_count);check: if (lsm->lsm_oinfo[stripe]->loi_id != lock->l_resource->lr_name.name[0]|| lsm->lsm_oinfo[stripe]->loi_gr != lock->l_resource->lr_name.name[1]){ LDLM_ERROR(lock, "resource doesn't match object "LPU64"/"LPU64, lsm->lsm_oinfo[stripe]->loi_id, lsm->lsm_oinfo[stripe]->loi_gr); RETURN(-ELDLM_NO_LOCK_DATA); } RETURN(stripe);}/* Get extra page reference to ensure it is not going away */void ll_pin_extent_cb(void *data){ struct page *page = data; page_cache_get(page); return;}/* Flush the page from page cache for an extent as its canceled. * Page to remove is delivered as @data. * * No one can dirty the extent until we've finished our work and they cannot * enqueue another lock. The DLM protects us from ll_file_read/write here, * but other kernel actors could have pages locked. * * If @discard is set, there is no need to write the page if it is dirty. * * Called with the DLM lock held. */int ll_page_removal_cb(void *data, int discard){ int rc; struct page *page = data; struct address_space *mapping; ENTRY; /* We have page reference already from ll_pin_page */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -