Skip to contentSkip to conversation

prep for flex file layout server

PATCH Superseded Weston Andros Adamson 3 participants 31 messages Jun 4, 2014 – Jun 5, 2014 1 message not in the archive

Subsystems (2)

v1 of 2 Superseded Latest is v2 →

lore
Share & tools
lore
#0 lore raw

cover prep for flex file layout server

These patches are in preparation for the pynfs implementation of a flex file layout server.

I already have patches for a working flex file server, but I figure those should wait until the spec is complete ;)

I pushed these patches to my linux-nfs.org tree on branch 'ff_prep':

git://git.linux-nfs.org/projects/dros/pynfs.git

The prep includes:

- patches that enable pynfs mds using real v4.1 DSes (on the backend, not usable from clients as there is no stateid sharing between mds and ds)

- fix several bugs in pnfs path

- move .x files to subdir 'xdrdef' - the nfs4.1 directory was getting crowded and we're going to add several more .x files along with all of the autogenerated files. Note this change touches server tests too.

- clean up the nfs4server's output - no longer print out EVERY part of EVERY operation which was very efficient at hiding tracebacks and made pynfs even slower. Old functionality is now switched on with -v flag. Also added an in-between mode "-s" that prints a summary of whats going on.

- support for NFSv3 backend communication - this is not actually used yet, but can be tested with file layout by always returning NFS4ERR_LAYOUTUNAVAILABLE in layoutget and using DataServer3 class instead of DataServer41

Weston Andros Adamson (17):
4.1 client: reclaim_complete after create_session 4.1 server: service RECLAIM_COMPLETE operations
dataserver: only catch connection error 4.1 server: avoid traceback in DS disconnect() move .x files to subdir 'xdrdef'
4.1 client: remove unused imports
4.1 server: add -v flag & silence random output 4.1 server: add -s option to print summary of ops
dataserver: make generic interface to ops
dataserver: don't import * from nfs4 specific mods 4.1 server: move nfs4_ops.py to nfs_ops.py add mntv3, portmapv2 and nfsv3 .x files
dataserver: separate generic and 4.1 code 4.1 server: add support for NFSv3 data servers 4.1 server: get rid of old op_getdeviceinfo
rpc: on socket error, close and mark pipe inactive
nfs3clnt: reconnect when sending on inactive pipe

 nfs4.1/block.py                             |    8 +-
 nfs4.1/client41tests/environment.py         |    4 +-
 nfs4.1/config.py                            |    8 +-
 nfs4.1/dataserver.py                        |  306 ++-
 nfs4.1/fs.py                                |   38 +-
 nfs4.1/nfs3client.py                        |  185 ++
 nfs4.1/nfs4.x                               | 3290 ---------------------------
 nfs4.1/nfs4.x.diff                          |   48 -
 nfs4.1/nfs4_ops.py                          |   61 -
 nfs4.1/nfs4client.py                        |   48 +-
 nfs4.1/nfs4commoncode.py                    |   10 +-
 nfs4.1/nfs4lib.py                           |   62 +-
 nfs4.1/nfs4server.py                        |  166 +-
 nfs4.1/nfs4state.py                         |   15 +-
 nfs4.1/nfs_ops.py                           |   89 +
 nfs4.1/pnfs_block.x                         |  149 --
 nfs4.1/sctrl.x                              |  145 --
 nfs4.1/server41tests/environment.py         |    4 +-
 nfs4.1/server41tests/st_block.py            |    4 +-
 nfs4.1/server41tests/st_compound.py         |    4 +-
 nfs4.1/server41tests/st_create_session.py   |    4 +-
 nfs4.1/server41tests/st_current_stateid.py  |    8 +-
 nfs4.1/server41tests/st_debug.py            |    4 +-
 nfs4.1/server41tests/st_delegation.py       |    4 +-
 nfs4.1/server41tests/st_destroy_clientid.py |    2 +-
 nfs4.1/server41tests/st_destroy_session.py  |    4 +-
 nfs4.1/server41tests/st_exchange_id.py      |    4 +-
 nfs4.1/server41tests/st_getdevicelist.py    |    4 +-
 nfs4.1/server41tests/st_lookup.py           |    2 +-
 nfs4.1/server41tests/st_lookupp.py          |    2 +-
 nfs4.1/server41tests/st_open.py             |    8 +-
 nfs4.1/server41tests/st_putfh.py            |    2 +-
 nfs4.1/server41tests/st_reboot.py           |    4 +-
 nfs4.1/server41tests/st_reclaim_complete.py |    2 +-
 nfs4.1/server41tests/st_rename.py           |    4 +-
 nfs4.1/server41tests/st_secinfo.py          |    4 +-
 nfs4.1/server41tests/st_secinfo_no_name.py  |    4 +-
 nfs4.1/server41tests/st_sequence.py         |    4 +-
 nfs4.1/server41tests/st_trunking.py         |    4 +-
 nfs4.1/server41tests/st_verify.py           |    2 +-
 nfs4.1/server_exports.py                    |    7 +-
 nfs4.1/setup.py                             |   33 +-
 nfs4.1/testclient.py                        |    2 +-
 nfs4.1/testserver.py                        |    2 +-
 nfs4.1/xdrdef/__init__.py                   |    0
 nfs4.1/xdrdef/mnt3.x                        |   68 +
 nfs4.1/xdrdef/nfs3.x                        |  818 +++++++
 nfs4.1/xdrdef/nfs4.x                        | 3290 +++++++++++++++++++++++++++
 nfs4.1/xdrdef/nfs4.x.diff                   |   48 +
 nfs4.1/xdrdef/pnfs_block.x                  |  149 ++
 nfs4.1/xdrdef/portmap.x                     |   51 +
 nfs4.1/xdrdef/sctrl.x                       |  145 ++
 rpc/rpc.py                                  |   26 +-
 53 files changed, 5337 insertions(+), 4022 deletions(-)
 create mode 100644 nfs4.1/nfs3client.py
 delete mode 100644 nfs4.1/nfs4.x
 delete mode 100644 nfs4.1/nfs4.x.diff
 delete mode 100644 nfs4.1/nfs4_ops.py
 create mode 100644 nfs4.1/nfs_ops.py
 delete mode 100644 nfs4.1/pnfs_block.x
 delete mode 100644 nfs4.1/sctrl.x
 create mode 100644 nfs4.1/xdrdef/__init__.py
 create mode 100644 nfs4.1/xdrdef/mnt3.x
 create mode 100644 nfs4.1/xdrdef/nfs3.x
 create mode 100644 nfs4.1/xdrdef/nfs4.x
 create mode 100644 nfs4.1/xdrdef/nfs4.x.diff
 create mode 100644 nfs4.1/xdrdef/pnfs_block.x
 create mode 100644 nfs4.1/xdrdef/portmap.x
 create mode 100644 nfs4.1/xdrdef/sctrl.x
Signature · 1 line
1.8.5.2 (Apple Git-48)
#1 lore raw

PATCH 1/17 4.1 client: reclaim_complete after create_session

Send RECLAIM_COMPLETE after CREATE_SESSION. This enables backend communication to v4.1 linux nfsd servers (i/o through MDS only).

---
 nfs4.1/nfs4client.py | 1 +
 1 file changed, 1 insertion(+)
nfs4.1/nfs4client.py +1 -0
index e750728..0d94a42 100644
@@ -367,6 +367,7 @@ class ClientRecord(object):
         self.seqid = inc_u32(csr.csr_sequence) # XXX Do we need to check this?
         sess = SessionRecord(csr, self)
         self.c.sessions[sess.sessionid] = sess
+        sess.compound([op.reclaim_complete(FALSE)])
         return sess
 
     def _cb_hook(self, prefix, opname, funct):
Signature · 1 line
1.8.5.2 (Apple Git-48)
#2 lore raw

Re: [PATCH pynfs 01/17] 4.1 client: reclaim_complete after create_session

Quoted 2 lines · Weston Andros Adamson

Send RECLAIM_COMPLETE after CREATE_SESSION. This enables backend communication to v4.1 linux nfsd servers (i/o through MDS only).

If that's unconditionally adding a reclaim_complete after every create_sesion, that's probably not what we want since there are tests that want to do the reclaim_complete by hand. You probably want to use new_client_session() instead? See 219cf7b7f7d0 and the preceding commit.

--b.

Quoted 21 lines
---
 nfs4.1/nfs4client.py | 1 +
 1 file changed, 1 insertion(+)
nfs4.1/nfs4client.py +1 -0
index e750728..0d94a42 100644
@@ -367,6 +367,7 @@ class ClientRecord(object):
         self.seqid = inc_u32(csr.csr_sequence) # XXX Do we need to check this?
         sess = SessionRecord(csr, self)
         self.c.sessions[sess.sessionid] = sess
+        sess.compound([op.reclaim_complete(FALSE)])
         return sess
 
     def _cb_hook(self, prefix, opname, funct):
Signature · 1 line
1.8.5.2 (Apple Git-48)
#3 lore raw

Re: [PATCH pynfs 01/17] 4.1 client: reclaim_complete after create_session

Quoted 11 lines · J. Bruce Fields
Quoted 2 lines · Weston Andros Adamson

Send RECLAIM_COMPLETE after CREATE_SESSION. This enables backend communication to v4.1 linux nfsd servers (i/o through MDS only).

If that's unconditionally adding a reclaim_complete after every create_sesion, that's probably not what we want since there are tests that want to do the reclaim_complete by hand. You probably want to use new_client_session() instead? See 219cf7b7f7d0 and the preceding commit.

—b.

Ok, thats a good point, but AFAIC new_client_session is never called - at least by nfs4server.

I’ll figure out a better way to do this.

-dros

Quoted 22 lines
Quoted 22 lines

---
nfs4.1/nfs4client.py | 1 +

1 file changed, 1 insertion(+)
nfs4.1/nfs4client.py +1 -0
index e750728..0d94a42 100644
@@ -367,6 +367,7 @@ class ClientRecord(object):
        self.seqid = inc_u32(csr.csr_sequence) # XXX Do we need to check this?
        sess = SessionRecord(csr, self)
        self.c.sessions[sess.sessionid] = sess
+        sess.compound([op.reclaim_complete(FALSE)])
        return sess
 
    def _cb_hook(self, prefix, opname, funct):
Signature · 1 line
1.8.5.2 (Apple Git-48)
#4 lore raw

PATCH 2/17 4.1 server: service RECLAIM_COMPLETE operations

In reply to Weston Andros Adamson

Just return ok!

---
 nfs4.1/nfs4server.py | 3 +++
 1 file changed, 3 insertions(+)
nfs4.1/nfs4server.py +3 -0
index 65fb9af..3607dc0 100755
@@ -1809,6 +1809,9 @@ class NFS4Server(rpc.Server):
         with find_state(env, arg.deleg_stateid, allow_0=False) as state:
             state.delegreturn()
         return encode_status(NFS4_OK)
+
+    def op_reclaim_complete(self, arg, env):
+        return encode_status(NFS4_OK)
     
     def op_getdevicelist(self, arg, env): # STUB
         check_session(env)
Signature · 1 line
1.8.5.2 (Apple Git-48)
#5 lore raw

Re: [PATCH pynfs 02/17] 4.1 server: service RECLAIM_COMPLETE operations

Quoted 1 line · Weston Andros Adamson

Just return ok!

Technically it should record whether or not the reclaim_complete has happened and return a GRACE error on any non-reclaim open performed before the reclaim_complete--but for your purposes you may not care...

--b.

Quoted 23 lines
---
 nfs4.1/nfs4server.py | 3 +++
 1 file changed, 3 insertions(+)
nfs4.1/nfs4server.py +3 -0
index 65fb9af..3607dc0 100755
@@ -1809,6 +1809,9 @@ class NFS4Server(rpc.Server):
         with find_state(env, arg.deleg_stateid, allow_0=False) as state:
             state.delegreturn()
         return encode_status(NFS4_OK)
+
+    def op_reclaim_complete(self, arg, env):
+        return encode_status(NFS4_OK)
 
     def op_getdevicelist(self, arg, env): # STUB
         check_session(env)
Signature · 1 line
1.8.5.2 (Apple Git-48)
#6 lore raw

Re: [PATCH pynfs 02/17] 4.1 server: service RECLAIM_COMPLETE operations

Quoted 7 lines · J. Bruce Fields
Quoted 1 line · Weston Andros Adamson

Just return ok!

Technically it should record whether or not the reclaim_complete has happened and return a GRACE error on any non-reclaim open performed before the reclaim_complete--but for your purposes you may not care...

...and a NOGRACE error on any reclaim opens performed by that client after the reclaim_complete?

Quoted 29 lines

--b.

Quoted 21 lines
---
 nfs4.1/nfs4server.py | 3 +++
 1 file changed, 3 insertions(+)
nfs4.1/nfs4server.py +3 -1
index 65fb9af..3607dc0 100755
@@ -1809,6 +1809,9 @@ class NFS4Server(rpc.Server):
         with find_state(env, arg.deleg_stateid, allow_0=False) as state:
             state.delegreturn()
         return encode_status(NFS4_OK)
+
+    def op_reclaim_complete(self, arg, env):
+        return encode_status(NFS4_OK)
 
     def op_getdevicelist(self, arg, env): # STUB
         check_session(env)
--
Quoted 2 lines

1.8.5.2 (Apple Git-48)

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#7 lore raw

Re: [PATCH pynfs 02/17] 4.1 server: service RECLAIM_COMPLETE operations

Are you saying that the pynfs server supports state recovery? This has not been my experience. I’ll double check.

-dros

Quoted 41 lines · Trond Myklebust
Quoted 7 lines · J. Bruce Fields
Quoted 1 line · Weston Andros Adamson

Just return ok!

Technically it should record whether or not the reclaim_complete has happened and return a GRACE error on any non-reclaim open performed before the reclaim_complete--but for your purposes you may not care...

...and a NOGRACE error on any reclaim opens performed by that client after the reclaim_complete?

Quoted 29 lines

--b.

Quoted 21 lines

---
nfs4.1/nfs4server.py | 3 +++

1 file changed, 3 insertions(+)
nfs4.1/nfs4server.py +3 -1
index 65fb9af..3607dc0 100755
@@ -1809,6 +1809,9 @@ class NFS4Server(rpc.Server):
        with find_state(env, arg.deleg_stateid, allow_0=False) as state:
            state.delegreturn()
        return encode_status(NFS4_OK)
+
+    def op_reclaim_complete(self, arg, env):
+        return encode_status(NFS4_OK)
 
    def op_getdevicelist(self, arg, env): # STUB
        check_session(env)
--
Quoted 2 lines

1.8.5.2 (Apple Git-48)

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#8 lore raw

Re: [PATCH pynfs 02/17] 4.1 server: service RECLAIM_COMPLETE operations

Quoted 2 lines · Weston Andros Adamson

Are you saying that the pynfs server supports state recovery? This has not been my experience. I’ll double check.

If you don't support state recovery, then I think the minimal correct behavior would be to have no grace period at all: return NO_GRACE on *every* reclaim operation and GRACE only on non-reclaims not preceded by a global (one_fs == FALSE) RECLAIM_COMPLETE for that client.

