OPEN(一)

来源:互联网 发布:辐射4 ini优化 编辑:程序博客网 时间:2024/06/05 17:31

1.OPEN请求报文和应答报文中的数据

        OPEN操作比较复杂,涉及到很多种特殊情况。按照RFC3530的规定,OPEN请求报文中需要包含下列数据:

struct OPEN4args {        seqid4          seqid;          // 这是一个序号,保证请求能够序列化.        uint32_t        share_access;   // 这是用户请求的访问权限        uint32_t        share_deny;     // 一定不能有这些权限,Linux中固定设置为0.        open_owner4     owner;          // clientid + 这次OPEN操作的名称.        openflag4       openhow;        // 有两个取值:OPEN4_NOCREATE和OPEN4_CREATE        open_claim4     claim;          // 有四个取值:CLAIM_NULL、CLAIM_PREVIOUS、CLAIM_DELEGATE_CUR、CLAIM_DELEGATE_PREV};

        owner包含两个字段:clientid和这次操作的名称,  服务器端可以根据clientid和OPEN操作的名称查找是否已经保存了这次操作的信息。seqid是OPEN操作的序号,保证多个OPEN操作序列化执行。share_access是用户打开文件时请求的访问权限,share_deny是为Windows share reservation设置的字段,Linux系统中这个字段固定为0。openhow表示如果文件不存在是否创建一个新文件。claim表示OPEN类型,按照按照claim值不同,OPEN操作分为四种类型。这篇文>章中,我们只讲解最常见的一种情况:打开服务器端存在的一个文件。这种请求中claim的类型是CLAIM_NULL。这种情况下,open_claim4中还包含了文件的名>称,这是我们要打开的文件。

    按照RFC3530的规定,OPEN操作应答报文包含下列内容

struct OPEN4resok {        stateid4        stateid;        /* Stateid for open */        change_info4    cinfo;          /* Directory Change Info */        uint32_t        rflags;         /* Result flags */        bitmap4         attrset;        /* attributes on create */        open_delegation4 delegation;    /* Info on any open                                           delegation */}; 
        stateid固定长度为16字节,代表了这个打开的文件,后续发起READ、WRITE操作时需要将这个stateid包含在请求报文中,服务器根据stateid查找对应的>文件。cinfo包含了父目录的属性信息。rflags是一些标志位,目前定义了两个标志位:

   const OPEN4_RESULT_CONFIRM      = 0x00000002;    // 应答报文中的stateid不能马上使用,需要发起OPEN_CONFIRM请求。
   const OPEN4_RESULT_LOCKTYPE_POSIX = 0x00000004;  // 服务器支持POSIX文件锁

        如果OPEN请求报文中openhow字段的值为NFS4_CREATE,则服务器端可以创建一个新的文件,应答消息中的attrset就包含了新创建文件的属性信息。应答消息最后一个字段是delegation的信息,RFC3530定义了三种取值:

    OPEN_DELEGATE_NONE   // 没有使用delegation
    OPEN_DELEGATE_READ   // 读操作使用的delegation
    OPEN_DELEGATE_WRITE  // 写操作使用的delegation

        OPEN_DELEGATE_READ表示读操作中使用的delegation。如果文件以只读方式打开,则可以申请这种delegation。一个客户端的多个用户或者不同的客户端可以共享同一个OPEN_DELEGATE_READ,因为多个用户同时执行读操作不会造成冲突。当另外一个用户试图向文件中写入数据时服务器会回收OPEN_DELEGATE_READ。OPEN_DELEGATE_WRITE表示写操作中使用的delegation,OPEN_DELEGATE_WRITE只能被一个用户独占。当另一个用户向文件写入数据时服务器会回收OPEN_DELEGATE_WRITE。具体实现中,Linux没有实现OPEN_DELEGATE_WRITE。


2.客户端程序

