filter.c

来自「lustre 1.6.5 source code」· C语言 代码 · 共 1,698 行 · 第 1/5 页

C
1,698
字号
{        struct lvfs_run_ctxt saved;        struct filter_obd *filter = &obd->u.filter;        struct file *file;        struct inode *inode;        int rc = 0;        ENTRY;        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);        file = filp_open(LAST_RCVD, O_RDWR | O_CREAT | O_LARGEFILE, 0700);        if (!file || IS_ERR(file)) {                rc = PTR_ERR(file);                CERROR("OBD filter: cannot open/create %s: rc = %d\n",                       LAST_RCVD, rc);                GOTO(out, rc);        }        filter->fo_rcvd_filp = file;        if (!S_ISREG(file->f_dentry->d_inode->i_mode)) {                CERROR("%s is not a regular file!: mode = %o\n", LAST_RCVD,                       file->f_dentry->d_inode->i_mode);                GOTO(err_filp, rc = -ENOENT);        }        inode = file->f_dentry->d_parent->d_inode;        /* We use i_op->unlink directly in filter_vfs_unlink() */        if (!inode->i_op || !inode->i_op->create || !inode->i_op->unlink) {                CERROR("%s: filesystem does not support create/unlink ops\n",                       obd->obd_name);                GOTO(err_filp, rc = -EOPNOTSUPP);        }        rc = filter_init_server_data(obd, file);        if (rc) {                CERROR("cannot read %s: rc = %d\n", LAST_RCVD, rc);                GOTO(err_filp, rc);        }        /* open and create health check io file*/        file = filp_open(HEALTH_CHECK, O_RDWR | O_CREAT, 0644);        if (IS_ERR(file)) {                rc = PTR_ERR(file);                CERROR("OBD filter: cannot open/create %s rc = %d\n",                       HEALTH_CHECK, rc);                GOTO(err_filp, rc);        }        filter->fo_health_check_filp = file;        if (!S_ISREG(file->f_dentry->d_inode->i_mode)) {                CERROR("%s is not a regular file!: mode = %o\n", HEALTH_CHECK,                       file->f_dentry->d_inode->i_mode);                GOTO(err_health_check, rc = -ENOENT);        }        rc = lvfs_check_io_health(obd, file);        if (rc)                GOTO(err_health_check, rc);        rc = filter_prep_groups(obd);        if (rc)                GOTO(err_server_data, rc); out:        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);        return(rc); err_server_data:        //class_disconnect_exports(obd, 0);        filter_free_server_data(filter); err_health_check:        if (filp_close(filter->fo_health_check_filp, 0))                CERROR("can't close %s after error\n", HEALTH_CHECK);        filter->fo_health_check_filp = NULL; err_filp:        if (filp_close(filter->fo_rcvd_filp, 0))                CERROR("can't close %s after error\n", LAST_RCVD);        filter->fo_rcvd_filp = NULL;        goto out;}/* cleanup the filter: write last used object id to status file */static void filter_post(struct obd_device *obd){        struct lvfs_run_ctxt saved;        struct filter_obd *filter = &obd->u.filter;        int rc, i;        /* XXX: filter_update_lastobjid used to call fsync_dev.  It might be         * best to start a transaction with h_sync, because we removed this         * from lastobjid */        push_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);        rc = filter_update_server_data(obd, filter->fo_rcvd_filp,                                       filter->fo_fsd, 0);        if (rc)                CERROR("error writing server data: rc = %d\n", rc);        for (i = 0; i < FILTER_GROUPS; i++) {                rc = filter_update_last_objid(obd, i, (i == FILTER_GROUPS - 1));                if (rc)                        CERROR("error writing group %d lastobjid: rc = %d\n",                               i, rc);        }        rc = filp_close(filter->fo_rcvd_filp, 0);        filter->fo_rcvd_filp = NULL;        if (rc)                CERROR("error closing %s: rc = %d\n", LAST_RCVD, rc);        rc = filp_close(filter->fo_health_check_filp, 0);        filter->fo_health_check_filp = NULL;        if (rc)                CERROR("error closing %s: rc = %d\n", HEALTH_CHECK, rc);        filter_cleanup_groups(obd);        filter_free_server_data(filter);        pop_ctxt(&saved, &obd->obd_lvfs_ctxt, NULL);}static void filter_set_last_id(struct filter_obd *filter,                               obd_id id, obd_gr group){        LASSERT(filter->fo_fsd != NULL);        LASSERT(group <= FILTER_GROUPS);        spin_lock(&filter->fo_objidlock);        filter->fo_last_objids[group] = id;        spin_unlock(&filter->fo_objidlock);}obd_id filter_last_id(struct filter_obd *filter, obd_gr group){        obd_id id;        LASSERT(filter->fo_fsd != NULL);        LASSERT(group <= FILTER_GROUPS);        /* FIXME: object groups */        spin_lock(&filter->fo_objidlock);        id = filter->fo_last_objids[group];        spin_unlock(&filter->fo_objidlock);        return id;}static int filter_lock_dentry(struct obd_device *obd, struct dentry *dparent){        LOCK_INODE_MUTEX(dparent->d_inode);        return 0;}/* We never dget the object parent, so DON'T dput it either */struct dentry *filter_parent(struct obd_device *obd, obd_gr group, obd_id objid){        struct filter_obd *filter = &obd->u.filter;        LASSERT(group < FILTER_GROUPS); /* FIXME: object groups */        if (group > 0 || filter->fo_subdir_count == 0)                return filter->fo_dentry_O_groups[group];        return filter->fo_dentry_O_sub[objid & (filter->fo_subdir_count - 1)];}/* We never dget the object parent, so DON'T dput it either */struct dentry *filter_parent_lock(struct obd_device *obd, obd_gr group,                                  obd_id objid){        unsigned long now = jiffies;        struct dentry *dparent = filter_parent(obd, group, objid);        int rc;        if (IS_ERR(dparent))                return dparent;        rc = filter_lock_dentry(obd, dparent);        fsfilt_check_slow(obd, now, "parent lock");        return rc ? ERR_PTR(rc) : dparent;}/* We never dget the object parent, so DON'T dput it either */static void filter_parent_unlock(struct dentry *dparent){        UNLOCK_INODE_MUTEX(dparent->d_inode);}/* How to get files, dentries, inodes from object id's. * * If dir_dentry is passed, the caller has already locked the parent * appropriately for this operation (normally a write lock).  If * dir_dentry is NULL, we do a read lock while we do the lookup to * avoid races with create/destroy and such changing the directory * internal to the filesystem code. */struct dentry *filter_fid2dentry(struct obd_device *obd,                                 struct dentry *dir_dentry,                                 obd_gr group, obd_id id){        struct dentry *dparent = dir_dentry;        struct dentry *dchild;        char name[32];        int len;        ENTRY;        if (OBD_FAIL_CHECK(OBD_FAIL_OST_ENOENT) &&            !obd->u.filter.fo_destroy_in_progress) {                /* don't fail lookups for orphan recovery, it causes                 * later LBUGs when objects still exist during precreate */                CDEBUG(D_INFO, "*** obd_fail_loc=%x ***\n",OBD_FAIL_OST_ENOENT);                RETURN(ERR_PTR(-ENOENT));        }        if (id == 0) {                CERROR("fatal: invalid object id 0\n");                RETURN(ERR_PTR(-ESTALE));        }        len = sprintf(name, LPU64, id);        if (dir_dentry == NULL) {                dparent = filter_parent_lock(obd, group, id);                if (IS_ERR(dparent)) {                        CERROR("%s: error getting object "LPU64":"LPU64                               " parent: rc %ld\n", obd->obd_name,                               id, group, PTR_ERR(dparent));                        RETURN(dparent);                }        }        CDEBUG(D_INODE, "looking up object O/%.*s/%s\n",               dparent->d_name.len, dparent->d_name.name, name);        dchild = /*ll_*/lookup_one_len(name, dparent, len);        if (dir_dentry == NULL)                filter_parent_unlock(dparent);        if (IS_ERR(dchild)) {                CERROR("%s: child lookup error %ld\n", obd->obd_name,                       PTR_ERR(dchild));                RETURN(dchild);        }        if (dchild->d_inode != NULL && is_bad_inode(dchild->d_inode)) {                CERROR("%s: got bad object "LPU64" inode %lu\n",                       obd->obd_name, id, dchild->d_inode->i_ino);                f_dput(dchild);                RETURN(ERR_PTR(-ENOENT));        }        CDEBUG(D_INODE, "got child objid %s: %p, count = %d\n",               name, dchild, atomic_read(&dchild->d_count));        LASSERT(atomic_read(&dchild->d_count) > 0);        RETURN(dchild);}static int filter_prepare_destroy(struct obd_device *obd, obd_id objid){        struct lustre_handle lockh;        int flags = LDLM_AST_DISCARD_DATA, rc;        struct ldlm_res_id res_id = { .name = { objid } };        ldlm_policy_data_t policy = { .l_extent = { 0, OBD_OBJECT_EOF } };        ENTRY;        /* Tell the clients that the object is gone now and that they should         * throw away any cached pages. */        rc = ldlm_cli_enqueue_local(obd->obd_namespace, &res_id, LDLM_EXTENT,                                    &policy, LCK_PW, &flags, ldlm_blocking_ast,                                    ldlm_completion_ast, NULL, NULL, 0, NULL,                                    &lockh);        /* We only care about the side-effects, just drop the lock. */        if (rc == ELDLM_OK)                ldlm_lock_decref(&lockh, LCK_PW);        RETURN(rc);}/* This is vfs_unlink() without down(i_sem).  If we call regular vfs_unlink() * we have 2.6 lock ordering issues with filter_commitrw_write() as it takes * i_sem before starting a handle, while filter_destroy() + vfs_unlink do the * reverse.  Caller must take i_sem before starting the transaction and we * drop it here before the inode is removed from the dentry.  bug 4180/6984 */int filter_vfs_unlink(struct inode *dir, struct dentry *dentry){        int rc;        ENTRY;        /* don't need dir->i_zombie for 2.4, it is for rename/unlink of dir         * itself we already hold dir->i_mutex for child create/unlink ops */        LASSERT(dentry->d_inode != NULL);        LASSERT(TRYLOCK_INODE_MUTEX(dir) == 0);        LASSERT(TRYLOCK_INODE_MUTEX(dentry->d_inode) == 0);        /* may_delete() */        if (/*!dentry->d_inode ||*/dentry->d_parent->d_inode != dir)                GOTO(out, rc = -ENOENT);        rc = ll_permission(dir, MAY_WRITE | MAY_EXEC, NULL);        if (rc)                GOTO(out, rc);        if (IS_APPEND(dir))                GOTO(out, rc = -EPERM);        /* check_sticky() */        if ((dentry->d_inode->i_uid != current->fsuid && !capable(CAP_FOWNER))||            IS_APPEND(dentry->d_inode) || IS_IMMUTABLE(dentry->d_inode))                GOTO(out, rc = -EPERM);        /* NOTE: This might need to go outside i_mutex, though it isn't clear if         *       that was done because of journal_start (which is already done         *       here) or some other ordering issue. */        DQUOT_INIT(dir);#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,5,0))        rc = security_inode_unlink(dir, dentry);        if (rc)                GOTO(out, rc);#endif        rc = dir->i_op->unlink(dir, dentry);out:        /* need to drop i_mutex before we lose inode reference */        UNLOCK_INODE_MUTEX(dentry->d_inode);        if (rc == 0)                d_delete(dentry);        RETURN(rc);}/* Caller must hold LCK_PW on parent and push us into kernel context. * Caller must hold child i_mutex, we drop it always. * Caller is also required to ensure that dchild->d_inode exists. */static int filter_destroy_internal(struct obd_device *obd, obd_id objid,                                   obd_gr group, struct dentry *dparent,                                   struct dentry *dchild){        struct inode *inode = dchild->d_inode;        int rc;        if (inode->i_nlink != 1 || atomic_read(&inode->i_count) != 1) {                CERROR("destroying objid %.*s ino %lu nlink %lu count %d\n",                       dchild->d_name.len, dchild->d_name.name, inode->i_ino,                       (unsigned long)inode->i_nlink,                       atomic_read(&inode->i_count));        }        rc = filter_vfs_unlink(dparent->d_inode, dchild);

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?