All this does is catch misbehaving clients, and maybe that's not a priority. But it's easy enough to implement.

--b.

Quoted 48 lines

-dros

Quoted 41 lines · Trond Myklebust
Quoted 7 lines · J. Bruce Fields
Quoted 1 line · Weston Andros Adamson

Just return ok!

Technically it should record whether or not the reclaim_complete has happened and return a GRACE error on any non-reclaim open performed before the reclaim_complete--but for your purposes you may not care...

...and a NOGRACE error on any reclaim opens performed by that client after the reclaim_complete?

Quoted 29 lines

--b.

Quoted 21 lines

---
nfs4.1/nfs4server.py | 3 +++

1 file changed, 3 insertions(+)
nfs4.1/nfs4server.py +3 -1
index 65fb9af..3607dc0 100755
@@ -1809,6 +1809,9 @@ class NFS4Server(rpc.Server):
        with find_state(env, arg.deleg_stateid, allow_0=False) as state:
            state.delegreturn()
        return encode_status(NFS4_OK)
+
+    def op_reclaim_complete(self, arg, env):
+        return encode_status(NFS4_OK)
 
    def op_getdevicelist(self, arg, env): # STUB
        check_session(env)
--
Quoted 2 lines

1.8.5.2 (Apple Git-48)

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#9 lore raw

Re: [PATCH pynfs 02/17] 4.1 server: service RECLAIM_COMPLETE operations

Quoted 11 lines · J. Bruce Fields
Quoted 2 lines · Weston Andros Adamson

Are you saying that the pynfs server supports state recovery? This has not been my experience. I’ll double check.

If you don't support state recovery, then I think the minimal correct behavior would be to have no grace period at all: return NO_GRACE on *every* reclaim operation and GRACE only on non-reclaims not preceded by a global (one_fs == FALSE) RECLAIM_COMPLETE for that client.

All this does is catch misbehaving clients, and maybe that's not a priority. But it's easy enough to implement.

Yeah, that sounds good.

-dros

Quoted 51 lines

—b.

Quoted 48 lines

-dros

Quoted 41 lines · Trond Myklebust
Quoted 7 lines · J. Bruce Fields
Quoted 1 line · Weston Andros Adamson

Just return ok!

Technically it should record whether or not the reclaim_complete has happened and return a GRACE error on any non-reclaim open performed before the reclaim_complete--but for your purposes you may not care...

...and a NOGRACE error on any reclaim opens performed by that client after the reclaim_complete?

Quoted 29 lines

--b.

Quoted 21 lines

---
nfs4.1/nfs4server.py | 3 +++

1 file changed, 3 insertions(+)
nfs4.1/nfs4server.py +3 -1
index 65fb9af..3607dc0 100755
@@ -1809,6 +1809,9 @@ class NFS4Server(rpc.Server):
       with find_state(env, arg.deleg_stateid, allow_0=False) as state:
           state.delegreturn()
       return encode_status(NFS4_OK)
+
+    def op_reclaim_complete(self, arg, env):
+        return encode_status(NFS4_OK)
 
   def op_getdevicelist(self, arg, env): # STUB
       check_session(env)
--
Quoted 2 lines

1.8.5.2 (Apple Git-48)

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#10 lore raw

Re: [PATCH pynfs 02/17] 4.1 server: service RECLAIM_COMPLETE operations

On second thought, I’m just going to drop this patch.

I only added it to avoid a NFS4ERR_NOTSUPP when connecting the file layout MDS to pynfs DSes, but it is harmless and outside the scope of what I’m doing.

Not worth that can of worms.

-dros

Quoted 71 lines · Weston Andros Adamson
Quoted 11 lines · J. Bruce Fields
Quoted 2 lines · Weston Andros Adamson

Are you saying that the pynfs server supports state recovery? This has not been my experience. I’ll double check.

If you don't support state recovery, then I think the minimal correct behavior would be to have no grace period at all: return NO_GRACE on *every* reclaim operation and GRACE only on non-reclaims not preceded by a global (one_fs == FALSE) RECLAIM_COMPLETE for that client.

All this does is catch misbehaving clients, and maybe that's not a priority. But it's easy enough to implement.

Yeah, that sounds good.

-dros

Quoted 51 lines

—b.

Quoted 48 lines

-dros

Quoted 41 lines · Trond Myklebust
Quoted 7 lines · J. Bruce Fields
Quoted 1 line · Weston Andros Adamson

Just return ok!

Technically it should record whether or not the reclaim_complete has happened and return a GRACE error on any non-reclaim open performed before the reclaim_complete--but for your purposes you may not care...

...and a NOGRACE error on any reclaim opens performed by that client after the reclaim_complete?

Quoted 29 lines

--b.

Quoted 21 lines

---
nfs4.1/nfs4server.py | 3 +++

1 file changed, 3 insertions(+)
nfs4.1/nfs4server.py +3 -1
index 65fb9af..3607dc0 100755
@@ -1809,6 +1809,9 @@ class NFS4Server(rpc.Server):
      with find_state(env, arg.deleg_stateid, allow_0=False) as state:
          state.delegreturn()
      return encode_status(NFS4_OK)
+
+    def op_reclaim_complete(self, arg, env):
+        return encode_status(NFS4_OK)
 
  def op_getdevicelist(self, arg, env): # STUB
      check_session(env)
--
Quoted 2 lines

1.8.5.2 (Apple Git-48)

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#11 lore raw

Re: [PATCH pynfs 02/17] 4.1 server: service RECLAIM_COMPLETE operations

Quoted 6 lines · Weston Andros Adamson

On second thought, I’m just going to drop this patch.

I only added it to avoid a NFS4ERR_NOTSUPP when connecting the file layout MDS to pynfs DSes, but it is harmless and outside the scope of what I’m doing.

Not worth that can of worms.

The MDS shouldn't really have to handle NOTSUPP on RECLAIM_COMPLETE (even if yours currently happens to). I think your no-op patch as it is would be better than nothing.

--b.

Quoted 79 lines

-dros

Quoted 71 lines · Weston Andros Adamson
Quoted 11 lines · J. Bruce Fields
Quoted 2 lines · Weston Andros Adamson

Are you saying that the pynfs server supports state recovery? This has not been my experience. I’ll double check.

If you don't support state recovery, then I think the minimal correct behavior would be to have no grace period at all: return NO_GRACE on *every* reclaim operation and GRACE only on non-reclaims not preceded by a global (one_fs == FALSE) RECLAIM_COMPLETE for that client.

All this does is catch misbehaving clients, and maybe that's not a priority. But it's easy enough to implement.

Yeah, that sounds good.

-dros

Quoted 51 lines

—b.

Quoted 48 lines

-dros

Quoted 41 lines · Trond Myklebust
Quoted 7 lines · J. Bruce Fields
Quoted 1 line · Weston Andros Adamson

Just return ok!

Technically it should record whether or not the reclaim_complete has happened and return a GRACE error on any non-reclaim open performed before the reclaim_complete--but for your purposes you may not care...

...and a NOGRACE error on any reclaim opens performed by that client after the reclaim_complete?

Quoted 29 lines

--b.

Quoted 21 lines

---
nfs4.1/nfs4server.py | 3 +++

1 file changed, 3 insertions(+)
nfs4.1/nfs4server.py +3 -1
index 65fb9af..3607dc0 100755
@@ -1809,6 +1809,9 @@ class NFS4Server(rpc.Server):
      with find_state(env, arg.deleg_stateid, allow_0=False) as state:
          state.delegreturn()
      return encode_status(NFS4_OK)
+
+    def op_reclaim_complete(self, arg, env):
+        return encode_status(NFS4_OK)
 
  def op_getdevicelist(self, arg, env): # STUB
      check_session(env)
--
Quoted 2 lines

1.8.5.2 (Apple Git-48)

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#12 lore raw

Re: [PATCH pynfs 02/17] 4.1 server: service RECLAIM_COMPLETE operations

Well, it works fine without it - the pynfs MDS just ignores the NOTSUPP!

If you really want it I can submit it later, but it’s unneeded and unrelated to the goals of this patchset.

-dros

Quoted 93 lines · J. Bruce Fields
Quoted 6 lines · Weston Andros Adamson

On second thought, I’m just going to drop this patch.

I only added it to avoid a NFS4ERR_NOTSUPP when connecting the file layout MDS to pynfs DSes, but it is harmless and outside the scope of what I’m doing.

Not worth that can of worms.

The MDS shouldn't really have to handle NOTSUPP on RECLAIM_COMPLETE (even if yours currently happens to). I think your no-op patch as it is would be better than nothing.

--b.

Quoted 79 lines

-dros

Quoted 71 lines · Weston Andros Adamson
Quoted 11 lines · J. Bruce Fields
Quoted 2 lines · Weston Andros Adamson

Are you saying that the pynfs server supports state recovery? This has not been my experience. I’ll double check.

If you don't support state recovery, then I think the minimal correct behavior would be to have no grace period at all: return NO_GRACE on *every* reclaim operation and GRACE only on non-reclaims not preceded by a global (one_fs == FALSE) RECLAIM_COMPLETE for that client.

All this does is catch misbehaving clients, and maybe that's not a priority. But it's easy enough to implement.

Yeah, that sounds good.

-dros

Quoted 51 lines

—b.

Quoted 48 lines

-dros

Quoted 41 lines · Trond Myklebust
Quoted 7 lines · J. Bruce Fields
Quoted 1 line · Weston Andros Adamson

Just return ok!

Technically it should record whether or not the reclaim_complete has happened and return a GRACE error on any non-reclaim open performed before the reclaim_complete--but for your purposes you may not care...

...and a NOGRACE error on any reclaim opens performed by that client after the reclaim_complete?

Quoted 29 lines

--b.

Quoted 21 lines

---
nfs4.1/nfs4server.py | 3 +++

1 file changed, 3 insertions(+)
nfs4.1/nfs4server.py +3 -1
index 65fb9af..3607dc0 100755
@@ -1809,6 +1809,9 @@ class NFS4Server(rpc.Server):
     with find_state(env, arg.deleg_stateid, allow_0=False) as state:
         state.delegreturn()
     return encode_status(NFS4_OK)
+
+    def op_reclaim_complete(self, arg, env):
+        return encode_status(NFS4_OK)
 
 def op_getdevicelist(self, arg, env): # STUB
     check_session(env)
--
Quoted 2 lines

1.8.5.2 (Apple Git-48)

--
To unsubscribe from this list: send the line "unsubscribe linux-nfs" in the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html

#13 lore raw

PATCH 3/17 dataserver: only catch connection error

In reply to Weston Andros Adamson

This specifically checks for the error being reported, otherwise a other exceptions like a programming error will be caught and treated as connection errors.

---
 nfs4.1/dataserver.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
nfs4.1/dataserver.py +2 -1
index 65e4f55..b8dd903 100644
@@ -9,6 +9,7 @@ import nfs4client
 import hashlib
 import sys
 import nfs4_ops as op
+import socket
 
 log = logging.getLogger("Dataserver Manager")
 
@@ -197,7 +198,7 @@ class DSDevice(object):
                     ds = DataServer(server, port, path, mdsds=self.mdsds,
                                     multipath_servers=server_list)
                     self.list.append(ds)
-                except:
+                except socket.error:
                     log.critical("cannot access %s:%i/%s" %
                                  (server, port, '/'.join(path)))
                     sys.exit(1)
Signature · 1 line
1.8.5.2 (Apple Git-48)
#14 lore raw

PATCH 4/17 4.1 server: avoid traceback in DS disconnect()

In reply to Weston Andros Adamson

Session objects have no destroy method.

---
 nfs4.1/dataserver.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
nfs4.1/dataserver.py +1 -1
index b8dd903..175dd95 100644
@@ -58,7 +58,7 @@ class DataServer(object):
         self.make_root()
 
     def disconnect(self):
-        self.sess.destroy()
+        pass
 
     def execute(self, ops, exceptions=[], delay=5, maxretries=3):
         """ execute the NFS call
Signature · 1 line
1.8.5.2 (Apple Git-48)
#15 lore raw

PATCH 6/17 4.1 client: remove unused imports

In reply to Weston Andros Adamson
---
 nfs4.1/nfs4client.py | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)
nfs4.1/nfs4client.py +1 -3
index 91c698d..0904577 100644
@@ -8,15 +8,13 @@ from xdrdef.sctrl_pack import SCTRLPacker, SCTRLUnpacker
 import nfs4_ops as op
 import time, struct
 import threading
-import collections
 import hmac
-from locking import Lock
 from nfs4commoncode import CBCompoundState as CompoundState, \
      cb_encode_status as encode_status, \
      cb_encode_status_by_name as encode_status_by_name
 
 
-import sys, traceback
+import traceback
 import logging
 logging.basicConfig(level=logging.INFO,
                     format="%(levelname)-7s:%(name)s:%(message)s")
Signature · 1 line
1.8.5.2 (Apple Git-48)
#16 lore raw

PATCH 7/17 4.1 server: add -v flag & silence random output

In reply to Weston Andros Adamson

By default the nfs4server spews so much information to stdout/stderr that it's almost useless. Add the -v flag (aka --verbose) to enable the old output.

Also remove some random prints and change some to log.info().

---
 nfs4.1/dataserver.py |  3 +--
 nfs4.1/fs.py         |  4 ----
 nfs4.1/nfs4client.py | 11 ++--------
 nfs4.1/nfs4server.py | 61 +++++++++++++++++++++++-----------------------------
 nfs4.1/nfs4state.py  |  1 -
 5 files changed, 30 insertions(+), 50 deletions(-)
nfs4.1/dataserver.py +1 -2
index 7f5f72c..d697631 100644
@@ -181,7 +181,7 @@ class DSDevice(object):
                 line = line.strip()
                 if not line or line.startswith('#'):
                     continue
-                print "Analyzing: %r" % line
+                log.info("Analyzing: %r" % line)
                 try:
                     server_list, path = nfs4lib.parse_nfs_url(line)
                 except:
@@ -191,7 +191,6 @@ class DSDevice(object):
                 # for now, just use the last path for local connections
                 server, port = server_list[-1]
                 server_list = server_list[:-1]
-                print server, port, path
                 try:
                     log.info("Adding dataserver ip:%s port:%s path:%s" %
                              (server, port, '/'.join(path)))
nfs4.1/fs.py +0 -4
index 3d63ce5..6ef283b 100644
@@ -13,7 +13,6 @@ from xdrdef.nfs4_pack import NFS4Packer
 log_o = logging.getLogger("fs.obj")
 log_fs = logging.getLogger("fs")
 logging.addLevelName(5, "FUNCT")
-log_fs.setLevel(20)
 
 class MetaData(object):
     """Contains everything that needs to be stored
@@ -743,7 +742,6 @@ class ConfigObj(FSObject):
             line = line.strip()
             if line and not line.startswith("#"):
                 lines.append(line)
-        print lines
         if len(lines) != 1:
             self._reset()
             return
@@ -1154,7 +1152,6 @@ class LayoutFSObj(FSObject):
                                             disk_offset,
                                             e.state))
         block_layout = pnfs_block_layout4(elist)
