文件解锁

文件解锁是NFS操作的重要部分,确保资源的正常访问。客户端通过LOCKU请求解锁,服务器端的nfsd4_decode_locku()解析并处理请求,使用VFS层的vfs_lock_file()解锁文件。当所有锁解除后,客户端发送RELEASE_LOCKOWNER请求,服务器端的nfsd4_release_lockowner()释放stateid对应的资源。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

    文件解锁是加锁的反操作,当处理完毕后应该尽量赶快解锁,避免影响其他用户访问文件。NFS中与文件解锁相关的操作有两个:LOCKU和RELEASE_LOCKOWNER。LOCKU的作用是解锁,RELEASE_LOCKOWNER的作用是释放stateid。


LOCKU客户端程序

    客户端处理LOCKU请求的函数是nfs4_proc_unlck(),这个函数最终调用了nfs4_do_unlck(),这个函数负责创建一个RPC任务,根据文件锁的信息初始化RPC请求报文,然后向服务器发送请求,代码如下:

static struct rpc_task *nfs4_do_unlck(struct file_lock *fl,
                struct nfs_open_context *ctx,
                struct nfs4_lock_state *lsp,
                struct nfs_seqid *seqid)
{
        struct nfs4_unlockdata *data;
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_LOCKU],
                .rpc_cred = ctx->cred,
        };
        struct rpc_task_setup task_setup_data = {
                .rpc_client = NFS_CLIENT(lsp->ls_state->inode),
                .rpc_message = &msg,
                .callback_ops = &nfs4_locku_ops,
                .workqueue = nfsiod_workqueue,
                .flags = RPC_TASK_ASYNC,
        };

        /* Ensure this is an unlock - when canceling a lock, the
         * canceled lock is passed in, and it won't be an unlock.
         */
        fl->fl_type = F_UNLCK;          // 文件锁操作是F_UNLCK

        // 创建一个新的nfs4_unlockdata结构,初始化LOCKU请求的参数信息
        data = nfs4_alloc_unlockdata(fl, ctx, lsp, seqid);
        if (data == NULL) {
                nfs_free_seqid(seqid);
                return ERR_PTR(-ENOMEM);
        }

        nfs41_init_sequence(&data->arg.seq_args, &data->res.seq_res, 1);
        msg.rpc_argp = &data->arg;
        msg.rpc_resp = &data->res;
        task_setup_data.callback_data = data;
        return rpc_run_task(&task_setup_data);          // 创建一个RPC任务,发送RPC请求.
}


LOCKU服务器端处理程序

服务器接收到LOCKU请求后,先调用nfsd4_decode_locku()解析报文,解析出的数据保存在数据结构struct nfsd4_locku,这个结构的定义如下:

struct nfsd4_locku {
        u32             lu_type;        // 文件锁类型
        u32             lu_seqid;       // 文件锁seqid
        stateid_t       lu_stateid;     // 文件锁stateid
        u64             lu_offset;      // 文件锁在文件中的偏移
        u64             lu_length;      // 文件锁长度
};
然后服务器调用函数nfsd4_locku()处理请求,这个函数代码如下:

__be32
nfsd4_locku(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
            struct nfsd4_locku *locku)
{
        struct nfs4_ol_stateid *stp;
        struct file *filp = NULL;
        struct file_lock file_lock;
        __be32 status;
        int err;

        dprintk("NFSD: nfsd4_locku: start=%Ld length=%Ld\n",
                (long long) locku->lu_offset,           // 这是文件锁的起始位置
                (long long) locku->lu_length);          // 这是文件锁的长度

        // 检查文件锁的长度是否有效.
        if (check_lock_length(locku->lu_offset, locku->lu_length))
                 return nfserr_inval;

        nfs4_lock_state();

	// 这个函数在检查stateid,根据stateid查找nfs4_ol_stateid结构.
        status = nfs4_preprocess_seqid_op(cstate, locku->lu_seqid,
                                        &locku->lu_stateid, NFS4_LOCK_STID, &stp);
        if (status)
                goto out;	// 查找过程出错了.

	// 取出一个文件对象结构.
        filp = find_any_file(stp->st_file);
        if (!filp) {
                status = nfserr_lock_range;	// 没有找到文件对象结构.
                goto out;
        }
        BUG_ON(!filp);          // 这条语句在后来的代码中已经去掉了,重复检查了.

	// 初始化一个文件锁结构
        locks_init_lock(&file_lock);
        file_lock.fl_type = F_UNLCK;            // 这是删除文件锁操作.
        file_lock.fl_owner = (fl_owner_t)lockowner(stp->st_stateowner);
        file_lock.fl_pid = current->tgid;
        file_lock.fl_file = filp;
        file_lock.fl_flags = FL_POSIX;
        file_lock.fl_lmops = &nfsd_posix_mng_ops;
        file_lock.fl_start = locku->lu_offset;

        file_lock.fl_end = last_byte_offset(locku->lu_offset, locku->lu_length);
        nfs4_transform_lock_offset(&file_lock);

