Commit fe133689 authored by Tigran Mkrtchyan's avatar Tigran Mkrtchyan
Browse files

nfsv4: pass compound ags as a requext context

Each v4.0 coumpound has a server side 'local variable'
to store current file handle, saved file handle and so on.
With v4.1 and introduction od sessions the number of
'local variable' are increased.

The patch refactors nfsv4 code to keep it simple and
readable.

Acked-By: Gerd
parent ebdfa50c
package org.dcache.chimera.nfs.v4;
import org.dcache.chimera.nfs.v4.xdr.nfs_resop4;
import org.dcache.chimera.nfs.v4.xdr.nfs_argop4;
import org.dcache.chimera.nfs.v4.*;
import org.dcache.xdr.RpcCall;
import org.dcache.chimera.FileSystemProvider;
import org.dcache.chimera.nfs.ExportFile;
import org.dcache.chimera.nfs.v4.xdr.nfs_resop4;
import org.dcache.chimera.posix.AclHandler;
import org.dcache.chimera.posix.UnixPermissionHandler;
/**
*
* NFSv4 operation abstraction
......@@ -20,26 +15,18 @@ public abstract class AbstractNFSv4Operation {
protected final nfs_resop4 _result = new nfs_resop4();
protected final FileSystemProvider _fs;
protected final RpcCall _callInfo;
protected final CompoundArgs _fh;
protected final nfs_argop4 _args;
protected final org.dcache.chimera.posix.UnixUser _user;
protected final ExportFile _exportFile;
protected final nfs_argop4 _args;
protected AclHandler _permissionHandler = UnixPermissionHandler.getInstance();
protected AclHandler _permissionHandler = UnixPermissionHandler.getInstance();
public AbstractNFSv4Operation(FileSystemProvider fs, ExportFile exportFile, RpcCall call$, CompoundArgs fh, nfs_argop4 args, int opCode) {
public AbstractNFSv4Operation(nfs_argop4 args, int opCode) {
_result.resop = opCode;
_fs = fs;
_callInfo = call$;
_fh = fh;
_args = args;
_exportFile = exportFile;
_user = HimeraNFS4Utils.remoteUser(_callInfo, _exportFile);
_args = args;
}
public abstract NFSv4OperationResult process();
/**
* Process current opration.
* @return <code>true</code> if next operration may continue.
*/
public abstract boolean process(CompoundContext context);
}
/*
* $Id:CompoundArgs.java 140 2007-06-07 13:44:55Z tigran $
*/
package org.dcache.chimera.nfs.v4;
import java.util.List;
import org.dcache.chimera.nfs.v4.xdr.nfsstat4;
import org.dcache.chimera.nfs.ChimeraNFSException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.dcache.chimera.FileSystemProvider;
import org.dcache.chimera.FsInode;
import org.dcache.chimera.nfs.ExportFile;
import org.dcache.chimera.nfs.v4.xdr.nfs_resop4;
import org.dcache.chimera.posix.UnixUser;
import org.dcache.xdr.RpcCall;
public class CompoundArgs {
public class CompoundContext {
private static final Logger _log = Logger.getLogger(CompoundArgs.class.getName());
private static final Logger _log = Logger.getLogger(CompoundContext.class.getName());
private FsInode _rootInode = null;
private FsInode _currentInode = null;
private FsInode _savedInode = null;
private final int _minorversion;
private int _position = 0;
private NFSv41Session _session = null;
public CompoundArgs(int minorversion) {
private final List<nfs_resop4> _processedOps;
private final FileSystemProvider _fs;
private final RpcCall _callInfo;
private final UnixUser _user;
private final ExportFile _exportFile;
/**
* Create context of COUMPOUND request.
*
* @param processedOps @{link List} wnere results of processed operations are stored.
* @param minorversion NFSv4 minor version number.
* @param fs backend file-system interface
* @param call RPC call
* @param exportFile list of servers exports.
*/
public CompoundContext(List<nfs_resop4> processedOps, int minorversion, FileSystemProvider fs,
RpcCall call, ExportFile exportFile) {
_processedOps = processedOps;
_minorversion = minorversion;
_fs = fs;
_callInfo = call;
_exportFile = exportFile;
_user = HimeraNFS4Utils.remoteUser(_callInfo, _exportFile);
}
public RpcCall getRpcCall() {
return _callInfo;
}
public UnixUser getUser() {
return _user;
}
public FileSystemProvider getFs() {
return _fs;
}
public int getMinorversion() {
return _minorversion;
}
......@@ -75,24 +109,28 @@ public class CompoundArgs {
_savedInode = _currentInode;
_log.log(Level.FINEST, "saved Inode: {0}", _savedInode.toString() );
}
/**
* Set NFSv4.1 session of current request.
* @param session
*/
public void setSession(NFSv41Session session) {
_session = session;
}
/**
* Get {@link NFSv41Session} used by current request.
* @return current session
*/
public NFSv41Session getSession() {
return _session;
}
/**
* the position in compound operation starting from zero
* @return position
* Get list of currently processed operations.
* @return list of operations.
*/
public int position() {
return _position;
}
public void nexPosition() {
_position ++ ;
public List<nfs_resop4> processedOperations() {
return _processedOps;
}
}
......@@ -11,7 +11,7 @@ import org.dcache.chimera.nfs.v4.xdr.COMPOUND4res;
import org.dcache.chimera.nfs.v4.xdr.COMPOUND4args;
import org.dcache.chimera.nfs.ChimeraNFSException;
import java.io.IOException;
import java.util.LinkedList;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
......@@ -51,48 +51,41 @@ public class NFSServerV41 extends nfs4_prot_NFS4_PROGRAM_ServerStub {
new Object[]{call$.getTransport().getRemoteSocketAddress(),
new String(arg1.tag.value.value)});
List<nfs_resop4> v = new LinkedList<nfs_resop4>();
List<nfs_resop4> v = new ArrayList<nfs_resop4>(arg1.argarray.length);
if (arg1.minorversion.value > 1) {
res.status = nfsstat4.NFS4ERR_MINOR_VERS_MISMATCH;
_log.log(Level.FINE, " : NFS4ERR_MINOR_VERS_MISMATCH");
} else {
nfs_argop4[] op = arg1.argarray;
CompoundContext context = new CompoundContext(v, arg1.minorversion.value,
_fs, call$, _exportFile);
for (int i = 0; i < op.length; i++) {
int nfsOp = op[i].argop;
_log.log(Level.FINE, " : {0} #{1}",
new Object[]{NFSv4Call.toString(nfsOp), i});
}
CompoundArgs fh = new CompoundArgs(arg1.minorversion.value);
for (nfs_argop4 op: arg1.argarray) {
for (int i = 0; i < op.length; i++) {
NFSv4OperationResult opRes = NFSv4OperationFactory.getOperation(_fs, call$, fh, op[i], _exportFile).process();
v.add(opRes.getResult());
// result status must be equivalent
// to the status of the last operation that
// was executed within the COMPOUND procedure
res.status = opRes.getStatus();
if (opRes.getStatus() != nfsstat4.NFS4_OK) {
_log.log(Level.FINE, "OP: {1} status: {1}",
new Object[]{NFSv4Call.toString(op[i].argop), res.status});
if( ! NFSv4OperationFactory.getOperation(op).process(context) ) {
break;
}
fh.nexPosition();
}
try {
_log.log(Level.FINE, "CURFH: {0}", fh.currentInode().toFullString());
_log.log(Level.FINE, "CURFH: {0}", context.currentInode().toFullString());
} catch (ChimeraNFSException he) {
_log.fine("CURFH: NULL");
}
v = context.processedOperations();
}
res.tag = arg1.tag;
res.resarray = v.toArray(new nfs_resop4[v.size()]);
// result status must be equivalent
// to the status of the last operation that
// was executed within the COMPOUND procedure
res.status = res.resarray[res.resarray.length-1].getStatus();
_log.log(Level.FINE, "OP: {1} status: {1}", new Object[]{res.tag, res.status});
} catch (Exception e) {
_log.log(Level.SEVERE, "Unhandled exception:", e);
res.resarray = new nfs_resop4[0];
......
......@@ -3,9 +3,6 @@ package org.dcache.chimera.nfs.v4;
import org.dcache.chimera.nfs.v4.xdr.nfs_argop4;
import org.dcache.chimera.nfs.v4.xdr.nfs4_prot;
import org.dcache.chimera.nfs.v4.xdr.nfs_opnum4;
import org.dcache.xdr.RpcCall;
import org.dcache.chimera.FileSystemProvider;
import org.dcache.chimera.nfs.ExportFile;
public class NFSv4OperationFactory {
......@@ -16,82 +13,80 @@ public class NFSv4OperationFactory {
public static AbstractNFSv4Operation getOperation(FileSystemProvider fs,
RpcCall call$, CompoundArgs fh, nfs_argop4 op,
ExportFile exports) {
public static AbstractNFSv4Operation getOperation(nfs_argop4 op) {
switch ( op.argop ) {
case nfs_opnum4.OP_ACCESS:
return new OperationACCESS(fs, call$, fh, op, exports);
return new OperationACCESS(op);
case nfs_opnum4.OP_CLOSE:
return new OperationCLOSE(fs, call$, fh, op, exports);
return new OperationCLOSE(op);
case nfs_opnum4.OP_COMMIT:
return new OperationCOMMIT(fs, call$, fh, op, exports);
return new OperationCOMMIT(op);
case nfs_opnum4.OP_CREATE:
return new OperationCREATE(fs, call$, fh, op, exports);
return new OperationCREATE(op);
case nfs_opnum4.OP_DELEGPURGE:
return new OperationDELEGPURGE(fs, call$, fh, op, exports);
return new OperationDELEGPURGE(op);
case nfs_opnum4.OP_DELEGRETURN:
return new OperationDELEGRETURN(fs, call$, fh, op, exports);
return new OperationDELEGRETURN(op);
case nfs_opnum4.OP_GETATTR:
return new OperationGETATTR(fs, call$, fh, op, exports);
return new OperationGETATTR(op);
case nfs_opnum4.OP_GETFH:
return new OperationGETFH(fs, call$, fh, op, exports);
return new OperationGETFH(op);
case nfs_opnum4.OP_LINK:
return new OperationLINK(fs, call$, fh, op, exports);
return new OperationLINK(op);
case nfs_opnum4.OP_LOCK:
return new OperationLOCK(fs, call$, fh, op, exports);
return new OperationLOCK(op);
case nfs_opnum4.OP_LOCKT:
return new OperationLOCKT(fs, call$, fh, op, exports);
return new OperationLOCKT(op);
case nfs_opnum4.OP_LOCKU:
return new OperationLOCKU(fs, call$, fh, op, exports);
return new OperationLOCKU(op);
case nfs_opnum4.OP_LOOKUP:
return new OperationLOOKUP(fs, call$, fh, op, exports);
return new OperationLOOKUP(op);
case nfs_opnum4.OP_LOOKUPP:
return new OperationLOOKUPP(fs, call$, fh, op, exports);
return new OperationLOOKUPP(op);
case nfs_opnum4.OP_NVERIFY:
return new OperationNVERIFY(fs, call$, fh, op, exports);
return new OperationNVERIFY(op);
case nfs_opnum4.OP_OPEN:
return new OperationOPEN(fs, call$, fh, op, exports);
return new OperationOPEN(op);
case nfs_opnum4.OP_OPENATTR:
return new OperationOPENATTR(fs, call$, fh, op, exports);
return new OperationOPENATTR(op);
case nfs_opnum4.OP_OPEN_CONFIRM:
return new OperationOPEN_CONFIRM(fs, call$, fh, op, exports);
return new OperationOPEN_CONFIRM(op);
case nfs_opnum4.OP_OPEN_DOWNGRADE:break;
case nfs_opnum4.OP_PUTFH:
return new OperationPUTFH(fs, call$, fh, op, exports);
return new OperationPUTFH(op);
case nfs_opnum4.OP_PUTPUBFH:
return new OperationPUTPUBFH(fs, call$, fh, op, exports);
return new OperationPUTPUBFH(op);
case nfs_opnum4.OP_PUTROOTFH:
return new OperationPUTROOTFH(fs, call$, fh, op, exports);
return new OperationPUTROOTFH(op);
case nfs_opnum4.OP_READ:
return new OperationREAD(fs, call$, fh, op, exports);
return new OperationREAD(op);
case nfs_opnum4.OP_READDIR:
return new OperationREADDIR(fs, call$, fh, op, exports);
return new OperationREADDIR(op);
case nfs_opnum4.OP_READLINK:
return new OperationREADLINK(fs, call$, fh, op, exports);
return new OperationREADLINK(op);
case nfs_opnum4.OP_REMOVE:
return new OperationREMOVE(fs, call$, fh, op, exports);
return new OperationREMOVE(op);
case nfs_opnum4.OP_RENAME:
return new OperationRENAME(fs, call$, fh, op, exports);
return new OperationRENAME(op);
case nfs_opnum4.OP_RENEW:
return new OperationRENEW(fs, call$, fh, op, exports);
return new OperationRENEW(op);
case nfs_opnum4.OP_RESTOREFH:
return new OperationRESTOREFH(fs, call$, fh, op, exports);
return new OperationRESTOREFH(op);
case nfs_opnum4.OP_SAVEFH:
return new OperationSAVEFH(fs, call$, fh, op, exports);
return new OperationSAVEFH(op);
case nfs_opnum4.OP_SECINFO:
return new OperationSECINFO(fs, call$, fh, op, exports);
return new OperationSECINFO(op);
case nfs_opnum4.OP_SETATTR:
return new OperationSETATTR(fs, call$, fh, op, exports);
return new OperationSETATTR(op);
case nfs_opnum4.OP_SETCLIENTID:
return new OperationSETCLIENTID(fs, call$, fh, op, exports);
return new OperationSETCLIENTID(op);
case nfs_opnum4.OP_SETCLIENTID_CONFIRM:
return new OperationSETCLIENTID_CONFIRM(fs, call$, fh, op, exports);
return new OperationSETCLIENTID_CONFIRM(op);
case nfs_opnum4.OP_VERIFY:
return new OperationVERIFY(fs, call$, fh, op, exports);
return new OperationVERIFY(op);
case nfs_opnum4.OP_WRITE:
return new OperationWRITE(fs, call$, fh, op, exports);
return new OperationWRITE(op);
/* case nfs_opnum4.OP_RELEASE_LOCKOWNER:
nRes.oprelease_lockowner = new RELEASE_LOCKOWNER4res();
res = new NFSv4OperationResult(nRes, nfsstat4.NFS4ERR_NOTSUPP);
......@@ -102,29 +97,28 @@ public class NFSv4OperationFactory {
*/
case nfs_opnum4.OP_GETDEVICELIST:
return new OperationGETDEVICELIST(fs, call$, fh, op, exports);
return new OperationGETDEVICELIST(op);
case nfs_opnum4.OP_LAYOUTGET:
return new OperationLAYOUTGET(fs, call$, fh, op, exports);
return new OperationLAYOUTGET(op);
case nfs_opnum4.OP_LAYOUTCOMMIT:
return new OperationLAYOUTCOMMIT(fs, call$, fh, op, exports);
return new OperationLAYOUTCOMMIT(op);
case nfs_opnum4.OP_LAYOUTRETURN:
return new OperationLAYOUTRETURN(fs, call$, fh, op, exports);
return new OperationLAYOUTRETURN(op);
case nfs_opnum4.OP_GETDEVICEINFO:
return new OperationGETDEVICEINFO(fs, call$, fh, op, exports);
return new OperationGETDEVICEINFO(op);
case nfs_opnum4.OP_EXCHANGE_ID:
return new OperationEXCHANGE_ID(fs, call$, fh, op, nfs4_prot.EXCHGID4_FLAG_USE_PNFS_MDS, exports);
return new OperationEXCHANGE_ID(op, nfs4_prot.EXCHGID4_FLAG_USE_PNFS_MDS);
case nfs_opnum4.OP_CREATE_SESSION:
return new OperationCREATE_SESSION(fs, call$, fh, op, exports);
return new OperationCREATE_SESSION(op);
case nfs_opnum4.OP_DESTROY_SESSION:
return new OperationDESTROY_SESSION(fs, call$, fh, op, exports);
return new OperationDESTROY_SESSION(op);
case nfs_opnum4.OP_SEQUENCE:
return new OperationSEQUENCE(fs, call$, fh, op, true, exports);
return new OperationSEQUENCE(op, true);
case nfs_opnum4.OP_ILLEGAL:
}
return new OperationILLEGAL(fs, call$, fh, op, exports);
return new OperationILLEGAL(op);
}
......
package org.dcache.chimera.nfs.v4;
import org.dcache.chimera.nfs.v4.xdr.nfs_resop4;
public class NFSv4OperationResult {
final nfs_resop4 _opRes;
final int _status;
public NFSv4OperationResult(nfs_resop4 res, int status) {
_opRes = res;
_status = status;
}
public int getStatus() {
return _status;
}
public nfs_resop4 getResult() {
return _opRes;
}
}
......@@ -8,11 +8,7 @@ import org.dcache.chimera.nfs.v4.xdr.nfs_opnum4;
import org.dcache.chimera.nfs.v4.xdr.ACCESS4res;
import org.dcache.chimera.nfs.v4.xdr.ACCESS4resok;
import org.dcache.chimera.nfs.ChimeraNFSException;
import org.dcache.xdr.RpcCall;
import org.apache.log4j.Logger;
import org.dcache.chimera.FileSystemProvider;
import org.dcache.chimera.JdbcFs;
import org.dcache.chimera.nfs.ExportFile;
import org.dcache.chimera.posix.AclHandler;
import org.dcache.chimera.posix.Stat;
import org.dcache.chimera.posix.UnixAcl;
......@@ -21,59 +17,59 @@ public class OperationACCESS extends AbstractNFSv4Operation {
private static final Logger _log = Logger.getLogger(OperationACCESS.class.getName());
OperationACCESS(FileSystemProvider fs, RpcCall call$, CompoundArgs fh, nfs_argop4 args, ExportFile exports) {
super(fs, exports, call$, fh, args, nfs_opnum4.OP_ACCESS);
OperationACCESS(nfs_argop4 args) {
super(args, nfs_opnum4.OP_ACCESS);
}
@Override
public NFSv4OperationResult process() {
public boolean process(CompoundContext context) {
ACCESS4res res = new ACCESS4res();
if(_log.isDebugEnabled() ) {
_log.debug("NFS Request ACCESS uid: " + _user );
_log.debug("NFS Request ACCESS uid: " + context.getUser() );
}
try {
int reqAccess = _args.opaccess.access.value;
Stat objStat = _fh.currentInode().statCache();
Stat objStat = context.currentInode().statCache();
UnixAcl acl = new UnixAcl(objStat.getUid(), objStat.getGid(),objStat.getMode() & 0777 );
int realAccess = 0;
if( (reqAccess & nfs4_prot.ACCESS4_EXECUTE) == nfs4_prot.ACCESS4_EXECUTE ) {
if ( _permissionHandler.isAllowed(acl, _user, AclHandler.ACL_EXECUTE ) ) {
if ( _permissionHandler.isAllowed(acl, context.getUser(), AclHandler.ACL_EXECUTE ) ) {
realAccess |= nfs4_prot.ACCESS4_EXECUTE;
}
}
if( (reqAccess & nfs4_prot.ACCESS4_EXTEND) == nfs4_prot.ACCESS4_EXTEND ) {
if ( _permissionHandler.isAllowed(acl, _user, AclHandler.ACL_INSERT ) ) {
if ( _permissionHandler.isAllowed(acl, context.getUser(), AclHandler.ACL_INSERT ) ) {
realAccess |= nfs4_prot.ACCESS4_EXTEND;
}
}
if( (reqAccess & nfs4_prot.ACCESS4_LOOKUP) == nfs4_prot.ACCESS4_LOOKUP ) {
if ( _permissionHandler.isAllowed(acl, _user, AclHandler.ACL_LOOKUP ) ) {
if ( _permissionHandler.isAllowed(acl, context.getUser(), AclHandler.ACL_LOOKUP ) ) {
realAccess |= nfs4_prot.ACCESS4_LOOKUP;
}
}
if( (reqAccess & nfs4_prot.ACCESS4_DELETE) == nfs4_prot.ACCESS4_DELETE ) {
if ( _permissionHandler.isAllowed(acl, _user, AclHandler.ACL_DELETE ) ) {
if ( _permissionHandler.isAllowed(acl, context.getUser(), AclHandler.ACL_DELETE ) ) {
realAccess |= nfs4_prot.ACCESS4_DELETE;
}
}
if( (reqAccess & nfs4_prot.ACCESS4_MODIFY) == nfs4_prot.ACCESS4_MODIFY ) {
if ( _permissionHandler.isAllowed(acl, _user, AclHandler.ACL_WRITE ) ){
if ( _permissionHandler.isAllowed(acl, context.getUser(), AclHandler.ACL_WRITE ) ){
realAccess |= nfs4_prot.ACCESS4_MODIFY;
}
}
if( (reqAccess & nfs4_prot.ACCESS4_READ) == nfs4_prot.ACCESS4_READ ) {
if ( _permissionHandler.isAllowed(acl, _user, AclHandler.ACL_READ ) ) {
if ( _permissionHandler.isAllowed(acl, context.getUser(), AclHandler.ACL_READ ) ) {
realAccess |= nfs4_prot.ACCESS4_READ;
}
}
......@@ -95,7 +91,8 @@ public class OperationACCESS extends AbstractNFSv4Operation {
_result.opaccess = res;
return new NFSv4OperationResult(_result, res.status);
context.processedOperations().add(_result);
return res.status == nfsstat4.NFS4_OK;
}
......
......@@ -8,10 +8,7 @@ import org.dcache.chimera.nfs.v4.xdr.nfs_argop4;
import org.dcache.chimera.nfs.v4.xdr.nfs_opnum4;
import org.dcache.chimera.nfs.v4.xdr.CLOSE4res;
import org.dcache.chimera.nfs.ChimeraNFSException;
import org.dcache.xdr.RpcCall;
import org.dcache.chimera.FileSystemProvider;
import org.dcache.chimera.FsInode;
import org.dcache.chimera.nfs.ExportFile;
public class OperationCLOSE extends AbstractNFSv4Operation {
......@@ -23,22 +20,22 @@ public class OperationCLOSE extends AbstractNFSv4Operation {
*/
private final boolean _isPNFS = false;
OperationCLOSE(FileSystemProvider fs, RpcCall call$, CompoundArgs fh, nfs_argop4 args, ExportFile exports) {
super(fs, exports, call$, fh, args, nfs_opnum4.OP_CLOSE);
OperationCLOSE(nfs_argop4 args) {
super(args, nfs_opnum4.OP_CLOSE);
}
@Override
public NFSv4OperationResult process() {
public boolean process(CompoundContext context) {
CLOSE4res res = new CLOSE4res();
try {
FsInode inode = _fh.currentInode();
FsInode inode = context.currentInode();
if( _fh.getSession() == null ) {
if( context.getSession() == null ) {
NFSv4StateHandler.getInstace().updateClientLeaseTime(_args.opclose.open_stateid);