-        print block_layout
         p = block.Packer()
         p.pack_pnfs_block_layout4(block_layout)
 ##         if self.id <= 4:
@@ -1194,7 +1191,6 @@ class LayoutFSObj(FSObject):
                 log_o.exception("Problem decoding opaque")
                 raise NFS4Error(NFS4ERR_BADLAYOUT, tag="Error decoding opaque")
             upd_list = update.blu_commit_list
-            print upd_list
         # Error check
         for e in upd_list:
             if e.bex_state != block.PNFS_BLOCK_READWRITE_DATA:
nfs4.1/nfs4client.py +2 -9
index 0904577..e504362 100644
@@ -19,9 +19,7 @@ import logging
 logging.basicConfig(level=logging.INFO,
                     format="%(levelname)-7s:%(name)s:%(message)s")
 log_cb = logging.getLogger("nfs.client.cb")
-log_cb.setLevel(logging.DEBUG)
 
-SHOW_TRAFFIC = True # Debugging aid, prints out client traffic
 class NFS4Client(rpc.Client, rpc.Server):
     def __init__(self, host='localhost', port=2049, minorversion=1, ctrl_proc=16):
         rpc.Client.__init__(self, 100003, 4)
@@ -76,9 +74,7 @@ class NFS4Client(rpc.Client, rpc.Server):
             pipe = self.c1
         p = packer(check_enum=checks, check_array=checks)
         c4 = COMPOUND4args(tag, version, ops)
-        if SHOW_TRAFFIC:
-            print
-            print c4
+        log_cb.info("compound args = %r" % (c4,))
         p.pack_COMPOUND4args(c4)
         return self.send_call(pipe, 1, p.get_buffer(), credinfo)
 
@@ -86,19 +82,16 @@ class NFS4Client(rpc.Client, rpc.Server):
         xid = self.compound_async(*args, **kwargs)
         pipe = kwargs.get("pipe", None)
         res = self.listen(xid, pipe=pipe)
-        if SHOW_TRAFFIC:
-            print res
+        log_cb.info("compound result = %r" % (res,))
         return res
     
     def listen(self, xid, pipe=None, timeout=10.0):
         if pipe is None:
             pipe = self.c1
         header, data = pipe.listen(xid, timeout)
-        #print "HEADER", header
         if data:
             p = nfs4lib.FancyNFS4Unpacker(data)
             data = p.unpack_COMPOUND4res()
-        #print "DATA", repr(data)
         return data
 
     def handle_0(self, data, cred):
nfs4.1/nfs4server.py +27 -34

150 lines not on this page · raw message

nfs4.1/nfs4state.py +0 -1
index 1294083..2f3cd59 100644
@@ -13,7 +13,6 @@ import rpc
 import logging
 
 log = logging.getLogger("nfs.server.state")
-log.setLevel(10)
 
 POSIXLOCK = False
 
Signature · 1 line
1.8.5.2 (Apple Git-48)
#17 lore raw

PATCH 8/17 4.1 server: add -s option to print summary of ops

In reply to Weston Andros Adamson

As a middle ground between verbose (-v) mode and silent mode, add "-s" (aka "--show_summary") to print one line per operation.

The summary mode will print a "role" header whenever the role changes.

Example output - mds starts, talks to v3 ds (.200), client (.11) mounts, touches an existing file:

call v3 172.16.200.200:2049
access
Mounting (2, 6) on '/files'

handle v4.1 ::ffff:172.16.200.11:758
exchange_id
create_session
sequence, reclaim_complete
sequence, putrootfh, secinfo_no_name
sequence, putrootfh, getfh, getattr
sequence, putfh, getattr
(repeated 6 times)
sequence, putfh, access, getattr
sequence, putfh, lookup, getfh, getattr
(repeated 1 times)
sequence, putfh, secinfo -> NFS4ERR_NOTSUPP
sequence, putfh, getattr
(repeated 4 times)
sequence, putfh, access, getattr

call v3 172.16.200.200:2049
create -> NFS3ERR_EXIST
lookup
getattr
(repeated 1 times)

handle v4.1 ::ffff:172.16.200.11:758
sequence, putfh, open, getfh, access, getattr

call v3 172.16.200.200:2049
getattr
(repeated 1 times)

handle v4.1 ::ffff:172.16.200.11:758
sequence, putfh, setattr, getattr
sequence, putfh, close, getattr

---
 nfs4.1/dataserver.py     | 16 ++++++++++------
 nfs4.1/nfs4client.py     |  7 ++++++-
 nfs4.1/nfs4server.py     | 47 ++++++++++++++++++++++++++++++++++++++++++++++-
 nfs4.1/server_exports.py |  7 ++++---
 4 files changed, 66 insertions(+), 11 deletions(-)
nfs4.1/dataserver.py +10 -6
index d697631..9b0462d 100644
@@ -13,8 +13,8 @@ import socket
 
 log = logging.getLogger("Dataserver Manager")
 
-class DataServer(object):
-    def __init__(self, server, port, path, flavor=rpc.AUTH_SYS, active=True, mdsds=True, multipath_servers=None):
+class DataServer41(object):
+    def __init__(self, server, port, path, flavor=rpc.AUTH_SYS, active=True, mdsds=True, multipath_servers=None, summary=None):
         self.mdsds = mdsds
         self.server = server
         self.port = int(port)
@@ -32,6 +32,8 @@ class DataServer(object):
         else:
             self.multipath_servers = []
 
+        self.summary = summary
+
         if active:
             self.up()
 
@@ -47,7 +49,8 @@ class DataServer(object):
         # only support root with AUTH_SYS for now
         s1 = rpc.security.instance(rpc.AUTH_SYS)
         self.cred1 = s1.init_cred(uid=0, gid=0)
-        self.c1 = nfs4client.NFS4Client(self.server, self.port)
+        self.c1 = nfs4client.NFS4Client(self.server, self.port,
+                                        summary=self.summary)
         self.c1.set_cred(self.cred1)
         self.c1.null()
         c = self.c1.new_client("DS.init_%s" % self.server)
@@ -172,7 +175,7 @@ class DSDevice(object):
         self.address_body = None # set by load()
         self.mdsds = mdsds # if you are both the DS and the MDS we are the only server
 
-    def load(self, filename):
+    def load(self, filename, server_obj):
         """ Read dataservers from configuration file:
         where each line has format e.g. server[:[port][/path]]
         """
@@ -194,8 +197,9 @@ class DSDevice(object):
                 try:
                     log.info("Adding dataserver ip:%s port:%s path:%s" %
                              (server, port, '/'.join(path)))
-                    ds = DataServer(server, port, path, mdsds=self.mdsds,
-                                    multipath_servers=server_list)
+                    ds = DataServer41(server, port, path, mdsds=self.mdsds,
+                                    multipath_servers=server_list,
+                                    summary=server_obj.summary)
                     self.list.append(ds)
                 except socket.error:
                     log.critical("cannot access %s:%i/%s" %
nfs4.1/nfs4client.py +6 -1
index e504362..f5d2006 100644
@@ -21,7 +21,7 @@ logging.basicConfig(level=logging.INFO,
 log_cb = logging.getLogger("nfs.client.cb")
 
 class NFS4Client(rpc.Client, rpc.Server):
-    def __init__(self, host='localhost', port=2049, minorversion=1, ctrl_proc=16):
+    def __init__(self, host='localhost', port=2049, minorversion=1, ctrl_proc=16, summary=None):
         rpc.Client.__init__(self, 100003, 4)
         self.prog = 0x40000000
         self.versions = [1] # List of supported versions of prog
@@ -36,6 +36,7 @@ class NFS4Client(rpc.Client, rpc.Server):
         self.c1 = self.connect(self.server_address)
         self.sessions = {} # XXX Really, this should be per server
         self.ctrl_proc = ctrl_proc
+        self.summary = summary
 
     def set_cred(self, credinfo):
         self.default_cred = credinfo
@@ -83,6 +84,10 @@ class NFS4Client(rpc.Client, rpc.Server):
         pipe = kwargs.get("pipe", None)
         res = self.listen(xid, pipe=pipe)
         log_cb.info("compound result = %r" % (res,))
+        if self.summary:
+            self.summary.show_op('call v4.1 %s:%s' % self.server_address,
+                [ nfs_opnum4[a.argop].lower()[3:] for a in args[0] ],
+                nfsstat4[res.status])
         return res
     
     def listen(self, xid, pipe=None, timeout=10.0):
nfs4.1/nfs4server.py +46 -1

87 lines not on this page · raw message

nfs4.1/server_exports.py +4 -3
index d96b27b..ef857ee 100644
@@ -15,7 +15,7 @@ def mount_stuff(server, opts):
         E = BlockLayoutFS(5, backing_device=dev)
         server.mount(E, path="/block")
     if opts.use_files:
-        dservers = _load_dataservers(opts.dataservers, server.is_ds and server.is_mds)
+        dservers = _load_dataservers(opts.dataservers, server)
         if dservers is None:
             return
         F = FileLayoutFS(6, dservers)
@@ -33,7 +33,8 @@ def _create_simple_block_dev():
     c1 = Concat([s3, s1])
     return BlockVolume(c1)
 
-def _load_dataservers(file, connect_to_ds=False):
+def _load_dataservers(filename, server):
+    connect_to_ds = server.is_ds and server.is_mds
     dss = DSDevice(connect_to_ds)
-    dss.load(file)
+    dss.load(filename, server)
     return dss;
Signature · 1 line
1.8.5.2 (Apple Git-48)
#18 lore raw

PATCH 9/17 dataserver: make generic interface to ops

In reply to Weston Andros Adamson

Hide the execute method to make DataServer objects more generic.

---
 nfs4.1/dataserver.py | 41 ++++++++++++++++++++++++++++++++++-------
 nfs4.1/fs.py         | 24 ++++--------------------
 2 files changed, 38 insertions(+), 27 deletions(-)
nfs4.1/dataserver.py +34 -7
index 9b0462d..5a3b851 100644
@@ -63,7 +63,7 @@ class DataServer41(object):
     def disconnect(self):
         pass
 
-    def execute(self, ops, exceptions=[], delay=5, maxretries=3):
+    def _execute(self, ops, exceptions=[], delay=5, maxretries=3):
         """ execute the NFS call
         If an error code is specified in the exceptions it means that the
         caller wants to handle the error himself
@@ -117,16 +117,16 @@ class DataServer41(object):
         kind = createtype4(NF4DIR)
         for comp in self.path:
             existing_path.append(comp)
-            res = self.execute(nfs4lib.use_obj(existing_path),
+            res = self._execute(nfs4lib.use_obj(existing_path),
                                exceptions=[NFS4ERR_NOENT])
             if res.status == NFS4ERR_NOENT:
                 cr_ops = nfs4lib.use_obj(existing_path[:-1]) + \
                     [op.create(kind, comp, attrs)]
-                self.execute(cr_ops)
-        res = self.execute(nfs4lib.use_obj(self.path) + [op.getfh()])
+                self._execute(cr_ops)
+        res = self._execute(nfs4lib.use_obj(self.path) + [op.getfh()])
         self.path_fh = res.resarray[-1].object
         need = ACCESS4_READ | ACCESS4_LOOKUP | ACCESS4_MODIFY | ACCESS4_EXTEND
-        res = self.execute(nfs4lib.use_obj(self.path_fh) + [op.access(need)])
+        res = self._execute(nfs4lib.use_obj(self.path_fh) + [op.access(need)])
         if res.resarray[-1].access != need:
             raise RuntimeError
         # XXX clean DS directory
@@ -146,7 +146,7 @@ class DataServer41(object):
             open_op = op.open(seqid, access, deny,
                               open_owner4(self.sess.client.clientid, owner),
                               openflag, open_claim4(CLAIM_NULL, name))
-            res = self.execute(nfs4lib.use_obj(self.path_fh) + [open_op, op.getfh()], exceptions=[NFS4ERR_EXIST])
+            res = self._execute(nfs4lib.use_obj(self.path_fh) + [open_op, op.getfh()], exceptions=[NFS4ERR_EXIST])
             if res.status == NFS4_OK:
                  ds_fh = res.resarray[-1].opgetfh.resok4.object
                  ds_openstateid = stateid4(0, res.resarray[-2].stateid.other)
@@ -162,10 +162,37 @@ class DataServer41(object):
         seqid=0 #FIXME: seqid must be !=0
         fh, stateid = self.filehandles[mds_fh]
         ops = [op.putfh(fh)] + [op.close(seqid, stateid)]
-        res = self.execute(ops)
+        res = self._execute(ops)
         # ignoring return
         del self.filehandles[mds_fh]
 
+    def read(self, fh, pos, count):
+        ops = [op.putfh(fh),
+               op.read(nfs4lib.state00, pos, count)]
+        # There are all sorts of error handling issues here
+        res = self._execute(ops)
+        data = res.resarray[-1].data
+        return data
+
+    def write(self, fh, pos, data):
+        ops = [op.putfh(fh),
+               op.write(nfs4lib.state00, pos, FILE_SYNC4, data)]
+        # There are all sorts of error handling issues here
+        res = self._execute(ops)
+
+    def truncate(self, fh, size):
+        ops = [op.putfh(fh),
+               op.setattr(nfs4lib.state00, {FATTR4_SIZE: size})]
+        res = self._execute(ops)
+
+    def get_size(self, fh):
+        ops = [op.putfh(fh),
+               op.getattr(1L << FATTR4_SIZE)]
+        res = self._execute(ops)
+        attrdict = res.resarray[-1].obj_attributes
+        return attrdict.get(FATTR4_SIZE, 0)
+
+
 class DSDevice(object):
     def __init__(self, mdsds):
         self.list = [] # list of DataServer instances
nfs4.1/fs.py +4 -20
index 6ef283b..8fc49ef 100644
@@ -1567,12 +1567,7 @@ class FilelayoutVolWrapper(object):
         self._pos = 0
 
     def read(self, count):
-        # STUB stateid0 is illegal to a ds
-        ops = [op.putfh(self._fh),
-               op.read(nfs4lib.state00, self._pos, count)]
-        # There are all sorts of error handling issues here
-        res = self._ds.execute(ops)
-        data = res.resarray[-1].data
+        data = self._ds.read(self._fh, self._pos, count)
         self._pos += len(data)
         return data
 
@@ -1580,25 +1575,14 @@ class FilelayoutVolWrapper(object):
         self._pos = offset
 
     def write(self, data):
-        ops = [op.putfh(self._fh),
-               op.write(nfs4lib.state00, self._pos, FILE_SYNC4, data)]
-        # There are all sorts of error handling issues here
-        res = self._ds.execute(ops)
+        self._ds.write(self._fh, self._pos, data)
         self._pos += len(data)
-        return
 
     def truncate(self, size):
-        ops = [op.putfh(self._fh),
-               op.setattr(nfs4lib.state00, {FATTR4_SIZE: size})]
-        res = self._ds.execute(ops)
-        return
+        self._ds.truncate(self._fh, size)
 
     def get_size(self):
-        ops = [op.putfh(self._fh),
-               op.getattr(1L << FATTR4_SIZE)]
-        res = self._ds.execute(ops)
-        attrdict = res.resarray[-1].obj_attributes
-        return attrdict.get(FATTR4_SIZE, 0)
+        return self._ds.get_size(self._fh)
 
 ################################################
 
Signature · 1 line
1.8.5.2 (Apple Git-48)
#19 lore raw

PATCH 10/17 dataserver: don't import * from nfs4 specific mods

In reply to Weston Andros Adamson

don't pollute the global namespace with constants and types from nfs4_*

this is in preparation for NFSv3 DSes.

---
 nfs4.1/dataserver.py | 60 ++++++++++++++++++++++++++--------------------------
 1 file changed, 30 insertions(+), 30 deletions(-)
nfs4.1/dataserver.py +30 -30
index 5a3b851..a825615 100644
@@ -1,8 +1,8 @@
 import rpc
 import nfs4lib
-from xdrdef.nfs4_type import *
+import xdrdef.nfs4_type as type4
 from xdrdef.nfs4_pack import NFS4Packer
-from xdrdef.nfs4_const import *
+import xdrdef.nfs4_const as const4
 import time
 import logging
 import nfs4client
@@ -56,7 +56,7 @@ class DataServer41(object):
         c = self.c1.new_client("DS.init_%s" % self.server)
         # This is a hack to ensure MDS/DS communication path is at least
         # as wide as the client/MDS channel (at least for linux client)
-        fore_attrs = channel_attrs4(0, 16384, 16384, 2868, 8, 8, [])
+        fore_attrs = type4.channel_attrs4(0, 16384, 16384, 2868, 8, 8, [])
         self.sess = c.create_session(fore_attrs=fore_attrs)
         self.make_root()
 
@@ -68,12 +68,12 @@ class DataServer41(object):
         If an error code is specified in the exceptions it means that the
         caller wants to handle the error himself
         """
-        retry_errors = [NFS4ERR_DELAY, NFS4ERR_GRACE]
-        state_errors = [NFS4ERR_STALE_CLIENTID, NFS4ERR_BADSESSION,
-                        NFS4ERR_BADSLOT, NFS4ERR_DEADSESSION]
+        retry_errors = [const4.NFS4ERR_DELAY, const4.NFS4ERR_GRACE]
+        state_errors = [const4.NFS4ERR_STALE_CLIENTID, const4.NFS4ERR_BADSESSION,
+                        const4.NFS4ERR_BADSLOT, const4.NFS4ERR_DEADSESSION]
         while True:
             res = self.sess.compound(ops)
-            if res.status == NFS4_OK or res.status in exceptions:
+            if res.status == const4.NFS4_OK or res.status in exceptions:
                 return res
             elif res.status in retry_errors:
                 if maxretries > 0:
@@ -95,7 +95,7 @@ class DataServer41(object):
         uaddr = '.'.join([self.server,
                           str(self.port >> 8),
                           str(self.port & 0xff)])
-        return netaddr4(self.proto, uaddr)
+        return type4.netaddr4(self.proto, uaddr)
 
     def get_multipath_netaddr4s(self):
         netaddr4s = []
@@ -108,24 +108,24 @@ class DataServer41(object):
             if server.find(':') >= 0:
                 proto = "tcp6"
 
-            netaddr4s.append(netaddr4(proto, uaddr))
+            netaddr4s.append(type4.netaddr4(proto, uaddr))
         return netaddr4s
 
 
-    def make_root(self, attrs={FATTR4_MODE:0777}):
+    def make_root(self, attrs={const4.FATTR4_MODE:0777}):
         existing_path = []
-        kind = createtype4(NF4DIR)
+        kind = type4.createtype4(const4.NF4DIR)
         for comp in self.path:
             existing_path.append(comp)
             res = self._execute(nfs4lib.use_obj(existing_path),
-                               exceptions=[NFS4ERR_NOENT])
-            if res.status == NFS4ERR_NOENT:
+                               exceptions=[const4.NFS4ERR_NOENT])
+            if res.status == const4.NFS4ERR_NOENT:
                 cr_ops = nfs4lib.use_obj(existing_path[:-1]) + \
                     [op.create(kind, comp, attrs)]
                 self._execute(cr_ops)
         res = self._execute(nfs4lib.use_obj(self.path) + [op.getfh()])
         self.path_fh = res.resarray[-1].object
-        need = ACCESS4_READ | ACCESS4_LOOKUP | ACCESS4_MODIFY | ACCESS4_EXTEND
+        need = const4.ACCESS4_READ | const4.ACCESS4_LOOKUP | const4.ACCESS4_MODIFY | const4.ACCESS4_EXTEND
         res = self._execute(nfs4lib.use_obj(self.path_fh) + [op.access(need)])
         if res.resarray[-1].access != need:
             raise RuntimeError
@@ -135,25 +135,25 @@ class DataServer41(object):
         return hashlib.sha1("%r" % mds_fh).hexdigest()
 
     def open_file(self, mds_fh, seqid=0,
-                  access=OPEN4_SHARE_ACCESS_BOTH, deny=OPEN4_SHARE_DENY_NONE,
-                  attrs={FATTR4_MODE: 0777}, owner = "mds", mode=GUARDED4):
+                  access=const4.OPEN4_SHARE_ACCESS_BOTH, deny=const4.OPEN4_SHARE_DENY_NONE,
+                  attrs={const4.FATTR4_MODE: 0777}, owner = "mds", mode=const4.GUARDED4):
         verifier = self.sess.c.verifier
