Protokół NFS
Transkrypt
Protokół NFS
Plan wykładu
1. Narzędzie rpcgen.
2. Generowanie programu rozproszonego.
3. Zdalny dostęp a przesyłanie plików.
4. Zasada działania Sieciowego Systemu Plików (NFS)
5. Pliki w systemie UNIX i NFS.
6. Serwer i klient NFS
7. Serwer NFS jako program RPC
●
protokół NFS,
●
protokół montowania,
●
kontrola uprawnień.
8. Podstawy konfiguracji serwera i klienta NFS.
9. Inne rozwiązania: CIFS/SMB.
1
Zastosowanie narzędzia rpcgen
W implementacjach Sun RPC jest dostępne narzędzie pozwalające znacznie
zmniejszyć nakład pracy potrzebny do skonstruowania aplikacji rozproszonej –
rpcgen. Na wejściu otrzymuje on plik specyfikacji zawierający deklaracje
stałych, globalnych typów danych, zmiennych globalnych i zdalnie
wywoływanych procedur. Pliki kodu źródłowego otrzymane na wyjściu to
przede wszystkim procedury łącznikowe dla strony klienta i serwera
zawierający kod realizujący serializację argumentów, wysyłanie i odbieranie
komunikatów RPC, konwersję danych pomiędzy reprezentacją natywną i
zewnętrzną.
2
Procedury produkowane przez
rpcgen
Procedura A
Procedura sprzęgająca
klienta
Komunikacyjna procedura
łącznikowa klienta
Komunikacyjna procedura
łącznikowa serwera
Procedura sprzęgająca
serwera
Procedura B
Procedura łącznikowa zostaje podzielona na część komunikacyjną i
sprzęgającą. Część komunikacyjna jest niemal identyczna dla wszystkich
aplikacji rozproszonych. Część sprzęgająca pełni rolę interfejsu pomiędzy
procedurą komunikacyjną a programem.
3
Pliki na wejściu i wyjściu
programu rpcgen
Nazwa pliku
Zawartość
plik.x
plik wejściowy – specyfikacja zdalnego programu
plik.h
deklaracje typów używanych w wygenerowanym
kodzie.
plik_xdr.c
wywołania procedur XDR używanych przez klienta
i program serwera w celu w celu dokonania
serializacji argumentów.
plik_clnt.c
łącznikowa procedura komunikacyjna strony klienta.
plik_svc.c
łącznikowa procedura komunikacyjna strony
serwera.
4
Pliki na wejściu i wyjściu
programu rpcgen
Program
użytkowy klienta
Procedury
sprzęgająca klienta
plik_clnt.c
plik.h
plik.x
kompilator C
Klient
kompilator C
Serwer
rpcgen
plik_xdr.c
plik_svc.c
Zdalnie wywoływane
procedury
Procedury
sprzęgająca serwera
5
Generowanie programu
rozporszonego (przykład)
Budowanie aplikacji rozproszonej z wykorzystaniem narzędzia rpcgen
odbywa się w ośmiu krokach:
1. Skonstruowanie i przetestowanie zwykłego (działającego lokalnie)
programu użytkowego.
2. Podział programu na część lokalną i zdalną.
3. Napisanie specyfikacji zdalnie wywoływanego programu
wykorzystywanej przez rpcgen.
4. Użycie generatora rpcgen do wyprodukowania plików źródłowych
wykorzystywanych do budowy klienta i serwera.
6
Generowanie programu
rozporszonego (przykład)
5. Implementacja procedur sprzęgających po stronie klienta i serwera.
6. Uzupełnienie, kompilacja i konsolidacja (linkowanie) plików składających
się na program kliencki.
7. Uzupełnienie, kompilacja i konsolidacja (linkowanie) plików składających
się na program serwera.
8. Uruchomienie serwera na komputerze odległym i klienta (jednego lub
wielu) na komputerach lokalnych.
7
Krok 1: program lokalny
Przykładowy program przedstawia prostą implementację dla zbioru słów.
#include<stdio.h>
#define WORDLEN 50
int main(int argc, char **argv){
char cmdline[WORDLEN+3];
char cmd;
int i;
while(1){
scanf("%s", cmdline);
if (strlen(cmdline)<1){
printf("brak komendy\n");
continue;
}
cmd = cmdline[0];
switch(cmd){
case 'I':
i = init();
printf("zbior zainicjowany (%d)\n", i);
break;
8
Krok 1: program lokalny
}
case 'i':
i = insert(cmdline + 2);
printf("wstawiono '%s' (%d)\n", cmdline + 2, i);
break;
case 'd':
i = delete(cmdline + 2);
printf("skasowano '%s' (%d)\n", cmdline + 2, i);
break;
case 'l':
if((i = lookup(cmdline + 2))>=0){
printf("slowo '%s' odnalezione (%d)\n", cmdline + 2, i);
}else{
printf("slowo '%s' nieodnalezione (%d)\n", cmdline + 2, i);
}
break;
case 'q':
printf("koniec pracy\n");
exit(1);
default:
printf("nieznana komenda '%c' \n", cmd);
break;
}// switch
}// while
9
Krok 1: program lokalny
Procedury realizujące poszczególne funkcje programu:
#define SETSIZE 100
char wordset[SETSIZE][WORDLEN+1];
int size = 0;
int init(){
size = 0;
return 1;
}
int insert(char *word){
strcpy(wordset[size], word);
return ++size;
}
int lookup(char *word){
int i, found = -1;
for(i=0; i<size; i++){
if (strcmp(wordset[i], word)==0){
found = i;
break;
}
}
return found;
}
10
Krok 1: program lokalny
int delete(char *word){
int i, j;
i = lookup(word);
if(i>=0){
for (j=i; j<size; j++){
strcpy(wordset[j], wordset[j+1]);
}
size--;
}
return size;
}
Przykładowe komendy wydawane programowi po uruchomieniu:
I
i:jeden
i:dwa
l:jeden
d:jeden
l:jeden
l:dwa
11
Krok 2: podział programu
main
scanf
main
init
insert
lookup
init
insert
lookup
scanf
delete
Dane używane
jako zbiór słów
delete
12
Krok 3: specyfikacja dla rpcgen
Specyfikacja musi zawierać deklaracje: stałych używanych w programie,
typów danych, używanych zdalnych programów i funkcji. Specyfikacja jest
pisana w języku RPC – plik rset.x.
const WORDLEN=50;
const SETSIZE=100;
struct example{ // przykład, obrazujące struktury XDR
int id;
char c;
};
program RSETPROG{
// deklaracja nazwy zdalnego programu
version RSETVERS {
// deklaracja wersji
int INIT(void) = 1;
// deklaracje zdalnych procedur
int INSERT(string) = 2;
int LOOKUP(string) = 3;
int DELETE(string) = 4;
} = 1;
// numer wersji
} = 0x22334455;
// numer programu
13
Krok 3: specyfikacja dla rpcgen
Przestrzeń numerów dla zdalnych programów:
0
– 1fffffff
określone przez firmę Sun
20000000 – 3fffffff
do wykorzystania lokalnego
40000000 – 5fffffff
dla aplikacji wykorzystujących
dynamiczne numerowanie programów
60000000 – 7fffffff
pozostałe adresy są zarezerwowane
80000000 – 9fffffff
do późniejszego wykorzystania
a0000000 – bfffffff
i nie powinny być używane
c0000000 – dfffffff
w programach
e0000000 - ffffffff
14
Krok 4: użycie rpcgen
Program rpcgen na podstawie specyfikacji tworzy pliki źródłowe
wykorzystywane do kompilacji programu klienckiego i serwera. Plik rset.h
zawiera deklaracje używane przez oba programy:
#ifndef _RSET_H_RPCGEN
#define _RSET_H_RPCGEN
#include <rpc/rpc.h>
#ifdef __cplusplus
extern "C" {
#endif
#define WORDLEN 50
#define SETSIZE 100
struct example {
int id;
char c;
};
typedef struct example example;
15
Krok 4: użycie rpcgen
#define RSETPROG 0x22334455
#define RSETVERS 1
#if defined(__STDC__) || defined(__cplusplus)
#define INIT 1
extern int * init_1(void *, CLIENT *);
extern int * init_1_svc(void *, struct svc_req *);
#define INSERT 2
extern int * insert_1(char **, CLIENT *);
extern int * insert_1_svc(char **, struct svc_req *);
#define LOOKUP 3
extern int * lookup_1(char **, CLIENT *);
extern int * lookup_1_svc(char **, struct svc_req *);
#define DELETE 4
extern int * delete_1(char **, CLIENT *);
extern int * delete_1_svc(char **, struct svc_req *);
extern int rsetprog_1_freeresult (SVCXPRT *, xdrproc_t, caddr_t);
16
Krok 4: użycie rpcgen
#else /* K&R C */
// stary styl deklaracji
#define INIT 1
extern int * init_1();
extern int * init_1_svc();
#define INSERT 2
extern int * insert_1();
extern int * insert_1_svc();
#define LOOKUP 3
extern int * lookup_1();
extern int * lookup_1_svc();
#define DELETE 4
extern int * delete_1();
extern int * delete_1_svc();
extern int rsetprog_1_freeresult ();
#endif /* K&R C */
17
Krok 4: użycie rpcgen
/* the xdr functions */
#if defined(__STDC__) || defined(__cplusplus)
extern bool_t xdr_example (XDR *, example*);
#else /* K&R C */
extern bool_t xdr_example ();
#endif /* K&R C */
#ifdef __cplusplus
}
#endif
#endif /* !_RSET_H_RPCGEN */
Zdefiniowane procedury zewnętrzne (np. init_1() i init_1_svc()) są
procedurami łącznikowymi, które powinny być napisane przez programistę.
18
Krok 4: użycie rpcgen
Plik rset_xdr.c jest tworzony gdy w specyfikacji były zdefiniowane
dodatkowe struktury, z których korzysta program.
#include "rset.h"
bool_t
xdr_example (XDR *xdrs, example *objp){
register int32_t *buf;
}
if (!xdr_int (xdrs, &objp->id))
return FALSE;
if (!xdr_char (xdrs, &objp->c))
return FALSE;
return TRUE;
19
Krok 5: procedury łącznikowe
Plik rset_clnt.c zawiera komunikacyjne procedury łącznikowe klienta, np.
int *insert_1(char **argp, CLIENT *clnt){
static int clnt_res;
}
memset((char *)&clnt_res, 0, sizeof(clnt_res));
if (clnt_call (clnt, INSERT,
(xdrproc_t) xdr_wrapstring, (caddr_t) argp,
(xdrproc_t) xdr_int, (caddr_t) &clnt_res,
TIMEOUT) != RPC_SUCCESS) { // wywołanie zdalnej procedury
return (NULL);
}
return (&clnt_res);
Program klienta o definicję procedur łącznikowych. Zwykle definiuje się je w
osobnym pliku rset_cif.c (krok 5).
int insert(char *word){
char **arg;
arg = &word;
return *insert_1(arg, handle);
}
20
Krok 5: procedury łącznikowe
Plik rset_svc.c zawiera kod serwera.
...
char *result;
xdrproc_t _xdr_argument, _xdr_result;
char *(*local)(char *, struct svc_req *);
...
case INSERT:
_xdr_argument = (xdrproc_t) xdr_wrapstring;
_xdr_result = (xdrproc_t) xdr_int;
local = (char *(*)(char *, struct svc_req *)) insert_1_svc;
break;
...
memset ((char *)&argument, 0, sizeof (argument));
if (!svc_getargs (transp, (xdrproc_t)_xdr_argument, (caddr_t)&argument)){
svcerr_decode (transp);
return;
} // pobranie argumentów
result = (*local)((char *)&argument, rqstp); // wywołanie procedury
if (result != NULL && !svc_sendreply(transp, (xdrproc_t)_xdr_result, result)){
svcerr_systemerr (transp);
} // wysłanie odpowiedzi
if (!svc_freeargs (transp, (xdrproc_t) _xdr_argument, (caddr_t) &argument)){
fprintf (stderr, "%s", "unable to free arguments"); exit(1);
21
} // zwolnienie pamięci
Krok 5: procedury łącznikowe
Procedury łącznikowe serwera zazwyczaj grupowane są w osobnym pliku
(rset_sif.c).
#include<rpc/rpc.h>
#include "rset.h"
static int retint;
int *init_1_svc(void *w, struct svc_req *sreq){
retint = init();
return &retint;
}
int *insert_1_svc(char **w, struct svc_req *sreq){
retint = insert(*w);
return &retint;
}
...
22
Krok 6: kompilacja klienta
W pliku źródłowym klienta rset.c należy dodać fragmenty kodu związane z
inicjacją połączenia RPC.
#include<rpc/rpc.h>
#include"rset.h"
#define RMACHINE "komputer.domena"
// nazwa lub adres ip serwera
CLIENT *handle;
// uchwyt wykorzystywany do komunikacji
...
if ((handle=clnt_create(RMACHINE, RSETPROG, RSETVERS, "tcp"))==NULL){
printf("nie mozna nawiazac polaczenia\n");
exit(1);
} // nawiązanie połączenia
Kompilacja i linkowanie:
gcc -o rset rset.c rset_cif.c rset_clnt.c rset_xdr.c
23
Krok 7: kompilacja serwera
Na serwer, oprócz plików wygenerowanych automatycznie: rset_svr.c,
rset_xdr.c i funkcji łącznikowych rset_sif.c i składa się plik zawierający
implementację zdalnych funkcji rset_fun.c.
Kompilacja i linkowanie:
gcc -o rsetd rset_svr.c rset_fun.c rset_sif.c rset_xdr.c
24
Krok 8: testowanie i
uruchomienie programów
Serwer powinien rozpocząć działanie zanim klient nawiąże próbę połączenia.
Zarówno program klienta jak i serwer można w celach testowych uruchomić na
tym samym komputerze. W tym celu należy w programie rset.c zastąpić
istniejącą deklarację przez:
#define RMACHINE "localhost”
Aby ułatwić zarządzanie projektem podczas poprawiania lub wprowadzania
zmian, warto zautomatyzować proces kompilacji za pomocą narzędzia make.
25
Zdalny dostęp a przesyłanie
plików
Wiele wczesnych systemów sieciowych udostępniało użytkownikowi usługi
polegające na przesyłaniu kopii plików pomiędzy komputerami. Nowsze
systemy umożliwiają programom użytkowym zdalny dostęp do plików. Dzięki
temu mechanizmowi można przechowywać jedną kopię dla każdego pliku.
Dostęp do pliku jest możliwy zarówno z tego komputera, na którym plik jest
przechowywany jak i z komputera odległego. Operacja pobrania danych z pliku
lub ich zapisania zlecana przez system operacyjny, na którym działa program
użytkowy, dotyczy zazwyczaj małego bloku pliku. Właśnie tym usługa
zdalnego dostępu różni się od usługi przesyłania plików – jednorazowo są
przesyłane małe bloki danych a nie całe pliki.
26
Sieciowy system plików
Sieciowy system plików – NFS (Network File System) [RFC 1094, 3530]
pozwala wykonywać na plikach odległych te same operacje, które można
wykonać na plikach lokalnych. Tak więc program użytkowy wykonuje operacje
open(), aby otworzyć plik odległy, operacje read(), aby przeczytać z niego
dane, write(), aby zapisać dane, seek(), aby przesunąć wskaźnik położenia
w pliku do określonego miejsca oraz operacje close(), aby zamknąć plik.
27
Dostęp do plików w niejednorodnym
środowisku sieciowym
Oprócz podstawowych operacji, programy realizujące usługę muszą tworzyć
i usuwać pliki, przeszukiwać katalogi, sprawdzać uprawnienia klientów,
zapewniać ochronę plików a także tłumaczyć informacje różnie reprezentowaną
w różnych komputerach.
Protokół NFS zaprojektowano tak, aby mógł działać w niejednorodnym
środowisku systemów komputerowych, pomimo że jego konstrukcja mocno
związana z systemem plików w systemie UNIX. Postarano się o dostosowanie
definiowanych operacji na plikach do wymagań wielu systemów tak dalece, jak
było to możliwe bez nadmiernej komplikacji komplikacji systemu i przy
zachowaniu warunku efektywności działania.
28
Przegląd systemu plików
w systemie UNIX
Z punktu widzenia użytkownika plik jest zdefiniowany jako ponumerowany
ciąg bajtów. Każdy plik ma dokładnie jednego właściciela i należy do dokładnie
jednej grupy. Identyfikatory właściciela i grupy są przechowywane razem z
plikiem. Właściciel może określić oddzielne prawa dostępu do pliku (read,
write, execute) dla siebie, członków grupy i wszystkich pozostałych
użytkowników:
właściciel grupa
inni
1 1 1 1 0 1 1 0 1
=
755
wykonywanie
zapis
odczyt
29
Przegląd systemu plików
w systemie UNIX
UNIX umożliwia współbieżny dostęp do pliku. Dostęp odbywa się za
pośrednictwem struktury danych wskazywanej przez deskryptor pliku.
Każde wywołanie funkcji open() tworzy nową, niezależną strukturę, w której
zapisana jest między innymi informacja o pozycji w pliku. Dzięki oddzieleniu
informacji o pozycji w pliku od pliku możliwy jest współbieżny dostęp wielu
programów użytkowych do jednego pliku bez wzajemnych zakłóceń.
UNIX nie umożliwia wzajemnego wykluczania pomiędzy procesami podczas
korzystania z plików. Jeżeli kilka procesów realizuje zapis tej samej pozycji w
pliku efekt ich działania może zależeć od kolejności w jakiej uzyskały one
dostęp do procesora.
30
Przegląd systemu plików
w systemie UNIX
Katalogi pozwalają wprowadzenie hierarchicznej struktury plików.
/
k1
p2
k2
p3
k4
p1
p4
k3
p5
p6
p7
Prawo czytania katalogu oznacza możliwość uzyskania listy plików
znajdujących się w tym katalogu. Prawo zapisu umożliwia utworzenie nowego
pliku, natomiast prawo wykonywania pozwala odwoływać się do dowolnego
pliku w danym katalogu.
31
Przegląd systemu plików
w systemie UNIX
Montowanie systemu plików.
/
k1
k2
p1
k3
/
/
k4
p2
p3
p4
p5
p6
p7
Mechanizm odwzorowania nazw plików tworzy dla użytkowników i programów
użytkowych jedną, połączoną hierarchię plików, mimo że pliki należące do tej
hierarchii mogą być fizycznie przechowywane na różnych dyskach.
32
Pliki w systemie NFS
Pliki w systemie NFS , podobnie jak pliki UNIX'owe, są widziane przez system
jako ciągi bajtów. Analogicznie są także struktury wykorzystywane do opisu
plików:
enum ftype {
NFNON = 0,
NFREG = 1,
NFDIR = 2,
NFBLK = 3,
NFCHR = 4,
NFLNK = 5
NF3SOCK = 6,
NF3FIFO = 7
};
struct timeval {
unsigned int seconds;
unsigned int useconds;
};
//
//
//
//
//
//
//
//
to nie jest plik
zwykły plik
katalog
urządzenie blokowe (np. dysk)
urządzenie znakowe (np. terminal)
link symboliczny
gniazdo
potok nazwany
// struktura do przekazywania czasu
// liczba sekund od 1 stycznia 1970 r.
// liczba mikrosekund
33
Pliki w systemie NFS
Podobna sytuacja zachodzi także dla atrybutów plików:
struct fattr
ftype
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
unsigned
{
int
int
int
int
int
int
int
type;
mode;
nlink;
uid;
gid;
size;
blocksize;
rdev;
unsigned int blocks;
unsigned int fsid;
unsigned int fileid;
timeval
atime;
timeval
mtime;
timeval
ctime;
};
//
//
//
//
//
//
//
//
//
//
//
//
//
//
typ pliku
rodzaj pliku
liczba twardych dowiązań do pliku
identyfikator właściciela pliku
identyfikator grupy do której należy plik
rozmiar w bajtach
rozmiar bloku w urządzeniu
numer urządzenia jeśli typ pliku to NFCHR
lub NFBLK
rozmiar pliku w blokach
identyfikator systemu plików
identyfikator pliku
czas ostatniego dostępu
czas ostatniej modyfikacji
czas ostatniej modyfikacji informacji
o pliku (i-node)
34
Pliki w systemie NFS
Rodzaj pliku jest sumą logiczną następujących stałych (zapisanych w systemie
ósemkowym):
0040000
0020000
0060000
0100000
0120000
0140000
0004000
0002000
0001000
0000400
0000200
0000100
0000040
0000020
0000010
0000004
0000002
0000001
katalog – typ NFDIR
urządzenie znakowe - typ NFCHR
urządzenie blokowe – typ NFBLK
zwykły plik - typ NFREG
link symboliczny – typ NFLNK
plik specjalny (np. Gniazdo) – typ NFNON
ustaw właściciela w momencie uruchomienia
ustaw grupę w momencie uruchomienia
zapamiętaj tekst z obszaru wymiany po użyciu
prawo read dla właściciela
prawo write dla właściciela
prawo execute dla właściciela
prawo read dla grupy
prawo write dla grupy
prawo execute dla grupy
prawo read dla wszystkich
prawo write dla wszystkich
prawo execute dla wszystkich
35
Serwer i klient NFS
Serwer NFS działa na komputerze, który ma własny lokalny system plików.
Udostępnia on część lokalnych plików komputerom odległym. Większość
implementacji oprogramowania klienckiego zapewnia integrację plików
dostępnych przez NFS z rodzimym systemem plików danego komputera.
funkcja systemowa
np. open()
analiza nazwy ścieżki
kod programu
klienta NFS
kod systemu
zarządzania plikami
36
Klient NFS
Aby programy użytkowe po stronie klienta mogły działać niezależnie od
miejsca przechowywania plików i od właściwości systemów, w których
działają serwery (np. inny format nazw ścieżek), w systemie NFS przyjęto
zasadę, że pełne nazwy ścieżek są interpretowane tylko po stronie klienta.
Klient wysyła do serwera kolejno poszczególne składowe nazwy ścieżki. Dla
każdej składowej otrzymuje w odpowiedzi informację dotyczącą pliku lub
katalogu, z którym ta nazwa składowa jest związana. W ten sposób przebywa
całą ścieżkę w hierarchii katalogów serwera.
Główna wada tego rozwiązania to duża liczba komunikatów przesyłanych
pomiędzy klientem a serwerem.
Główna zaleta to identyczny dostęp do plików zdalnych i lokalnych z punktu
widzenia oprogramowania użytkowego.
37
Uchwyty do plików
Po odnalezieniu i otwarciu pliku klient musi mieć możliwość identyfikacji
tego pliku podczas operacji takich jak odczytywanie czy zapisywanie. W tym
celu w systemie NFS stosuje się 32 bajtowe uchwyty plików (handles).
typedef opaque fhandle[FHSIZE];
Uchwyt pliku dla klienta jest nieprzezroczysty, co oznacza, że klient nie
może sam zdekodować uchwytu ani utworzyć nowego. Uchwyty są tworzone
i rozpoznawane tylko przez serwery. Często w implementacjach NFS
wyposażonych w mechanizmy ochrony, stosuje się skomplikowane sposoby
kodowania uchwytów, aby program kliencki nie mógł “odgadnąć” uchwytu
dla pliku. Dodatkowym zabezpieczeniem może być ograniczenie czasu
ważności uchwytu. Transakcje między klientem a serwerem potrzebne do
uzyskania uchwytu są niewidoczne dla programu użytkowego.
38
Serwer NFS
Serwery NFS są serwerami bezstanowymi. Informacja o stanie interakcji jest
przechowywana po stronie klienta. Dzięki temu przerwy w pracy serwera (lub
sieci) nie muszą mieć wpływu na działanie klienta. Dodatkowo implementacja
serwera staje się prostsza, gdyż nie musi zawierać operacji odtwarzania stanu
serwera po awarii.
W sytuacji gdy dana operacja nie może być zrealizowana w jednym akcie
komunikacji używa się tzw. ,,magic cookie”. Jest to informacja o stanie
interakcji wysyłana klientowi przez serwer. Aby uzyskać dalszą część danych
klient w kolejnym zapytaniu odsyła magic cookie. Klient nie może
interpretować ani sam tworzyć magic cookies. Wykorzystanie tej techniki nie
zapewnia niepodzielności operacji ani wykluczania dostępu!
39
Protokół NFS
program NFS_PROGRAM {
version NFS_VERSION {
void NFSPROC_NULL(void)
attrstat NFSPROC_GETATTR(fhandle)
attrstat NFSPROC_SETATTR(sattrargs)
void NFSPROC_ROOT(void)
diropres NFSPROC_LOOKUP(diropargs)
readlinkres NFSPROC_READLINK(fhandle)
readres NFSPROC_READ(readargs)
void NFSPROC_WRITECACHE(void)
attrstat NFSPROC_WRITE(writeargs)
diropres NFSPROC_CREATE(createargs)
stat NFSPROC_REMOVE(diropargs)
stat NFSPROC_RENAME(renameargs)
stat NFSPROC_LINK(linkargs)
stat NFSPROC_SYMLINK(symlinkargs)
diropres NFSPROC_MKDIR(createargs)
stat NFSPROC_RMDIR(diropargs)
readdirres NFSPROC_READDIR(readdirargs)
statfsres NFSPROC_STATFS(fhandle)
} = 2;
} = 100003;
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
=
0;
1;
2;
3;
4;
5;
6;
7;
8;
9;
10;
11;
12;
13;
14;
15;
16;
17;
40
Protokół NFS
●
void NFSPROC_NULL(void) = 0; procedura wykorzystywana do
testowania czasu odpowiedzi serwera.
attrstat NFSPROC_GETATTR (fhandle) = 1; zwraca strukturę
zawierającą atrybuty pliku określonego przez uchwyt fhandle:
●
union attrstat switch (stat status) {
case NFS_OK:
fattr attributes; // atrybuty
default:
void;
};
●
attrstat NFSPROC_SETATTR (attrargs) = 2; ustawia atrybuty dla
pliku.
struct sattrargs {
fhandle file;
sattr attributes;
};
// uchwyt pliku
// atrybuty
41
Protokół NFS
Struktura attrstat w zależności od stanu (status) zwracane są atrybuty pliku
na którym dokonywano operacji (fattr) lub typ void. Możliwe stany:
enum stat {
NFS_OK
=0, //
NFSERR_PERM
=1, //
NFSERR_NOENT
=2, //
NFSERR_IO
=5, //
NFSERR_NXIO
=6, //
NFSERR_ACCES
=13,//
NFSERR_EXIST
=17,//
NFSERR_NODEV
=19,//
NFSERR_NOTDIR
=20,//
NFSERR_ISDIR
=21,//
NFSERR_FBIG
=27,//
NFSERR_NOSPC
=28,//
NFSERR_ROFS
=30,//
NFSERR_NAMETOOLONG =63,//
NFSERR_NOTEMPTY
=66,//
NFSERR_DQUOT
=69,//
NFSERR_STALE
=70,//
NFSERR_WFLUSH
=99 //
};
procedura wykonana poprawnie
niezgodność lub błąd identyfikatora właściciela
plik lub katalog nie istnieje
wystąpił błąd w urządzeniu we-wy
nie istniejące urządzenie lub adres
odmowa zezwolenia na dostęp
plik o podanej nazwie juz istnieje
wskazane urządzenie nie istnieje
wskazany obiekt nie jest katalogiem
wskazany obiekt jest katalogiem
plik za duży dla serwera
brak miejsca na dysku
próba zapisu do systemu plików tylko do odczytu
za długa nazwa pliku
katalog nie jest pusty
przekroczony limit miejsca na dysku
uchwyt do pliku przeterminowany
bufor zapisu został opróżniony
42
Protokół NFS
Z poziomu klienta NFS ustawiany może być jedynie podzbiór wszystkich
dostępnych atrybutów:
struct sattr
unsigned
unsigned
unsigned
unsigned
timeval
timeval
};
{
int
int
int
int
mode;
uid;
gid;
size;
atime;
mtime;
//
//
//
//
//
//
rodzaj pliku
identyfikator właściciela
grupa do której należy plik
rozmiar pliku w bajtach
czas ostatniego dostępu
czas ostatniej modyfikacji
43
Protokół NFS
void NFSPROC_ROOT(void) = 3; niepotrzebna, zastąpiona przez
MNTPROC_MNT w programie MOUNTPROG.
●
●
diropres NFSPROC_LOOKUP(diropargs) = 4; zwraca strukturę
zawierającą uchwyt oraz atrybuty katalogu lub pliku. Procedura korzysta z
następujących struktur danych:
struct diropargs {
fhandle dir; // uchwyt katalogu
filename name; // nazwa pliku - typedef string filename<MAXNAMLEN>, gdzie
const MAXNAMELEN = 255;
};
union diropres switch (stat status) {
case NFS_OK:
struct {
fhandle file;
// uchwyt katalogu lub pliku
fattr
attributes;
// atrybuty katalogu lub pliku
} diropok;
default:
void;
};
44
Protokół NFS
●
readlinkres NFSPROC_READLINK(fhandle) = 5; zwraca informacje o
linku symbolicznym poprzez strukturę:
union readlinkres switch (stat status) {
case NFS_OK:
path data; // ścieżka do pliku - typedef string path<MAXPATHLEN>,
gdzie const MAXPATHLEN=1024
default:
void;
};
UWAGA: protokół NFS zakłada, że ścieżka jest przetwarzana po stronie klienta.
Ponieważ nie ma zdefiniowanej standardowej notacji sieciowej dla ścieżek, wynik
wywołania tej procedury zależy istotnie od architektury i systemu operacyjnego
serwera NFS.
45
Protokół NFS
readres NFSPROC_READ(readargs) = 6; odczytuje dane z pliku. Korzysta
●
z następujących struktur:
struct readargs {
fhandle file;
unsigned offset;
};
unsigned count;
unsigned totalcount;
// uchwyt pliku
// miejsce, od którego rozpocząć czytanie,
0 - początek pliku
// liczba bajtów do odczytania
// ignorowane, usunięte w kolejnych wersjach
union readres switch (stat status) {
case NFS_OK:
fattr attributes; // atrybuty plikupo odczycie
nfsdata data;
// dane – maksymalnie 8192 bajty
default:
void;
};
●
void NFSPROC_WRITECACHE(void) = 7; do użycia w przyszłych wersjach
protokołu.
46
Protokół NFS
●
attrstat NFSPROC_WRITE(writeargs) = 8; zapisuje dane do pliku.
Argumenty znajdują się w strukturze
struct writeargs {
fhandle file;
unsigned beginoffset;
unsigned offset;
unsigned totalcount;
nfsdata data;
};
//
//
//
//
//
uchwyt do pliku
ignorowane, usunięte w kolejnych wersjach
miejsce, od którego należy rozpocząć zapis
ignorowane, usunięte w kolejnych wersjach
zapisywane dane (maks. 8192 bajty)
Zwracane atrybuty określają stan pliku po operacji WRITE. Zapis musi być
wykonany w sposób niepodzielny. Dane wysyłane przez różnych klientów
wywołujących funkcję WRITE nie mogą zostać zmieszane.
47
Protokół NFS
●
diropres NFSPROC_CREATE(createargs) = 9; tworzy nowy plik zgodnie
z informacją zawartą w strukturze
struct createargs {
diropargs where;
sattr attributes;
};
// miejsce stworzenia pliku
// atrybuty tworzonego pliku
gdzie attributes zawiera atrybuty pliku ustawiane przez klienta. W przypadku
udanego zakończenia operacji zwracany jest uchwyt do stworzonego pliku wraz z
pełnym zestawem atrybutów.
UWAGA: procedura powinna tworzyć plik tylko wtedy gdy on nie istnieje.
48
Protokół NFS
●
stat NFSPROC_REMOVE(diropargs) = 10; usuwa wskazany plik.
●
stat NFSPROC_RENAME(renameargs) = 11; zmienia nazwę pliku.
Argumentem jest struktura
struct renameargs {
diropargs from;
diropargs to;
};
●
stat NFSPROC_LINK(linkargs) = 12; tworzy nowy twardy link do
określonego pliku.
struct linkargs {
fhandle from;
diropargs to;
};
// uchwyt do pliku
// miejsce utworzenia dowiązania symbolicznego
UWAGA: UWAGA: procedury REMOVE, RENAME i LINK nie są indepotentne.
49
Protokół NFS
●
stat NFSPROC_SYMLINK(symlinkargs) = 13; tworzy nowy link
symboliczny do wskazanego pliku.
struct symlinkargs {
diropargs from;
// uchwyt do pliku
path to;
// ścieżka dowiązania
sattr attributes; // atrybuty – mogą być nieużywane w zależności od
systemu operacyjnego
};
●
diropres NFSPROC_MKDIR (createargs) = 14; tworzy nowy katalog i
zwraca jego uchwyt.
●
stat NFSPROC_RMDIR (diropargs) = 15; usuwa wskazany katalog.
UWAGA: procedury MKDIR i RMDIR nie są indepotentne.
50
Protokół NFS
readdirres NFSPROC_READDIR (readdirargs) = 16; zwraca
●
poszczególne pozycje w podanym katalogu. Wykorzystuje struktury:
struct readdirargs {
fhandle dir;
nfscookie cookie;
};
unsigned count;
// uchwyt katalogu
// “magic cookie” (4 bajty). Aby otrzymać wpisy
od początku katalogu należy ustawić wszystkie
bity na 0
// maksymalna liczba zwracanych bajtów
51
Protokół NFS
Na wynik działania READDIR składają się struktury:
struct entry {
unsigned fileid;
filename name;
nfscookie cookie;
};
entry *nextentry;
// unikalny identyfikator pliku
// nazwa pliku
// “magic cookie” wskazujące na następną
pozycję w katalogu
// następny wpis
union readdirres switch (stat status) {
case NFS_OK:
struct {
entry *entries;
// wskaźnik do pierwszego zwróconego wpisu
bool eof;
// TRUE jeśli brak kolejnych wpisów w katalogu
} readdirok;
default:
void;
};
52
Protokół NFS
●
statfsres NFSPROC_STATFS(fhandle) = 17; zwraca informacje o
sieciowym systemie plików.
union statfsres (stat status) {
case NFS_OK:
struct {
unsigned tsize;
// optymalna dla serwera liczba przesyłanych
bajtów dla instrukcji READ i WRITE
unsigned bsize;
// rozmiar bloku w bajtach
unsigned blocks; // całkowita liczba bloków w systemie
unsigned bfree;
// liczba wolnych bloków
unsigned bavail; // liczba bloków dostępnych dla użytkowników
} info;
default:
void;
};
53
Protokół montowania
Protokół montowania współpracuje z serwerem NFS przy nawiązywaniu
połączenia z klientem. W przeciwieństwie do NFS jest on protokołem stanowym.
Służy do sprawdzania ścieżek plików, oraz autoryzacji i uprawnień klienta. Klient
używa tego protokołu aby dostać pierwszy uchwyt do korzenia systemu plików.
program MOUNTPROG {
version MOUNTVERS {
void MOUNTPROC_NULL(void)
=
fhstatus MOUNTPROC_MNT(dirpath)
=
mountlist MOUNTPROC_DUMP(void)
=
void MOUNTPROC_UMNT(dirpath)
=
void MOUNTPROC_UMNTALL(void)
=
exportlist MOUNTPROC_EXPORT(void) =
} = 1;
} = 100005;
0;
1;
2;
3;
4;
5;
54
Protokół montowania
●
void MNTPROC_NULL(void) = 0; służy do testowania serwera.
●
fhstatus MNTPROC_MNT(dirpath) = 1; zwraca uchwyt do zdalnego
katalogu. Używane typy danych:
typedef string dirpath<MNTPATHLEN>; const MNTPATHLEN = 1024;
union fhstatus switch (unsigned status) {
case 0:
fhandle directory;
// uchwyt do katalogu
default:
void;
}
●
mountlist MNTPROC_DUMP(void) = 2; zwraca listę zamontowanych
systemów plików na serwerze.
struct *mountlist {
name
hostname;
dirpath
directory;
mountlist nextentry;
};
// nazwa hosta
// katalog - ścieżka
// wskażnik do następnego wpisu
55
Protokół montowania
●
void MNTPROC_UMNT(dirpath) = 3; odmontowuje wskazany system
plików.
●
void MNTPROC_UMNTALL(void) = 4; odmontowuje wszystkie
zamontowane uprzednio systemy plików.
●
exportlist MNTPROC_EXPORT(void) = 5; zwraca listę dostępnych
systemów plików na serwerze.
struct *groups {
name grname;
groups grnext;
};
// nazwa grupy
// następny element
struct *exportlist {
dirpath filesys;
groups groups;
exportlist next;
};
// system plików
// lista grup, które mogą go importować
// następny element
56
Kontrola uprawnień
Do sprawdzenia uprawnień klienta stosuje się tryb AUTH_UNIX lub AUTH_NONE.
Od Wersji 3 możliwa jest dodatkowo autoryzacja poprzez AUTH_SHORT,
AUTH_DES, oraz AUTH_KERB. W przypadku stosowania trybu AUTH_UNIX serwer
może bezpośrednio określać uprawnienia klienta do poszczególnych katalogów i
plików. W przypadku AUTH_DES i AUTH_KERB musi istnieć dodatkowe
mapowanie (zwykle po stronie serwera) wiążące dane użytkownika z jego
identyfikatorem i grupą używaną w ramach systemu plików.
57
Konfiguracja
Konfiguracja serwera – lista punktów montowania wraz z listą komputerów
mogących korzystać z niego korzystać jest zapisana w pliku /etc/exports.
W zależności od rodzaju systemu UNIX poszczególne linie pliku mogą mieć
postać:
/u1
149.156.74.150(ro,no_root_squash)
/u1
-ro 149.156.74.150
lub
W obu przypadkach użytkownik komputera 149.156.74.150 może ubiegać sie
o dostęp do katalogu /u1 wraz z podkatalogami z prawem czytania. Inne
wybrane opcje
access host[:host]...
root=0
- pełny dostęp (w trybie rw)
- mapuje użytkownika root pod uid=0
-anon=uid
- mapuje użytkownika anonimowego pod uid
58
Konfiguracja
Konfiguracja klienta – w celu zamontowania zdalnego systemu plików klient
wywołuje komendę mount:
mount -o ro -t nfs 149.156.74.170:/u1 /u
Aby montowanie odbywało się automatycznie po uruchomieniu komputera w
pliku /etc/fstab należy umieścić linijkę:
149.156.74.170:/u1
/u
nfs
ro
0 0
59
Inne rozwiązania - CIFS/SMB
CIFS (Common Internet File System) - podstawowe własności:
●
dostęp do plików i drukarek,
●
blokowanie plikow,
●
optymalizacja (read-ahead, write-behind),
●
powiadomienia o zmianach pliku,
●
negocjacja wersji protokołu
●
rozszerzone atrybuty (autor, zawartość),
●
rozproszone replikowalne wirtualne wolumeny
●
korzystanie z DNS,
●
grupowanie żądań.
60
CIFS – schemat działania
CIFS (Common Internet File System):
●
parsowanie nazwy zasobu:
file://fs.corp.com/u/fred/stuff.txt, \\server\public\policy.doc, x:\policy.doc
●
zlokalizowanie serwera,
●
w przypadku korzystania z TCP, nawiązanie połączenia,
●
wymiana komunikatów SMB (Server Message Block).
61
CIFS – schemat działania
SMB_COM_NEGOTIATE - inicjacja komunikacji. Odpowiedź zawiera wybrany
dialekt,
SMB SMB_COM_SESSION_SETUP_ANDX - dane autoryzacyjne klienta.
SMB_COM_TREE_CONNECT – pełna ściżka dostępu do wolumenu.
W odpowiedzi odesłany zostaje jego identyfikator (Tid).
SMB_COM_OPEN - przesłanie lokalizacji zasoby względem wolumenu (Tid).
W odpowiedzi otrzymuje się identyfikator zasobu (Fid).
SMB_COM_READ – klient przesyła Tid, Fid, offset, i liczbe bajtów do odczytu.
SMB_COM_CLOSE – zamknięcie pliku (Fid)
SMB_COM_TREE_DISCONNECT – rozłączenie z wolumenem (Tid).
http://www.snia.org/tech_activities/CIFS/CIFS-TR-1p00_FINAL.pdf
62
CIFS – Implementacja Samba
Samba to serwer umożliwiający dostęp do plików komputerom działającym pod
kontrolą systemu Windows.
Składniki Samby:
smbd - demon umożliwiający współdzielenie plików i drukarek w sieci SMB i
zapewniający uwierzytelnianie klientów SMB (porty 137, 138).
smbd - demon świadczący usługi Windows Internet Name Service (WINS)
i wspomagający przeglądanie zasobów sieci (porty 135, 139 i 445).
Więcej informacji: http://www.samba.org
63
Podsumowanie
Zwykle do konstrukcji programów rozproszonych wykorzystywane jest
narzędzie rpcgen. Proces budowania aplikacji rozproszonej można podzielić na
osiem etapów. Najpierw programista buduje zwykły program lokalny.
Następnie musi on zostać podzielony na część lokalną i zdalną. Program rpcgen
automatycznie generuje większość kodu potrzebnego do obsługi komunikacji
RPC. Pomimo tego konwersją do modelu rozproszonego zwykle jest
pracochłonna i wymaga uwagi.
Protokół NFS umożliwia zdalny dostęp do plików. Za jego pomocą wielu
użytkowników może jednocześnie korzystać ze wspólnych zasobów plikowych.
Pomimo, że koncepcja plików w NFS'ie bazuje na rozwiązaniach znanych
z systemów UNIX może on być używany także w ramach innych systemów.
Specyfikacja NFS opiera się na modelu RPC i wykorzystuje XDR.
64