        /*
        *  Try to unlock the file in the VFS.
        */
        // 调用VFS层的函数删除文件锁
        err = vfs_lock_file(filp, F_SETLK, &file_lock, NULL);
        if (err) {
                dprintk("NFSD: nfs4_locku: vfs_lock_file failed!\n");
                goto out_nfserr;        // 删除文件锁过程出错了.
        }
        /*
        * OK, unlock succeeded; the only thing left to do is update the stateid.
        */
        // 更新stateid
        update_stateid(&stp->st_stid.sc_stateid);
        memcpy(&locku->lu_stateid, &stp->st_stid.sc_stateid, sizeof(stateid_t));

out:
        if (!cstate->replay_owner)
                nfs4_unlock_state();
        return status;

out_nfserr:
        status = nfserrno(err);
        goto out;
}

    这个函数思路很清楚,首先检查stateid是否有效,查找对应的nfs4_ol_stateid结构,然后创建了一个文件锁结构,调用VFS层的函数vfs_lock_file()解锁就可以了。


当所有的锁全部解除后,客户端会向服务器发起RELEASE_LOCKOWNER请求,删除stateid。

RELEASE_LOCKOWNER客户端处理程序

客户端的处理函数是nfs4_release_lockowner(),这个函数也比较简单,就是创建了一个RPC任务,然后按照RFC的规定设置了请求报文中的数据。

int nfs4_release_lockowner(struct nfs4_lock_state *lsp)
{
        struct nfs_server *server = lsp->ls_state->owner->so_server;
        struct nfs_release_lockowner_data *data;
        struct rpc_message msg = {
                .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_RELEASE_LOCKOWNER],
        };

        if (server->nfs_client->cl_mvops->minor_version != 0)
                return -EINVAL;
        data = kmalloc(sizeof(*data), GFP_NOFS);
        if (!data)
                return -ENOMEM;
        data->lsp = lsp;
        data->server = server;
        data->args.lock_owner.clientid = server->nfs_client->cl_clientid;
        data->args.lock_owner.id = lsp->ls_seqid.owner_id;
        data->args.lock_owner.s_dev = server->s_dev;
        msg.rpc_argp = &data->args;
        rpc_call_async(server->client, &msg, 0, &nfs4_release_lockowner_ops, data);
        return 0;
}

RELEASE_LOCKOWNER服务器端处理程序

服务器端的处理程序是nfsd4_release_lockowner(),这个函数根据owner查找对应的nfs4_lockowner结构,然后释放这个结构就可以了,代码如下:

__be32
nfsd4_release_lockowner(struct svc_rqst *rqstp,
                        struct nfsd4_compound_state *cstate,
                        struct nfsd4_release_lockowner *rlockowner)
{
        clientid_t *clid = &rlockowner->rl_clientid;    // 取出clientid.
        struct nfs4_stateowner *sop;
        struct nfs4_lockowner *lo;
        struct nfs4_ol_stateid *stp;
        struct xdr_netobj *owner = &rlockowner->rl_owner;
        struct list_head matches;
	// 这是clientid的hash值
        unsigned int hashval = ownerstr_hashval(clid->cl_id, owner);
        __be32 status;
        struct nfsd_net *nn = net_generic(&init_net, nfsd_net_id);

        dprintk("nfsd4_release_lockowner clientid: (%08x/%08x):\n",
                clid->cl_boot, clid->cl_id);

        /* XXX check for lease expiration */

        status = nfserr_stale_clientid;
        if (STALE_CLIENTID(clid, nn))
                return status;  // 客户端已经过期了,就不必处理了.

        nfs4_lock_state();
        status = nfserr_locks_held;
        INIT_LIST_HEAD(&matches);
        // 遍历链表中每个nfs4_stateowner结构,系统中所有的nfs4_stateowner保存在全局hash表ownerstr_hashtbl中了.
        list_for_each_entry(sop, &ownerstr_hashtbl[hashval], so_strhash) {
                if (sop->so_is_open_owner)      // 这是一个nfs4_openowner结构,检查下一个.
                        continue;
                if (!same_owner_str(sop, owner, clid))
                        continue;	// 名称不相同,这不是我们查找的nfs4_lockowner结构.
		// 遍历链表中每个nfs4_ol_stateid结构   目前情况下一个nfs4_lockowner结构中只包含一个nfs4_ol_stateid结构.
                list_for_each_entry(stp, &sop->so_stateids,
                                st_perstateowner) {
                        lo = lockowner(sop);            // 取出nfs4_lockowenr结构.
                        if (check_for_locks(stp->st_file, lo))
                                goto out;       // 如果还有文件锁没有释放,就不能处理了.
                        list_add(&lo->lo_list, &matches);
                }
        }
        /* Clients probably won't expect us to return with some (but not all)
         * of the lockowner state released; so don't release any until all
         * have been checked. */
        status = nfs_ok;
        while (!list_empty(&matches)) { // 处理每一个nfs4_lockowner结构.
                lo = list_entry(matches.next, struct nfs4_lockowner,
                                                                lo_list);
                /* unhash_stateowner deletes so_perclient only
                 * for openowners. */
                list_del(&lo->lo_list);
                release_lockowner(lo);  // 删除这个nfs4_lockowner结构.
        }
out:
        nfs4_unlock_state();
        return status;
}
    但是感觉这个函数有些乱。目前实现中,nfs4_lockowner中只能包含一个nfs4_ol_stateid,但是数据结构中使用了一个链表,为以后扩充做准备吗?如果nfs4_lockowner中包含了多个nfs4_ol_stateid,这个函数就可能出问题。现在没办法进行验证,先这样放着吧。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值