-        openflag = openflag4(OPEN4_CREATE, createhow4(mode, attrs, verifier))
+        openflag = type4.openflag4(const4.OPEN4_CREATE, type4.createhow4(mode, attrs, verifier))
         name = self.fh_to_name(mds_fh)
         while True:
             if mds_fh in self.filehandles:
                 return
             open_op = op.open(seqid, access, deny,
-                              open_owner4(self.sess.client.clientid, owner),
-                              openflag, open_claim4(CLAIM_NULL, name))
-            res = self._execute(nfs4lib.use_obj(self.path_fh) + [open_op, op.getfh()], exceptions=[NFS4ERR_EXIST])
-            if res.status == NFS4_OK:
+                              type4.open_owner4(self.sess.client.clientid, owner),
+                              openflag, type4.open_claim4(const4.CLAIM_NULL, name))
+            res = self._execute(nfs4lib.use_obj(self.path_fh) + [open_op, op.getfh()], exceptions=[const4.NFS4ERR_EXIST])
+            if res.status == const4.NFS4_OK:
                  ds_fh = res.resarray[-1].opgetfh.resok4.object
-                 ds_openstateid = stateid4(0, res.resarray[-2].stateid.other)
+                 ds_openstateid = type4.stateid4(0, res.resarray[-2].stateid.other)
                  self.filehandles[mds_fh] = (ds_fh, ds_openstateid)
                  return
-            elif res.status == NFS4ERR_EXIST:
-                 openflag = openflag4(OPEN4_NOCREATE)
+            elif res.status == const4.NFS4ERR_EXIST:
+                 openflag = type4.openflag4(const4.OPEN4_NOCREATE)
             else:
                 raise RuntimeError
 
@@ -176,26 +176,26 @@ class DataServer41(object):
 
     def write(self, fh, pos, data):
         ops = [op.putfh(fh),
-               op.write(nfs4lib.state00, pos, FILE_SYNC4, data)]
+               op.write(nfs4lib.state00, pos, const4.FILE_SYNC4, data)]
         # There are all sorts of error handling issues here
         res = self._execute(ops)
 
     def truncate(self, fh, size):
         ops = [op.putfh(fh),
-               op.setattr(nfs4lib.state00, {FATTR4_SIZE: size})]
+               op.setattr(nfs4lib.state00, {const4.FATTR4_SIZE: size})]
         res = self._execute(ops)
 
     def get_size(self, fh):
         ops = [op.putfh(fh),
-               op.getattr(1L << FATTR4_SIZE)]
+               op.getattr(1L << const4.FATTR4_SIZE)]
         res = self._execute(ops)
         attrdict = res.resarray[-1].obj_attributes
-        return attrdict.get(FATTR4_SIZE, 0)
+        return attrdict.get(const4.FATTR4_SIZE, 0)
 
 
 class DSDevice(object):
     def __init__(self, mdsds):
-        self.list = [] # list of DataServer instances
+        self.list = [] # list of DataServer41 instances
         # STUB only one data group supported for now
         self.devid = 0
         self.active = 0
@@ -247,7 +247,7 @@ class DSDevice(object):
                 netaddrs.append(multipath)
                 stripe_indices.append(index)
                 index = index + 1
-        addr = nfsv4_1_file_layout_ds_addr4(stripe_indices, netaddrs)
+        addr = type4.nfsv4_1_file_layout_ds_addr4(stripe_indices, netaddrs)
         p = NFS4Packer()
         p.pack_nfsv4_1_file_layout_ds_addr4(addr)
         return p.get_buffer()
Signature · 1 line
1.8.5.2 (Apple Git-48)
#20 lore raw

PATCH 11/17 4.1 server: move nfs4_ops.py to nfs_ops.py

In reply to Weston Andros Adamson

Also replace ugly exec & inspect code to just define a class with a __getattr__ switch.

---
 nfs4.1/dataserver.py | 32 ++++++++++---------
 nfs4.1/fs.py         |  2 --
 nfs4.1/nfs4_ops.py   | 61 -----------------------------------
 nfs4.1/nfs4client.py | 16 +++++-----
 nfs4.1/nfs4lib.py    |  8 +++--
 nfs4.1/nfs4state.py  |  8 +++--
 nfs4.1/nfs_ops.py    | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 7 files changed, 125 insertions(+), 91 deletions(-)
 delete mode 100644 nfs4.1/nfs4_ops.py
 create mode 100644 nfs4.1/nfs_ops.py
nfs4.1/dataserver.py +17 -15
index a825615..c73e195 100644
@@ -8,11 +8,13 @@ import logging
 import nfs4client
 import hashlib
 import sys
-import nfs4_ops as op
+import nfs_ops
 import socket
 
 log = logging.getLogger("Dataserver Manager")
 
+op4 = nfs_ops.NFS4ops()
+
 class DataServer41(object):
     def __init__(self, server, port, path, flavor=rpc.AUTH_SYS, active=True, mdsds=True, multipath_servers=None, summary=None):
         self.mdsds = mdsds
@@ -121,12 +123,12 @@ class DataServer41(object):
                                exceptions=[const4.NFS4ERR_NOENT])
             if res.status == const4.NFS4ERR_NOENT:
                 cr_ops = nfs4lib.use_obj(existing_path[:-1]) + \
-                    [op.create(kind, comp, attrs)]
+                    [op4.create(kind, comp, attrs)]
                 self._execute(cr_ops)
-        res = self._execute(nfs4lib.use_obj(self.path) + [op.getfh()])
+        res = self._execute(nfs4lib.use_obj(self.path) + [op4.getfh()])
         self.path_fh = res.resarray[-1].object
         need = const4.ACCESS4_READ | const4.ACCESS4_LOOKUP | const4.ACCESS4_MODIFY | const4.ACCESS4_EXTEND
-        res = self._execute(nfs4lib.use_obj(self.path_fh) + [op.access(need)])
+        res = self._execute(nfs4lib.use_obj(self.path_fh) + [op4.access(need)])
         if res.resarray[-1].access != need:
             raise RuntimeError
         # XXX clean DS directory
@@ -143,10 +145,10 @@ class DataServer41(object):
         while True:
             if mds_fh in self.filehandles:
                 return