        客户端设置OPEN请求报文中数据的函数是nfs4_opendata_alloc(),这个函数的代码如下:

参数dentry:这是要打开的文件在客户端的目录项结构

参数sp:这表示客户端的一个用户,就是这个用户要打开文件

参数fmode:这是文件的打开权限,读权限还是写权限

参数flags:这是打开文件时指定的一些标志位,如O_CREAT表示如何文件不存在就创建一个新文件

参数attrs:这是为新创建的文件设置的属性信息,如访问权限。

参数gfp_mask:这是分配内存时使用的标志位

static struct nfs4_opendata *nfs4_opendata_alloc(struct dentry *dentry,struct nfs4_state_owner *sp, fmode_t fmode, int flags,const struct iattr *attrs,gfp_t gfp_mask){struct dentry *parent = dget_parent(dentry);// 获取父目录的目录项结构struct inode *dir = parent->d_inode;// 这是父目录的索引节点struct nfs_server *server = NFS_SERVER(dir);// 文件系统结构struct nfs4_opendata *p;p = kzalloc(sizeof(*p), gfp_mask);// 分配内存if (p == NULL)goto err;// 分配内存失败// 这时分配了一个nfs_seqid结构,暂时没有链接到nfs_seqid_counter中p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid, gfp_mask);if (p->o_arg.seqid == NULL)// seqid分配失败.goto err_free;nfs_sb_active(dentry->d_sb);p->dentry = dget(dentry);// 这是要打开文件的目录项结构p->dir = parent;// 设置父目录的索引节点p->owner = sp;// nfs4_state_owner结构atomic_inc(&sp->so_count);// 增加这个结构的引用计数p->o_arg.fh = NFS_FH(dir);// 父目录的文件句柄p->o_arg.open_flags = flags;// 打开目标文件时设置的标志信息,如O_CREATp->o_arg.fmode = fmode & (FMODE_READ|FMODE_WRITE);// 文件的访问模式p->o_arg.clientid = server->nfs_client->cl_clientid;// 这表示一个NFS客户端// nfs_seqid_counter的创建时间p->o_arg.id.create_time = ktime_to_ns(sp->so_seqid.create_time);// 这是客户端为nfs4_state_owner结构设置的编号p->o_arg.id.uniquifier = sp->so_seqid.owner_id;p->o_arg.name = &dentry->d_name;// 目标文件的名称p->o_arg.server = server;// nfs_server结构p->o_arg.bitmask = server->attr_bitmask;// NFS服务器端文件系统支持的属性信息p->o_arg.open_bitmap = &nfs4_fattr_bitmap[0];// 需要查找的基本属性信息p->o_arg.claim = NFS4_OPEN_CLAIM_NULL;// 正常打开文件.// 这是为OPEN4_CREATE设置的信息if (attrs != NULL && attrs->ia_valid != 0) {__be32 verf[2];p->o_arg.u.attrs = &p->attrs;memcpy(&p->attrs, attrs, sizeof(p->attrs));verf[0] = jiffies;// 当前时间verf[1] = current->pid;// 进程的pidmemcpy(p->o_arg.u.verifier.data, verf,sizeof(p->o_arg.u.verifier.data));}p->c_arg.fh = &p->o_res.fh;p->c_arg.stateid = &p->o_res.stateid;p->c_arg.seqid = p->o_arg.seqid;nfs4_init_opendata_res(p);kref_init(&p->kref);return p;err_free:kfree(p);err:dput(parent);return NULL;}

        函数encode_open()根据nfs4_opendata_alloc()设置的信息封装OPEN请求报文。

static void encode_open(struct xdr_stream *xdr, const struct nfs_openargs *arg, struct compound_hdr *hdr){        encode_op_hdr(xdr, OP_OPEN, decode_open_maxsz, hdr);    // OPEN请求编号        encode_openhdr(xdr, arg);        encode_opentype(xdr, arg);     // openhow,取值为OPEN4_CREATE或者OPEN4_NOCREATE        switch (arg->claim) {             // claim  通常情况下取值是NFS4_OPEN_CLAIM_NULL        case NFS4_OPEN_CLAIM_NULL:                encode_claim_null(xdr, arg->name);                break;        case NFS4_OPEN_CLAIM_PREVIOUS:                encode_claim_previous(xdr, arg->u.delegation_type);                break;        case NFS4_OPEN_CLAIM_DELEGATE_CUR:                encode_claim_delegate_cur(xdr, arg->name, &arg->u.delegation);                break;        default:                BUG();        }}


static inline void encode_openhdr(struct xdr_stream *xdr, const struct nfs_openargs *arg){        __be32 *p; /* * opcode 4, seqid 4, share_access 4, share_deny 4, clientid 8, ownerlen 4, * owner 4 = 32 */        // 这是seqid        encode_nfs4_seqid(xdr, arg->seqid);     // arg->seqid->sequence->counter    seqid        // share_accessed  文件访问权限    只读 0x00000001   只写 0x00000002   读写 0x00000003        // share_deny = 0   always         encode_share_access(xdr, arg->fmode);   // 编码share_access和share_deny        p = reserve_space(xdr, 36);        p = xdr_encode_hyper(p, arg->clientid); // 编码clientid   8字节        *p++ = cpu_to_be32(24);         // owner 长度固定为24字节        p = xdr_encode_opaque_fixed(p, "open id:", 8);  // 8字节        *p++ = cpu_to_be32(arg->server->s_dev);         // 4字节        // 设备号        *p++ = cpu_to_be32(arg->id.uniquifier);         // nfs4_state_owner结构的编号  4字节        xdr_encode_hyper(p, arg->id.create_time);       // nfs4_state_owner结构的创建时间  8字节}
对照RFC3530的规定,请求报文中的owner字段由clientid和这次请求操作的名称两部分构成,名称字段长度固定为24字节,包含了字符串"open id:"(8字节)、NFS文件系统所在设备的设备号(4字节)、用户信息数据结构的编号(4字节)、用户信息结构的创建时间(8字节)。
原创粉丝点击