-            open_op = op.open(seqid, access, deny,
+            open_op = op4.open(seqid, access, deny,
                               type4.open_owner4(self.sess.client.clientid, owner),
                               openflag, type4.open_claim4(const4.CLAIM_NULL, name))
-            res = self._execute(nfs4lib.use_obj(self.path_fh) + [open_op, op.getfh()], exceptions=[const4.NFS4ERR_EXIST])
+            res = self._execute(nfs4lib.use_obj(self.path_fh) + [open_op, op4.getfh()], exceptions=[const4.NFS4ERR_EXIST])
             if res.status == const4.NFS4_OK:
                  ds_fh = res.resarray[-1].opgetfh.resok4.object
                  ds_openstateid = type4.stateid4(0, res.resarray[-2].stateid.other)
@@ -161,33 +163,33 @@ class DataServer41(object):
         """close the given file"""
         seqid=0 #FIXME: seqid must be !=0
         fh, stateid = self.filehandles[mds_fh]
-        ops = [op.putfh(fh)] + [op.close(seqid, stateid)]
+        ops = [op4.putfh(fh)] + [op4.close(seqid, stateid)]
         res = self._execute(ops)
         # ignoring return
         del self.filehandles[mds_fh]
 
     def read(self, fh, pos, count):
-        ops = [op.putfh(fh),
-               op.read(nfs4lib.state00, pos, count)]
+        ops = [op4.putfh(fh),
+               op4.read(nfs4lib.state00, pos, count)]
         # There are all sorts of error handling issues here
         res = self._execute(ops)
         data = res.resarray[-1].data
         return data
 
     def write(self, fh, pos, data):
-        ops = [op.putfh(fh),
-               op.write(nfs4lib.state00, pos, const4.FILE_SYNC4, data)]
+        ops = [op4.putfh(fh),
+               op4.write(nfs4lib.state00, pos, const4.FILE_SYNC4, data)]
         # There are all sorts of error handling issues here
         res = self._execute(ops)
 
     def truncate(self, fh, size):
-        ops = [op.putfh(fh),
-               op.setattr(nfs4lib.state00, {const4.FATTR4_SIZE: size})]
+        ops = [op4.putfh(fh),
+               op4.setattr(nfs4lib.state00, {const4.FATTR4_SIZE: size})]
         res = self._execute(ops)
 
     def get_size(self, fh):
-        ops = [op.putfh(fh),
-               op.getattr(1L << const4.FATTR4_SIZE)]
+        ops = [op4.putfh(fh),
+               op4.getattr(1L << const4.FATTR4_SIZE)]
         res = self._execute(ops)
         attrdict = res.resarray[-1].obj_attributes
         return attrdict.get(const4.FATTR4_SIZE, 0)
nfs4.1/fs.py +0 -2
index 8fc49ef..8947014 100644
@@ -1557,8 +1557,6 @@ class FileLayoutFile(object): # XXX This should inherit from fs_base.py
         vol = FilelayoutVolWrapper(self._obj, device.list[index])
         return vol, v_pos, remaining
 
-import nfs4_ops as op
-
 class FilelayoutVolWrapper(object):
     def __init__(self, obj, dataserver):
         self._obj = obj
nfs4.1/nfs4_ops.py deleted +0 -61

61 lines not on this page · raw message

nfs4.1/nfs4client.py +9 -7
index f5d2006..263f37d 100644
@@ -5,7 +5,7 @@ from nfs4lib import NFS4Error, NFS4Replay, inc_u32
 from xdrdef.nfs4_type import *
 from xdrdef.nfs4_const import *
 from xdrdef.sctrl_pack import SCTRLPacker, SCTRLUnpacker
-import nfs4_ops as op
+import nfs_ops
 import time, struct
 import threading
 import hmac
@@ -20,6 +20,8 @@ logging.basicConfig(level=logging.INFO,
                     format="%(levelname)-7s:%(name)s:%(message)s")
 log_cb = logging.getLogger("nfs.client.cb")
 
+op4 = nfs_ops.NFS4ops()
+
 class NFS4Client(rpc.Client, rpc.Server):
     def __init__(self, host='localhost', port=2049, minorversion=1, ctrl_proc=16, summary=None):
         rpc.Client.__init__(self, 100003, 4)
@@ -275,7 +277,7 @@ class NFS4Client(rpc.Client, rpc.Server):
         owner = client_owner4(verf, name)
         if protect is None:
             protect = state_protect4_a(SP4_NONE)
-        res = self.compound([op.exchange_id(owner, flags, protect,
+        res = self.compound([op4.exchange_id(owner, flags, protect,
                                             [self.impl_id])],
                             cred)
         nfs4lib.check(res, expect)
@@ -287,7 +289,7 @@ class NFS4Client(rpc.Client, rpc.Server):
     def new_client_session(self, name, flags=0, sec=None):
         c = self.new_client(name, flags=flags)
         s = c.create_session(sec=sec)
-        s.compound([op.reclaim_complete(FALSE)])
+        s.compound([op4.reclaim_complete(FALSE)])
         return s
 
 class ClientStateProtection(object):
@@ -339,7 +341,7 @@ class ClientRecord(object):
         if prog is None:
             prog = self.c.prog
         for item in xrange(max_retries):
-            res = self.c.compound([op.create_session(self.clientid, self.seqid,
+            res = self.c.compound([op4.create_session(self.clientid, self.seqid,
                                                  flags,
                                                  fore_attrs, back_attrs,
                                                  prog, sec)],
@@ -362,7 +364,7 @@ class ClientRecord(object):
         self.seqid = inc_u32(csr.csr_sequence) # XXX Do we need to check this?
         sess = SessionRecord(csr, self)
         self.c.sessions[sess.sessionid] = sess
-        sess.compound([op.reclaim_complete(FALSE)])
+        sess.compound([op4.reclaim_complete(FALSE)])
         return sess
 
     def _cb_hook(self, prefix, opname, funct):
@@ -430,7 +432,7 @@ class SessionRecord(object):
             raise RuntimeError
             slot = self.fore_channel.slots[slot]
         # STUB, need to properly set highest
-        return op.sequence(self.sessionid, slot.get_seqid(seq_delta),
+        return op4.sequence(self.sessionid, slot.get_seqid(seq_delta),
                            slot.id, slot.id, cache_this)
 
     def set_ssv(self, ssv=None, *args, **kwargs):
@@ -443,7 +445,7 @@ class SessionRecord(object):
         p = nfs4lib.FancyNFS4Packer()
         p.pack_SEQUENCE4args(seq_op.opsequence)
         digest =  protect.context.hmac(p.get_buffer(), SSV4_SUBKEY_MIC_I2T)
-        ssv_op = op.set_ssv(ssv, digest)
+        ssv_op = op4.set_ssv(ssv, digest)
         res = self.c.compound([seq_op, ssv_op], *args, **kwargs)
         # STUB - do some checking
         protect.context.set_ssv(ssv)
nfs4.1/nfs4lib.py +5 -3
index 116324a..02352e1 100644
@@ -3,7 +3,7 @@ import rpc
 import xdrdef.nfs4_const
 from xdrdef.nfs4_pack import NFS4Packer, NFS4Unpacker
 import xdrdef.nfs4_type
-import nfs4_ops as op
+import nfs_ops
 import time
 import collections
 import hmac
@@ -30,6 +30,8 @@ state01 = xdrdef.nfs4_type.stateid4(1, "\0" * 12)
 
 import hashlib # Note this requires 2.5 or higher
 
+op4 = nfs_ops.NFS4ops()
+
 # Note that all the oid strings have tag and length bytes prepended, as
 # per description of sec_oid4 in draft26 sect 3.2
 
@@ -626,9 +628,9 @@ def use_obj(file):
     if file is None or file == [None]:
         return []
     elif type(file) is str:
-        return [op.putfh(file)]
+        return [op4.putfh(file)]
     else:
-        return [op.putrootfh()] + [op.lookup(comp) for comp in file]
+        return [op4.putrootfh()] + [op4.lookup(comp) for comp in file]
 
 ###############################################
 # Attribute information
nfs4.1/nfs4state.py +5 -3
index 2f3cd59..2214c0d 100644
@@ -8,12 +8,14 @@ from nfs4lib import NFS4Error
 #from xdrdef.nfs4_type import stateid4
 from xdrdef.nfs4_type import *
 from xdrdef.nfs4_const import *
-import nfs4_ops as op
+import nfs_ops
 import rpc
 import logging
 
 log = logging.getLogger("nfs.server.state")
 
+op4 = nfs_ops.NFS4ops()
+
 POSIXLOCK = False
 
 SHARE, BYTE, DELEG, LAYOUT, ANON = range(5) # State types
@@ -748,9 +750,9 @@ class DelegEntry(StateTableEntry):
         # ANSWER - we care about self.status, which can be set to 
         # INVALID anytime by deleg_return
         slot = session.channel_back.choose_slot()
-        seq_op = op.cb_sequence(session.sessionid, slot.get_seqid(),
+        seq_op = op4.cb_sequence(session.sessionid, slot.get_seqid(),
                                 slot.id, slot.id, True, []) # STUB
-        recall_op = op.cb_recall(self.get_id(cb=True), False, self.file.fh)
+        recall_op = op4.cb_recall(self.get_id(cb=True), False, self.file.fh)
         if self.invalid:
             # Race here doesn't matter, but would like to avoid the
             # RPC if possible.
nfs4.1/nfs_ops.py new file +89 -0

89 lines not on this page · raw message

Signature · 1 line
1.8.5.2 (Apple Git-48)
#21 lore raw

PATCH 12/17 add mntv3, portmapv2 and nfsv3 .x files

In reply to Weston Andros Adamson

mntv3 and nfsv3 .x files made from IETF specs by Tom Haynes <[email protected]>.

portmap2 .x files made from IETF specs by Weston Andros Adamson <[email protected]>.

---
 nfs4.1/xdrdef/mnt3.x    |  68 ++++
 nfs4.1/xdrdef/nfs3.x    | 818 ++++++++++++++++++++++++++++++++++++++++++++++++
 nfs4.1/xdrdef/portmap.x |  51 +++
 3 files changed, 937 insertions(+)
 create mode 100644 nfs4.1/xdrdef/mnt3.x
 create mode 100644 nfs4.1/xdrdef/nfs3.x
 create mode 100644 nfs4.1/xdrdef/portmap.x
nfs4.1/xdrdef/mnt3.x new file +68 -0
new file mode 100644
index 0000000..b632322
@@ -0,0 +1,68 @@
+const MNTPATHLEN = 1024;   /* Maximum bytes in a path name */
+const MNTNAMLEN = 255;     /* Maximum bytes in a name */
+const FHSIZE3 = 64;        /* Maximum bytes in a V3 file handle */
+
+typedef opaque  fhandle3 <FHSIZE3>;
+typedef string  dirpath <MNTPATHLEN>;
+typedef string  name <MNTNAMLEN>;
+
+struct mountres3_ok {
+        fhandle3        fhandle;
+        int             auth_flavors <>;
+};
+
+union mountres3 switch (mountstat3 fhs_status) {
+case MNT3_OK:
+        mountres3_ok mountinfo;
+default:
+        void;
+};
+
+struct mountbody {
+        name            ml_hostname;
+        dirpath         ml_directory;
+        mountlist       ml_next;
+};
+
+typedef mountbody *mountlist;
+
+
+struct groupnode {
+        name            gr_name;
+        groups          gr_next;
+};
+
+typedef groupnode *groups;
+
+
+struct exportnode {
+        dirpath         ex_dir;
+        groups          ex_groups;
+        exports         ex_next;
+};
+
+typedef exportnode *exports;
+
+enum mountstat3 {
+        MNT3_OK = 0,                     /* no error */
+        MNT3ERR_PERM = 1,                /* Not owner */
+        MNT3ERR_NOENT = 2,               /* No such file or directory */
+        MNT3ERR_IO = 5,                  /* I/O error */
+        MNT3ERR_ACCES = 13,              /* Permission denied */
+        MNT3ERR_NOTDIR = 20,             /* Not a directory */
+        MNT3ERR_INVAL = 22,              /* Invalid argument */
+        MNT3ERR_NAMETOOLONG = 63,        /* Filename too long */
+        MNT3ERR_NOTSUPP = 10004,         /* Operation not supported */
+        MNT3ERR_SERVERFAULT = 10006      /* A failure on the server */
+};
+
+program MOUNT_PROGRAM {
+        version MOUNT_V3 {
+                void            MOUNTPROC3_NULL(void) = 0;
+                mountres3       MOUNTPROC3_MNT(dirpath) = 1;
+                mountlist       MOUNTPROC3_DUMP(void) = 2;
+                void            MOUNTPROC3_UMNT(dirpath) = 3;
+                void            MOUNTPROC3_UMNTALL(void) = 4;
+                exports         MOUNTPROC3_EXPORT(void) = 5;
+        } = 3;
+} = 100005;
nfs4.1/xdrdef/nfs3.x new file +818 -0

818 lines not on this page · raw message

nfs4.1/xdrdef/portmap.x new file +51 -0

51 lines not on this page · raw message

Signature · 1 line
1.8.5.2 (Apple Git-48)
#22 lore raw

Re: [PATCH pynfs 12/17] add mntv3, portmapv2 and nfsv3 .x files

Quoted 2 lines · Weston Andros Adamson

mntv3 and nfsv3 .x files made from IETF specs by Tom Haynes <[email protected]>.

Some folks actually submitted v3 client code at some point and I never managed to get it merged. Maybe I should dig that up again while we're doing this.... But probably it's still out of scope.

--b.

Quoted 972 lines

portmap2 .x files made from IETF specs by Weston Andros Adamson <[email protected]>.

---
 nfs4.1/xdrdef/mnt3.x    |  68 ++++
 nfs4.1/xdrdef/nfs3.x    | 818 ++++++++++++++++++++++++++++++++++++++++++++++++
 nfs4.1/xdrdef/portmap.x |  51 +++
 3 files changed, 937 insertions(+)
 create mode 100644 nfs4.1/xdrdef/mnt3.x
 create mode 100644 nfs4.1/xdrdef/nfs3.x
 create mode 100644 nfs4.1/xdrdef/portmap.x
nfs4.1/xdrdef/mnt3.x new file +68 -0
new file mode 100644
index 0000000..b632322
@@ -0,0 +1,68 @@
+const MNTPATHLEN = 1024;   /* Maximum bytes in a path name */
+const MNTNAMLEN = 255;     /* Maximum bytes in a name */
+const FHSIZE3 = 64;        /* Maximum bytes in a V3 file handle */
+
+typedef opaque  fhandle3 <FHSIZE3>;
+typedef string  dirpath <MNTPATHLEN>;
+typedef string  name <MNTNAMLEN>;
+
+struct mountres3_ok {
+        fhandle3        fhandle;
+        int             auth_flavors <>;
+};
+
+union mountres3 switch (mountstat3 fhs_status) {
+case MNT3_OK:
+        mountres3_ok mountinfo;
+default:
+        void;
+};
+
+struct mountbody {
+        name            ml_hostname;
+        dirpath         ml_directory;
+        mountlist       ml_next;
+};
+
+typedef mountbody *mountlist;
+
+
+struct groupnode {
+        name            gr_name;
+        groups          gr_next;
+};
+
+typedef groupnode *groups;
+
+
+struct exportnode {
+        dirpath         ex_dir;
+        groups          ex_groups;
+        exports         ex_next;
+};
+
+typedef exportnode *exports;
+
+enum mountstat3 {
+        MNT3_OK = 0,                     /* no error */
+        MNT3ERR_PERM = 1,                /* Not owner */
+        MNT3ERR_NOENT = 2,               /* No such file or directory */
+        MNT3ERR_IO = 5,                  /* I/O error */
+        MNT3ERR_ACCES = 13,              /* Permission denied */
+        MNT3ERR_NOTDIR = 20,             /* Not a directory */
+        MNT3ERR_INVAL = 22,              /* Invalid argument */
+        MNT3ERR_NAMETOOLONG = 63,        /* Filename too long */
+        MNT3ERR_NOTSUPP = 10004,         /* Operation not supported */
+        MNT3ERR_SERVERFAULT = 10006      /* A failure on the server */
+};
+
+program MOUNT_PROGRAM {
+        version MOUNT_V3 {
+                void            MOUNTPROC3_NULL(void) = 0;
+                mountres3       MOUNTPROC3_MNT(dirpath) = 1;
+                mountlist       MOUNTPROC3_DUMP(void) = 2;
+                void            MOUNTPROC3_UMNT(dirpath) = 3;
+                void            MOUNTPROC3_UMNTALL(void) = 4;
+                exports         MOUNTPROC3_EXPORT(void) = 5;
+        } = 3;
+} = 100005;
nfs4.1/xdrdef/nfs3.x new file +818 -0
new file mode 100644
index 0000000..ddd1395
@@ -0,0 +1,818 @@
+const NFS3_FHSIZE = 64;        /* Maximum bytes in a V3 file handle */
+
+const FALSE = 0;
+const TRUE = 1;
+
+const NFS3_COOKIEVERFSIZE = 8;
+const NFS3_CREATEVERFSIZE = 8;
+const NFS3_WRITEVERFSIZE = 8;
+
+typedef unsigned hyper uint64;
+typedef hyper   int64;
+typedef unsigned int uint32;
+typedef int    int32;
+typedef string  filename3 <>;
+typedef string  nfspath3 <>;
+typedef uint64  fileid3;
+typedef uint64  cookie3;
+typedef opaque  cookieverf3[NFS3_COOKIEVERFSIZE];
+typedef opaque  createverf3[NFS3_CREATEVERFSIZE];
+typedef opaque  writeverf3[NFS3_WRITEVERFSIZE];
+typedef uint32  uid3;
+typedef uint32  gid3;
+typedef uint64  size3;
+typedef uint64  offset3;
+typedef uint32  mode3;
+typedef uint32  count3;
+
+enum nfsstat3 {
+        NFS3_OK = 0,
+        NFS3ERR_PERM = 1,
+        NFS3ERR_NOENT = 2,
+        NFS3ERR_IO = 5,
+        NFS3ERR_NXIO = 6,
+        NFS3ERR_ACCES = 13,
+        NFS3ERR_EXIST = 17,
+        NFS3ERR_XDEV = 18,
+        NFS3ERR_NODEV = 19,
+        NFS3ERR_NOTDIR = 20,
+        NFS3ERR_ISDIR = 21,
+        NFS3ERR_INVAL = 22,
+        NFS3ERR_FBIG = 27,
+        NFS3ERR_NOSPC = 28,
+        NFS3ERR_ROFS = 30,
+        NFS3ERR_MLINK = 31,
+        NFS3ERR_NAMETOOLONG = 63,
+        NFS3ERR_NOTEMPTY = 66,
+        NFS3ERR_DQUOT = 69,
+        NFS3ERR_STALE = 70,
+        NFS3ERR_REMOTE = 71,
+        NFS3ERR_BADHANDLE = 10001,
+        NFS3ERR_NOT_SYNC = 10002,
+        NFS3ERR_BAD_COOKIE = 10003,
+        NFS3ERR_NOTSUPP = 10004,
+        NFS3ERR_TOOSMALL = 10005,
+        NFS3ERR_SERVERFAULT = 10006,
+        NFS3ERR_BADTYPE = 10007,
+        NFS3ERR_JUKEBOX = 10008
+};
+
+enum ftype3 {
+        NF3REG = 1,
+        NF3DIR = 2,
+        NF3BLK = 3,
+        NF3CHR = 4,
+        NF3LNK = 5,
+        NF3SOCK = 6,
+        NF3FIFO = 7
+};
+
+struct specdata3 {
+        uint32          specdata1;
+        uint32          specdata2;
+};
+
+struct nfs_fh3 {
+        opaque          data <NFS3_FHSIZE>;
+};
+
+struct nfstime3 {
+        uint32          seconds;
+        uint32          nseconds;
+};
+
+struct fattr3 {
+        ftype3          type;
+        mode3           mode;
+        uint32          nlink;
+        uid3            uid;
+        gid3            gid;
+        size3           size;
+        size3           used;
+        specdata3       rdev;
+        uint64          fsid;
+        fileid3         fileid;
+        nfstime3        atime;
+        nfstime3        mtime;
+        nfstime3        ctime;
+};
+
+union post_op_attr switch (bool attributes_follow) {
+case TRUE:
+        fattr3 attributes;
+case FALSE:
+        void;
+};
+
+struct wcc_attr {
+        size3           size;
+        nfstime3        mtime;
+        nfstime3        ctime;
+};
+
+union pre_op_attr switch (bool attributes_follow) {
+case TRUE:
+        wcc_attr attributes;
+case FALSE:
+        void;
+};
+
+struct wcc_data {
+        pre_op_attr     before;
+        post_op_attr    after;
+};
+
+union post_op_fh3 switch (bool handle_follows) {
+case TRUE:
+        nfs_fh3 handle;
+case FALSE:
+        void;
+};
+
+enum time_how {
+        DONT_CHANGE = 0,
+        SET_TO_SERVER_TIME = 1,
+        SET_TO_CLIENT_TIME = 2
+};
+
+union set_mode3 switch (bool set_it) {
+case TRUE:
+        mode3 mode;
+default:
+        void;
+};
+
+union set_uid3 switch (bool set_it) {
+case TRUE:
+        uid3 uid;
+default:
+        void;
+};
+
+union set_gid3 switch (bool set_it) {
+case TRUE:
+        gid3 gid;
+default:
+        void;
+};
+
+union set_size3 switch (bool set_it) {
+case TRUE:
+        size3 size;
+default:
+        void;
+};
+
+union set_atime switch (time_how set_it) {
+case SET_TO_CLIENT_TIME:
+        nfstime3 atime;
+default:
+        void;
+};
+
+union set_mtime switch (time_how set_it) {
+case SET_TO_CLIENT_TIME:
+        nfstime3 mtime;
+default:
+        void;
+};
+
+struct sattr3 {
+        set_mode3       mode;
+        set_uid3        uid;
+        set_gid3        gid;
+        set_size3       size;
+        set_atime       atime;
+        set_mtime       mtime;
+};
+
+struct diropargs3 {
+        nfs_fh3         dir;
+        filename3       name;
+};
+
+struct GETATTR3args {
+        nfs_fh3         object;
+};
+
+struct GETATTR3resok {
+        fattr3          obj_attributes;
+};
+
+union GETATTR3res switch (nfsstat3 status) {
+case NFS3_OK:
+        GETATTR3resok resok;
+default:
+        void;
+};
+
+union sattrguard3 switch (bool check) {
+case TRUE:
+        nfstime3 obj_ctime;
+case FALSE:
+        void;
+};
+
+struct SETATTR3args {
+        nfs_fh3         object;
+        sattr3          new_attributes;
+        sattrguard3     guard;
+};
+
+struct SETATTR3resok {
+        wcc_data        obj_wcc;
+};
+
+struct SETATTR3resfail {
+        wcc_data        obj_wcc;
+};
+
+union SETATTR3res switch (nfsstat3 status) {
+case NFS3_OK:
+        SETATTR3resok resok;
+default:
+        SETATTR3resfail resfail;
+};
+
+struct LOOKUP3args {
+        diropargs3      what;
+};
+
+struct LOOKUP3resok {
+        nfs_fh3         object;
+        post_op_attr    obj_attributes;
+        post_op_attr    dir_attributes;
+};
+
+struct LOOKUP3resfail {
+        post_op_attr    dir_attributes;
+};
+
+union LOOKUP3res switch (nfsstat3 status) {
+case NFS3_OK:
+        LOOKUP3resok resok;
+default:
+        LOOKUP3resfail resfail;
+};
+
+const           ACCESS3_READ = 0x0001;
+const           ACCESS3_LOOKUP = 0x0002;
+const           ACCESS3_MODIFY = 0x0004;
+const           ACCESS3_EXTEND = 0x0008;
+const           ACCESS3_DELETE = 0x0010;
+const           ACCESS3_EXECUTE = 0x0020;
+
+struct ACCESS3args {
+        nfs_fh3         object;
+        uint32          access;
+};
+
+struct ACCESS3resok {
+        post_op_attr    obj_attributes;
+        uint32          access;
+};
+
+struct ACCESS3resfail {
+        post_op_attr    obj_attributes;
+};
+
+union ACCESS3res switch (nfsstat3 status) {
+case NFS3_OK:
+        ACCESS3resok resok;
+default:
+        ACCESS3resfail resfail;
+};
+
+struct READLINK3args {
+        nfs_fh3         symlink;
+};
+
+struct READLINK3resok {
+        post_op_attr    symlink_attributes;
+        nfspath3        data;
+};
+
+struct READLINK3resfail {
+        post_op_attr    symlink_attributes;
+};
+
+union READLINK3res switch (nfsstat3 status) {
+case NFS3_OK:
+        READLINK3resok resok;
+default:
+        READLINK3resfail resfail;
+};
+
+struct READ3args {
+        nfs_fh3         file;
+        offset3         offset;
+        count3          count;
+};
+
+struct READ3resok {
+        post_op_attr    file_attributes;
+        count3          count;
+        bool            eof;
+        opaque          data <>;
+};
+
+struct READ3resfail {
+        post_op_attr    file_attributes;
+};
+
+union READ3res switch (nfsstat3 status) {
+case NFS3_OK:
+        READ3resok resok;
+default:
+        READ3resfail resfail;
+};
+
+enum stable_how {
+        UNSTABLE = 0,
+        DATA_SYNC = 1,
+        FILE_SYNC = 2
+};
+
+struct WRITE3args {
+        nfs_fh3         file;
+        offset3         offset;
+        count3          count;
+        stable_how      stable;
+        opaque          data <>;
+};
+
+struct WRITE3resok {
+        wcc_data        file_wcc;
+        count3          count;
+        stable_how      committed;
+        writeverf3      verf;
+};
+
+struct WRITE3resfail {
+        wcc_data        file_wcc;
+};
+
+union WRITE3res switch (nfsstat3 status) {
+case NFS3_OK:
+        WRITE3resok resok;
+default:
+        WRITE3resfail resfail;
+};
+
+enum createmode3 {
+        UNCHECKED = 0,
+        GUARDED = 1,
+        EXCLUSIVE = 2
+};
+
+union createhow3 switch (createmode3 mode) {
+case UNCHECKED:
+case GUARDED:
+        sattr3 obj_attributes;
+case EXCLUSIVE:
+        createverf3 verf;
+};
+
+struct CREATE3args {
+        diropargs3      where;
+        createhow3      how;
+};
+
+struct CREATE3resok {
+        post_op_fh3     obj;
+        post_op_attr    obj_attributes;
+        wcc_data        dir_wcc;
+};
+
+struct CREATE3resfail {
+        wcc_data        dir_wcc;
+};
+
+union CREATE3res switch (nfsstat3 status) {
+case NFS3_OK:
+        CREATE3resok resok;
+default:
+        CREATE3resfail resfail;
+};
+
+struct MKDIR3args {
+        diropargs3      where;
+        sattr3          attributes;
+};
+
+struct MKDIR3resok {
+        post_op_fh3     obj;
+        post_op_attr    obj_attributes;
+        wcc_data        dir_wcc;
+};
+
+struct MKDIR3resfail {
+        wcc_data        dir_wcc;
+};
+
+union MKDIR3res switch (nfsstat3 status) {
+case NFS3_OK:
+        MKDIR3resok resok;
+default:
+        MKDIR3resfail resfail;
+};
+
+struct symlinkdata3 {
+        sattr3          symlink_attributes;
+        nfspath3        symlink_data;
+};
+
+struct SYMLINK3args {
+        diropargs3      where;
+        symlinkdata3    symlink;
+};
+
+struct SYMLINK3resok {
+        post_op_fh3     obj;
+        post_op_attr    obj_attributes;
+        wcc_data        dir_wcc;
+};
+
+struct SYMLINK3resfail {
+        wcc_data        dir_wcc;
+};
+
+union SYMLINK3res switch (nfsstat3 status) {
+case NFS3_OK:
+        SYMLINK3resok resok;
+default:
+        SYMLINK3resfail resfail;
+};
+
+struct devicedata3 {
+        sattr3          dev_attributes;
+        specdata3       spec;
+};
+
+union mknoddata3 switch (ftype3 type) {
+case NF3CHR:
+case NF3BLK:
+        devicedata3 device;
+case NF3SOCK:
+case NF3FIFO:
+        sattr3 pipe_attributes;
+default:
+        void;
+};
+
+struct MKNOD3args {
+        diropargs3      where;
+        mknoddata3      what;
+};
+
+struct MKNOD3resok {
+        post_op_fh3     obj;
+        post_op_attr    obj_attributes;
+        wcc_data        dir_wcc;
+};
+
+struct MKNOD3resfail {
+        wcc_data        dir_wcc;
+};
+
+union MKNOD3res switch (nfsstat3 status) {
+case NFS3_OK:
+        MKNOD3resok resok;
+default:
+        MKNOD3resfail resfail;
+};
+
+struct REMOVE3args {
+        diropargs3      object;
+};
+
+struct REMOVE3resok {
+        wcc_data        dir_wcc;
+};
+
+struct REMOVE3resfail {
+        wcc_data        dir_wcc;
+};
+
+union REMOVE3res switch (nfsstat3 status) {
+case NFS3_OK:
+        REMOVE3resok resok;
+default:
+        REMOVE3resfail resfail;
+};
+
+struct RMDIR3args {
+        diropargs3      object;
+};
+
+struct RMDIR3resok {
+        wcc_data        dir_wcc;
+};
+
+struct RMDIR3resfail {
+        wcc_data        dir_wcc;
+};
+
+union RMDIR3res switch (nfsstat3 status) {
+case NFS3_OK:
+        RMDIR3resok resok;
+default:
+        RMDIR3resfail resfail;
+};
+
+struct RENAME3args {
+        diropargs3      fromfile;
+        diropargs3      tofile;
+};
+
+struct RENAME3resok {
+        wcc_data        fromdir_wcc;
+        wcc_data        todir_wcc;
+};
+
+struct RENAME3resfail {
+        wcc_data        fromdir_wcc;
+        wcc_data        todir_wcc;
+};
+
+union RENAME3res switch (nfsstat3 status) {
+case NFS3_OK:
+        RENAME3resok resok;
+default:
+        RENAME3resfail resfail;
+};
+
+struct LINK3args {
+        nfs_fh3         file;
+        diropargs3      link;
+};
+
+struct LINK3resok {
+        post_op_attr    file_attributes;
+        wcc_data        linkdir_wcc;
+};
+
+struct LINK3resfail {
+        post_op_attr    file_attributes;
+        wcc_data        linkdir_wcc;
+};
+
+union LINK3res switch (nfsstat3 status) {
+case NFS3_OK:
+        LINK3resok resok;
+default:
+        LINK3resfail resfail;
+};
+
+struct READDIR3args {
+        nfs_fh3         dir;
+        cookie3         cookie;
+        cookieverf3     cookieverf;
+        count3          count;
+};
+
+struct entry3 {
+        fileid3         fileid;
+        filename3       name;
+        cookie3         cookie;
+        entry3         *nextentry;
+};
+
+struct dirlist3 {
+        entry3         *entries;
+        bool            eof;
+};
+
+struct READDIR3resok {
+        post_op_attr    dir_attributes;
+        cookieverf3     cookieverf;
+        dirlist3        reply;
+};
+
+struct READDIR3resfail {
+        post_op_attr    dir_attributes;
+};
+
+union READDIR3res switch (nfsstat3 status) {
+case NFS3_OK:
+        READDIR3resok resok;
+default:
+        READDIR3resfail resfail;
+};
+
+struct READDIRPLUS3args {
+        nfs_fh3         dir;
+        cookie3         cookie;
+        cookieverf3     cookieverf;
+        count3          dircount;
+        count3          maxcount;
+};
+
+struct entryplus3 {
+        fileid3         fileid;
+        filename3       name;
+        cookie3         cookie;
+        post_op_attr    name_attributes;
+        post_op_fh3     name_handle;
+        entryplus3     *nextentry;
+};
+
+struct dirlistplus3 {
+        entryplus3     *entries;
+        bool            eof;
+};
+
+struct READDIRPLUS3resok {
+        post_op_attr    dir_attributes;
+        cookieverf3     cookieverf;
+        dirlistplus3    reply;
+};
+
+struct READDIRPLUS3resfail {
+        post_op_attr    dir_attributes;
+};
+
+union READDIRPLUS3res switch (nfsstat3 status) {
+case NFS3_OK:
+        READDIRPLUS3resok resok;
+default:
+        READDIRPLUS3resfail resfail;
+};
+
+struct FSSTAT3args {
+        nfs_fh3         fsroot;
+};
+
+struct FSSTAT3resok {
+        post_op_attr    obj_attributes;
+        size3           tbytes;
+        size3           fbytes;
+        size3           abytes;
+        size3           tfiles;
+        size3           ffiles;
+        size3           afiles;
+        uint32          invarsec;
+};
+
+struct FSSTAT3resfail {
+        post_op_attr    obj_attributes;
+};
+
+union FSSTAT3res switch (nfsstat3 status) {
+case NFS3_OK:
+        FSSTAT3resok resok;
+default:
+        FSSTAT3resfail resfail;
+};
+
+const           FSF3_LINK = 0x0001;
+const           FSF3_SYMLINK = 0x0002;
+const           FSF3_HOMOGENEOUS = 0x0008;
+const           FSF3_CANSETTIME = 0x0010;
+
+struct FSINFOargs {
+        nfs_fh3         fsroot;
+};
+
+struct FSINFO3resok {
+        post_op_attr    obj_attributes;
+        uint32          rtmax;
+        uint32          rtpref;
+        uint32          rtmult;
+        uint32          wtmax;
+        uint32          wtpref;
+        uint32          wtmult;
+        uint32          dtpref;
+        size3           maxfilesize;
+        nfstime3        time_delta;
+        uint32          properties;
+};
+
+struct FSINFO3resfail {
+        post_op_attr    obj_attributes;
+};
+
+union FSINFO3res switch (nfsstat3 status) {
+case NFS3_OK:
+        FSINFO3resok resok;
+default:
+        FSINFO3resfail resfail;
+};
+
+struct PATHCONF3args {
+        nfs_fh3         object;
+};
+
+struct PATHCONF3resok {
+        post_op_attr    obj_attributes;
+        uint32          linkmax;
+        uint32          name_max;
+        bool            no_trunc;
+        bool            chown_restricted;
+        bool            case_insensitive;
+        bool            case_preserving;
+};
+
+struct PATHCONF3resfail {
+        post_op_attr    obj_attributes;
+};
+
+union PATHCONF3res switch (nfsstat3 status) {
+case NFS3_OK:
+        PATHCONF3resok resok;
+default:
+        PATHCONF3resfail resfail;
+};
+
+struct COMMIT3args {
+        nfs_fh3         file;
+        offset3         offset;
+        count3          count;
+};
+
+struct COMMIT3resok {
+        wcc_data        file_wcc;
+        writeverf3      verf;
+};
+
+struct COMMIT3resfail {
+        wcc_data        file_wcc;
+};
+
+union COMMIT3res switch (nfsstat3 status) {
+case NFS3_OK:
+        COMMIT3resok resok;
+default:
+        COMMIT3resfail resfail;
+};
+
+program         NFS_PROGRAM {
+        version         NFS_V3 {
+
+                void
+                NFSPROC3_NULL(void) = 0;
+
+                GETATTR3res
+                NFSPROC3_GETATTR(GETATTR3args) = 1;
+
+                SETATTR3res
+                NFSPROC3_SETATTR(SETATTR3args) = 2;
+
+                LOOKUP3res
+                NFSPROC3_LOOKUP(LOOKUP3args) = 3;
+
+                ACCESS3res
+                NFSPROC3_ACCESS(ACCESS3args) = 4;
+
+                READLINK3res
+                NFSPROC3_READLINK(READLINK3args) = 5;
+
+                READ3res
+                NFSPROC3_READ(READ3args) = 6;
+
+                WRITE3res
+                NFSPROC3_WRITE(WRITE3args) = 7;
+
+                CREATE3res
+                NFSPROC3_CREATE(CREATE3args) = 8;
+
+                MKDIR3res
+                NFSPROC3_MKDIR(MKDIR3args) = 9;
+
+                SYMLINK3res
+                NFSPROC3_SYMLINK(SYMLINK3args) = 10;
+
+                MKNOD3res
+                NFSPROC3_MKNOD(MKNOD3args) = 11;
+
+                REMOVE3res
+                NFSPROC3_REMOVE(REMOVE3args) = 12;
+
+                RMDIR3res
+                NFSPROC3_RMDIR(RMDIR3args) = 13;
+
+                RENAME3res
+                NFSPROC3_RENAME(RENAME3args) = 14;
+
+                LINK3res
+                NFSPROC3_LINK(LINK3args) = 15;
+
+                READDIR3res
+                NFSPROC3_READDIR(READDIR3args) = 16;
+
+                READDIRPLUS3res
+                NFSPROC3_READDIRPLUS(READDIRPLUS3args) = 17;
+
+                FSSTAT3res
+                NFSPROC3_FSSTAT(FSSTAT3args) = 18;
+
+                FSINFO3res
+                NFSPROC3_FSINFO(FSINFO3args) = 19;
+
+                PATHCONF3res
+                NFSPROC3_PATHCONF(PATHCONF3args) = 20;
+
+                COMMIT3res
+                NFSPROC3_COMMIT(COMMIT3args) = 21;
+        } = 3;
+} = 100003;
nfs4.1/xdrdef/portmap.x new file +51 -0
new file mode 100644
index 0000000..1158d4e
@@ -0,0 +1,51 @@
+const PMAP_PORT = 111;      /* portmapper port number */
+
+struct mapping {
+	unsigned int prog;
+	unsigned int vers;
+	unsigned int prot;
+	unsigned int port;
+};
+
+const IPPROTO_TCP = 6;      /* protocol number for TCP/IP */
+const IPPROTO_UDP = 17;     /* protocol number for UDP/IP */
+
+struct pmaplist {
+	mapping map;
+	pmaplist next;
+};
+
+struct call_args {
+	unsigned int prog;
+	unsigned int vers;
+	unsigned int proc;
+	opaque args<>;
+};
+
+struct call_result {
+	unsigned int port;
+	opaque res<>;
+};
+
+program PMAP_PROG {
+	version PMAP_VERS {
+		void
+		PMAPPROC_NULL(void)         = 0;
+
+		bool
+		PMAPPROC_SET(mapping)       = 1;
+
+		bool
+		PMAPPROC_UNSET(mapping)     = 2;
+
+		unsigned int
+		PMAPPROC_GETPORT(mapping)   = 3;
+
+		pmaplist
+		PMAPPROC_DUMP(void)         = 4;
+
+		call_result
+		PMAPPROC_CALLIT(call_args)  = 5;
+	} = 2;
+} = 100000;
+
Signature · 1 line
1.8.5.2 (Apple Git-48)
#23 lore raw

PATCH 13/17 dataserver: separate generic and 4.1 code

In reply to Weston Andros Adamson
---
 nfs4.1/dataserver.py | 99 ++++++++++++++++++++++++++++------------------------
 1 file changed, 54 insertions(+), 45 deletions(-)
nfs4.1/dataserver.py +54 -45
index c73e195..40364d4 100644
@@ -15,7 +15,7 @@ log = logging.getLogger("Dataserver Manager")
 
 op4 = nfs_ops.NFS4ops()
 
-class DataServer41(object):
+class DataServer(object):
     def __init__(self, server, port, path, flavor=rpc.AUTH_SYS, active=True, mdsds=True, multipath_servers=None, summary=None):
         self.mdsds = mdsds
         self.server = server
@@ -43,28 +43,44 @@ class DataServer41(object):
         self.active = True
         if not self.mdsds:
             self.connect()
+            self.make_root()
 
     def down(self):
+        self.disconnect()
         self.active = False
 
-    def connect(self):
-        # only support root with AUTH_SYS for now
-        s1 = rpc.security.instance(rpc.AUTH_SYS)
-        self.cred1 = s1.init_cred(uid=0, gid=0)
-        self.c1 = nfs4client.NFS4Client(self.server, self.port,
-                                        summary=self.summary)
-        self.c1.set_cred(self.cred1)
-        self.c1.null()
-        c = self.c1.new_client("DS.init_%s" % self.server)
-        # This is a hack to ensure MDS/DS communication path is at least
-        # as wide as the client/MDS channel (at least for linux client)
-        fore_attrs = type4.channel_attrs4(0, 16384, 16384, 2868, 8, 8, [])
-        self.sess = c.create_session(fore_attrs=fore_attrs)
-        self.make_root()
+    def reset(self):
+        self.down()
+        self.up()
+
+    def get_netaddr4(self):
+        # STUB server multipathing not supported yet
+        uaddr = '.'.join([self.server,
+                          str(self.port >> 8),
+                          str(self.port & 0xff)])
+        return type4.netaddr4(self.proto, uaddr)
+
+    def get_multipath_netaddr4s(self):
+        netaddr4s = []
+        for addr in self.multipath_servers:
+            server, port = addr
+            uaddr = '.'.join([server,
+                            str(port >> 8),
+                            str(port & 0xff)])
+            proto = "tcp"
+            if server.find(':') >= 0:
+                proto = "tcp6"
+
+            netaddr4s.append(type4.netaddr4(proto, uaddr))
+        return netaddr4s
+
+    def fh_to_name(self, mds_fh):
+        return hashlib.sha1("%r" % mds_fh).hexdigest()
 
     def disconnect(self):
         pass
 
+class DataServer41(DataServer):
     def _execute(self, ops, exceptions=[], delay=5, maxretries=3):
         """ execute the NFS call
         If an error code is specified in the exceptions it means that the
@@ -85,36 +101,28 @@ class DataServer41(object):
                     log.error("Too many retries with DS %s" % self.server)
                     raise Exception("Dataserver communication retry error")
             elif res.status in state_errors:
-                self.disconnect()
-                self.connect()
+                self.reset()
             else:
                 log.error("Unhandled status %s from DS %s" %
                           (nfsstat4[res.status], self.server))
                 raise Exception("Dataserver communication error")
 
-    def get_netaddr4(self):
-        # STUB server multipathing not supported yet
-        uaddr = '.'.join([self.server,
-                          str(self.port >> 8),
-                          str(self.port & 0xff)])
-        return type4.netaddr4(self.proto, uaddr)
-
-    def get_multipath_netaddr4s(self):
-        netaddr4s = []
-        for addr in self.multipath_servers:
-            server, port = addr
-            uaddr = '.'.join([server,
-                            str(port >> 8),
-                            str(port & 0xff)])
-            proto = "tcp"
-            if server.find(':') >= 0:
-                proto = "tcp6"
-
-            netaddr4s.append(type4.netaddr4(proto, uaddr))
-        return netaddr4s
-
+    def connect(self):
+        # only support root with AUTH_SYS for now
+        s1 = rpc.security.instance(rpc.AUTH_SYS)
+        self.cred1 = s1.init_cred(uid=0, gid=0)
+        self.c1 = nfs4client.NFS4Client(self.server, self.port,
+                                        summary=self.summary)
+        self.c1.set_cred(self.cred1)
+        self.c1.null()
+        c = self.c1.new_client("DS.init_%s" % self.server)
+        # This is a hack to ensure MDS/DS communication path is at least
+        # as wide as the client/MDS channel (at least for linux client)
+        fore_attrs = type4.channel_attrs4(0, 16384, 16384, 2868, 8, 8, [])
+        self.sess = c.create_session(fore_attrs=fore_attrs)
 
-    def make_root(self, attrs={const4.FATTR4_MODE:0777}):
+    def make_root(self):
+        attrs = {const4.FATTR4_MODE:0777}
         existing_path = []
         kind = type4.createtype4(const4.NF4DIR)
         for comp in self.path:
@@ -133,12 +141,13 @@ class DataServer41(object):
             raise RuntimeError
         # XXX clean DS directory
 
-    def fh_to_name(self, mds_fh):
-        return hashlib.sha1("%r" % mds_fh).hexdigest()
-
-    def open_file(self, mds_fh, seqid=0,
-                  access=const4.OPEN4_SHARE_ACCESS_BOTH, deny=const4.OPEN4_SHARE_DENY_NONE,
-                  attrs={const4.FATTR4_MODE: 0777}, owner = "mds", mode=const4.GUARDED4):
+    def open_file(self, mds_fh):
+        seqid=0
+        access = const4.OPEN4_SHARE_ACCESS_BOTH
+        deny = const4.OPEN4_SHARE_DENY_NONE
+        attrs = {const4.FATTR4_MODE: 0777}
+        owner = "mds"
+        mode = const4.GUARDED4
         verifier = self.sess.c.verifier
         openflag = type4.openflag4(const4.OPEN4_CREATE, type4.createhow4(mode, attrs, verifier))
         name = self.fh_to_name(mds_fh)
Signature · 1 line
1.8.5.2 (Apple Git-48)
#24 lore raw

PATCH 14/17 4.1 server: add support for NFSv3 data servers

In reply to Weston Andros Adamson

Add the NFSv3 client and a new DataServer class that handles DS ops using the v3 client.

DataServer3 is not used yet, as it requires flexfile layouts in order to pass a v3 DS to clients.

Tested with linux client mounting pnfs MDS via v4.1 (disabling pnfs) and a linux server acting as the v3 DS.

---
 nfs4.1/dataserver.py | 100 ++++++++++++++++++++++++++++
 nfs4.1/nfs3client.py | 180 +++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 280 insertions(+)
 create mode 100644 nfs4.1/nfs3client.py
nfs4.1/dataserver.py +100 -0
index 40364d4..0fcd820 100644
@@ -3,9 +3,12 @@ import nfs4lib
 import xdrdef.nfs4_type as type4
 from xdrdef.nfs4_pack import NFS4Packer
 import xdrdef.nfs4_const as const4
+import xdrdef.nfs3_type as type3
+import xdrdef.nfs3_const as const3
 import time
 import logging
 import nfs4client
+import nfs3client
 import hashlib
 import sys
 import nfs_ops
@@ -14,6 +17,7 @@ import socket
 log = logging.getLogger("Dataserver Manager")
 
 op4 = nfs_ops.NFS4ops()
+op3 = nfs_ops.NFS3ops()
 
 class DataServer(object):
     def __init__(self, server, port, path, flavor=rpc.AUTH_SYS, active=True, mdsds=True, multipath_servers=None, summary=None):
@@ -203,6 +207,102 @@ class DataServer41(DataServer):
         attrdict = res.resarray[-1].obj_attributes
         return attrdict.get(const4.FATTR4_SIZE, 0)
 
+class DataServer3(DataServer):
+    def _execute(self, procnum, procarg, exceptions=(), delay=5, maxretries=3):
+        """ execute the NFS call
+        If an error code is specified in the exceptions it means that the
+        caller wants to handle the error himself
+        """
+        retry_errors = []
+        while True:
+            res = self.c1.proc(procnum, procarg)
+            if res.status == const3.NFS3_OK or res.status in exceptions:
+                return res
+            elif res.status in retry_errors:
+                if maxretries > 0:
+                    maxretries -= 1
+                    time.sleep(delay)
+                else:
+                    log.error("Too many retries with DS %s" % self.server)
+                    raise Exception("Dataserver communication retry error")
+            else:
+                log.error("Unhandled status %s from DS %s" %
+                          (const3.nfsstat3[res.status], self.server))
+                raise Exception("Dataserver communication error")
+
+    def connect(self):
+        # only support root with AUTH_SYS for now
+        s1 = rpc.security.instance(rpc.AUTH_SYS)
+        self.cred1 = s1.init_cred(uid=0, gid=0)
+        self.c1 = nfs3client.NFS3Client(self.server, self.port,
+                                        summary=self.summary)
+        self.c1.set_cred(self.cred1)
+        self.rootfh = type3.nfs_fh3(self.c1.mntclnt.get_rootfh(self.path))
+        self.c1.null()
+
+    def make_root(self):
+        """ don't actually make a root path - we must use it as the export """
+        need = const3.ACCESS3_READ | const3.ACCESS3_LOOKUP | \
+               const3.ACCESS3_MODIFY | const3.ACCESS3_EXTEND
+        arg = op3.access(self.rootfh, need)
+        res = self._execute(const3.NFSPROC3_ACCESS, arg)
+        if res.resok.access != need:
+            raise RuntimeError
+        # XXX clean DS directory
+
+    def open_file(self, mds_fh):
+        name = self.fh_to_name(mds_fh)
+        where = type3.diropargs3(self.rootfh, name)
+        attr = type3.sattr3(mode=type3.set_mode3(True, 0777),
+                            uid=type3.set_uid3(True, 0),
+                            gid=type3.set_gid3(True, 0),
+                            size=type3.set_size3(False),
+                            atime=type3.set_atime(False),
+                            mtime=type3.set_mtime(False))
+        how = type3.createhow3(const3.GUARDED, attr)
+        arg = op3.create(where, how)
+        res = self._execute(const3.NFSPROC3_CREATE, arg,
+                            exceptions=(const3.NFS3ERR_EXIST,))
+
+        if res.status == const3.NFS3_OK:
+            self.filehandles[mds_fh] = (res.resok.obj.handle, None)
+
+        else:
+            arg = op3.lookup(type3.diropargs3(self.rootfh, name))
+            res = self._execute(const3.NFSPROC3_LOOKUP, arg)
+
+            self.filehandles[mds_fh] = (res.resok.object, None)
+
+    def close_file(self, mds_fh):
+        del self.filehandles[mds_fh]
+
+    def read(self, fh, pos, count):
+        arg = op3.read(fh, pos, count)
+        res = self._execute(const3.NFSPROC3_READ, arg)
+        # XXX check res.status?
+        return res.resok.data
+
+    def write(self, fh, pos, data):
+        arg = op3.write(fh, pos, len(data), const3.FILE_SYNC, data)
+        # There are all sorts of error handling issues here
+        res = self._execute(const3.NFSPROC3_WRITE, arg)
+
+    def truncate(self, fh, size):
+        attr = type3.sattr3(mode=type3.set_mode3(False),
+                            uid=type3.set_uid3(False),
+                            gid=type3.set_gid3(False),
+                            size=type3.set_size3(True, size),
+                            atime=type3.set_atime(False),
+                            mtime=type3.set_mtime(False))
+        arg = op3.setattr(fh, attr, type3.sattrguard3(check=False))
+        res = self._execute(const3.NFSPROC3_SETATTR, arg)
+
+    def get_size(self, fh):
+        arg = op3.getattr(fh)
+        res = self._execute(const3.NFSPROC3_GETATTR, arg)
+        # XXX check res.status?
+        return res.resok.obj_attributes.size
+
 
 class DSDevice(object):
     def __init__(self, mdsds):
nfs4.1/nfs3client.py new file +180 -0

180 lines not on this page · raw message

Signature · 1 line
1.8.5.2 (Apple Git-48)
#25 lore raw

PATCH 15/17 4.1 server: get rid of old op_getdeviceinfo

In reply to Weston Andros Adamson

This has been commented out for a while.

---
 nfs4.1/nfs4server.py | 21 ---------------------
 1 file changed, 21 deletions(-)
nfs4.1/nfs4server.py +0 -21
index 088e8c4..594e9d5 100755
@@ -1870,27 +1870,6 @@ class NFS4Server(rpc.Server):
                                   new_cookie >= len(list))
         return encode_status(NFS4_OK, res)
 
-#     def op_getdeviceinfo(self, arg, env): # STUB
-#         check_session(env)
-#         # check_cfh(env)
-#         # fs = env.cfh.fs
-#         # STUB - only deals with block volumes
-#         kind = arg.gdia_layout_type
-#         if kind != LAYOUT4_BLOCK_VOLUME:
-#             return encode_status(NFS4ERR_INVAL)
-#         # STUB - want to pull this from fs, not block module
-#         d = block.devices.get(arg.gdia_device_id, None)
-#         if d is None:
-#             return encode_status(NFS4ERR_INVAL)
-#         address = device_addr4(LAYOUT4_BLOCK_VOLUME, d.get_addr())
-#         # Check that we don't exceed count
-#         p = nfs4lib.FancyNFS4Packer()
-#         p.pack_device_addr4(address)
-#         if len(p.get_buffer()) > arg.gdia_maxcount:
-#             return encode_status(NFS4ERR_TOOSMALL, gdir_mincount = len(p.get_buffer()))
-#         res = GETDEVICEINFO4resok(address, 0)
-#         return encode_status(NFS4_OK, res)
-
     def op_getdeviceinfo(self, arg, env): # STUB
         # STUB - ignoring notifications
         check_session(env)
Signature · 1 line
1.8.5.2 (Apple Git-48)
#26 lore raw

PATCH 15/17 nfs41 svr: get rid of old op_getdeviceinfo

In reply to Weston Andros Adamson

This has been commented out for a while.

---
 nfs4.1/nfs4server.py | 21 ---------------------
 1 file changed, 21 deletions(-)
nfs4.1/nfs4server.py +0 -21
index 062e3c4..27e2352 100755
@@ -1870,27 +1870,6 @@ class NFS4Server(rpc.Server):
                                   new_cookie >= len(list))
         return encode_status(NFS4_OK, res)
 
-#     def op_getdeviceinfo(self, arg, env): # STUB
-#         check_session(env)
-#         # check_cfh(env)
-#         # fs = env.cfh.fs
-#         # STUB - only deals with block volumes
-#         kind = arg.gdia_layout_type
-#         if kind != LAYOUT4_BLOCK_VOLUME:
-#             return encode_status(NFS4ERR_INVAL)
-#         # STUB - want to pull this from fs, not block module
-#         d = block.devices.get(arg.gdia_device_id, None)
-#         if d is None:
-#             return encode_status(NFS4ERR_INVAL)
-#         address = device_addr4(LAYOUT4_BLOCK_VOLUME, d.get_addr())
-#         # Check that we don't exceed count
-#         p = nfs4lib.FancyNFS4Packer()
-#         p.pack_device_addr4(address)
-#         if len(p.get_buffer()) > arg.gdia_maxcount:
-#             return encode_status(NFS4ERR_TOOSMALL, gdir_mincount = len(p.get_buffer()))
-#         res = GETDEVICEINFO4resok(address, 0)
-#         return encode_status(NFS4_OK, res)
-
     def op_getdeviceinfo(self, arg, env): # STUB
         # STUB - ignoring notifications
         check_session(env)
Signature · 1 line
1.8.5.2 (Apple Git-48)
#27 lore raw

PATCH 16/17 rpc: on socket error, close and mark pipe inactive

In reply to Weston Andros Adamson

call _event_close() on socket errors instead of tracing back and mark the pipe as inactive so callers can reconnect as needed.

---
 rpc/rpc.py | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)
rpc/rpc.py +23 -3
index 250e945..4801883 100644
@@ -351,6 +351,7 @@ class RpcPipe(Pipe):
         self._pending = {} # {xid:defer}
         self._lock = threading.Lock() # Protects fields below
         self._xid = 0
+        self.set_active()
 
     def _get_xid(self):
         with self._lock:
@@ -358,6 +359,15 @@ class RpcPipe(Pipe):
             self._xid = inc_u32(out)
         return out
 
+    def set_active(self):
+        self._active = True
+
+    def clear_active(self):
+        self._active = False
+
+    def is_active(self):
+        return self._active
+
     def listen(self, xid, timeout=None):
         """Wait for a reply to a CALL."""
         self._pending[xid].wait(timeout)
@@ -500,15 +510,24 @@ class ConnectionHandler(object):
                 log_p.warn(1, "polling error from %i" % fd)
                 # STUB - now what?
             for fd in w:
-                self._event_write(fd)
+                try:
+                    self._event_write(fd)
+                except socket.error, e:
+                    self._event_close(fd)
             for fd in r:
                 if fd in self.listeners:
-                    self._event_connect_incoming(fd)
+                    try:
+                        self._event_connect_incoming(fd)
+                    except socket.error, e:
+                        self._event_close(fd)
                 elif fd == self._alarm_poll.fileno():
                     commands = self._alarm_poll.recv(self.rsize)
                     for c in commands:
                         data = self._alarm.pop()
-                        switch[c](data)
+                        try:
+                            switch[c](data)
+                        except socket.error, e:
+                            self._event_close(fd)
                 else:
                     try:
                         data = self.sockets[fd].recv_records(self.rsize)
@@ -557,6 +576,7 @@ class ConnectionHandler(object):
         self.writelist -= temp
         self.readlist -= temp
         self.errlist -= temp
+        self.sockets[fd].clear_active()
         self.sockets[fd].close()
         del self.sockets[fd]
 
Signature · 1 line
1.8.5.2 (Apple Git-48)
#28 lore raw

PATCH 17/17 nfs3clnt: reconnect when sending on inactive pipe

In reply to Weston Andros Adamson
---
 nfs4.1/nfs3client.py | 45 +++++++++++++++++++++++++--------------------
 1 file changed, 25 insertions(+), 20 deletions(-)
nfs4.1/nfs3client.py +25 -20
index 79a6f0e..176765c 100644
@@ -30,14 +30,19 @@ class PORTMAPClient(rpc.Client):
     def __init__(self, host='localhost', port=PMAP_PORT):
         rpc.Client.__init__(self, PMAP_PROG, PMAP_VERS)
         self.server_address = (host, port)
-        self.c1 = self.connect(self.server_address)
+        self._pipe = None
+
+    def get_pipe(self):
+        if not self._pipe or not self._pipe.is_active():
+           self._pipe = self.connect(self.server_address)
+        return self._pipe
 
     def proc_async(self, procnum, procarg, credinfo=None, pipe=None,
                    checks=True, packer=PORTMAPPacker):
         if credinfo is None:
             credinfo = self.default_cred
         if pipe is None:
-            pipe = self.c1
+            pipe = self.get_pipe()
         p = packer(check_enum=checks, check_array=checks)
         arg_packer = getattr(p, 'pack_%s' % procarg.__class__.__name__)
         arg_packer(procarg)
@@ -51,7 +56,7 @@ class PORTMAPClient(rpc.Client):
 
     def listen(self, xid, restypename, pipe=None, timeout=10.0):
         if pipe is None:
-            pipe = self.c1
+            pipe = self.get_pipe()
         header, data = pipe.listen(xid, timeout)
         if data:
             p = PORTMAPUnpacker(data)
@@ -69,14 +74,19 @@ class Mnt3Client(rpc.Client):
     def __init__(self, host='localhost', port=None):
         rpc.Client.__init__(self, MOUNT_PROGRAM, MOUNT_V3)
         self.server_address = (host, port)
-        self.c1 = self.connect(self.server_address)
+        self._pipe = None
+
+    def get_pipe(self):
+        if not self._pipe or not self._pipe.is_active():
+            self._pipe = self.connect(self.server_address)
+        return self._pipe
 
     def proc_async(self, procnum, procarg, credinfo=None, pipe=None,
                    checks=True, packer=MNT3Packer):
         if credinfo is None:
             credinfo = self.default_cred
         if pipe is None:
-            pipe = self.c1
+            pipe = self.get_pipe()
         p = packer(check_enum=checks, check_array=checks)
         arg_packer = getattr(p, 'pack_%s' % procarg.__class__.__name__)
         arg_packer(procarg)
@@ -90,7 +100,7 @@ class Mnt3Client(rpc.Client):
 
     def listen(self, xid, restypename, pipe=None, timeout=10.0):
         if pipe is None:
-            pipe = self.c1
+            pipe = self.get_pipe()
         header, data = pipe.listen(xid, timeout)
         if data:
             p = MNT3Unpacker(data)
@@ -110,15 +120,6 @@ class Mnt3Client(rpc.Client):
 class NFS3Client(rpc.Client):
     def __init__(self, host='localhost', port=None, ctrl_proc=16, summary=None):
         rpc.Client.__init__(self, 100003, 3)
-        #self.prog = 0x40000000
-        #self.versions = [1] # List of supported versions of prog
-
-        #self.minorversion = minorversion
-        #self.minor_versions = [minorversion]
-        #self.tag = "default tag"
-        #self.impl_id = nfs_impl_id4("citi.umich.edu", "pynfs X.X",
-        #                            nfs4lib.get_nfstime())
-
         self.portmap = PORTMAPClient(host=host)
         self.mntport = self.portmap.get_port(MOUNT_PROGRAM, MOUNT_V3)
         if not port:
@@ -128,17 +129,21 @@ class NFS3Client(rpc.Client):
 
         self.verifier = struct.pack('>d', time.time())
         self.server_address = (host, self.port)
-        self.c1 = self.connect(self.server_address)
-        #self.sessions = {} # XXX Really, this should be per server
         self.ctrl_proc = ctrl_proc
         self.summary = summary
+        self._pipe = None
         self.mntclnt = Mnt3Client(host=host, port=self.mntport)
 
+    def get_pipe(self):
+        if not self._pipe or not self._pipe.is_active():
+            self._pipe = self.connect(self.server_address)
+        return self._pipe
+
     def set_cred(self, credinfo):
         self.default_cred = credinfo
 
     def null_async(self, data=""):
-        return self.send_call(self.c1, 0, data)
+        return self.send_call(self.get_pipe(), 0, data)
 
     def null(self, *args, **kwargs):
         xid = self.null_async(*args, **kwargs)
@@ -149,7 +154,7 @@ class NFS3Client(rpc.Client):
         if credinfo is None:
             credinfo = self.default_cred
         if pipe is None:
-            pipe = self.c1
+            pipe = self.get_pipe()
         p = packer(check_enum=checks, check_array=checks)
         arg_packer = getattr(p, 'pack_%s' % procarg.__class__.__name__)
         arg_packer(procarg)
@@ -167,7 +172,7 @@ class NFS3Client(rpc.Client):
 
     def listen(self, xid, procarg=None, pipe=None, timeout=10.0):
         if pipe is None:
-            pipe = self.c1
+            pipe = self.get_pipe()
         header, data = pipe.listen(xid, timeout)
         if data:
             p = NFS3Unpacker(data)
Signature · 1 line
1.8.5.2 (Apple Git-48)

A message that is not in the archive (sent off-list or not yet received): [email protected]

#30 lore raw

Re: [PATCH pynfs 05/17] move .x files to subdir 'xdrdef'

Quoted 1 line · Weston Andros Adamson
 nfs4.1/nfs4.x                               | 3290 ---------------------------

...

Quoted 1 line
 nfs4.1/xdrdef/nfs4.x                        | 3290 +++++++++++++++++++++++++++

git should be able to show that as a rename instead of a huge add/delete pair. Maybe git-format-patch needs the -M option or something?

--b.

#31 lore raw

Re: [PATCH pynfs 05/17] move .x files to subdir 'xdrdef'

Huh, I didn’t know there was such an option. I’ll repost.

-dros

Quoted 9 lines · J. Bruce Fields
Quoted 1 line · Weston Andros Adamson

nfs4.1/nfs4.x | 3290 ---------------------------

...

Quoted 1 line

nfs4.1/xdrdef/nfs4.x | 3290 +++++++++++++++++++++++++++

git should be able to show that as a rename instead of a huge add/delete pair. Maybe git-format-patch needs the -M option or something?

--b.