2017-06-07 1 views
3

In xnu haben wir die Entität vnode_t, die die Datei global darstellt.vnode und Dateideskriptor in xnu, wo wird der Dateioperationsvektor gespeichert

Jeder Prozess kann auf die Datei zugreifen (vorausgesetzt, es richtig Berechtigungen), indem Sie neuen Dateideskriptor und stellen Sie den V-Knoten unter fg_data

fp->f_fglob->fg_data = vp; 

den V-Knoten enthält eine Liste von grundlegenden Aktionen für alle relevanten Vorgänge und gesetzt in Übereinstimmung mit dem FS der Datei. h., der HFS + -Treiber implementiert einen solchen Vektor und setzt seinen V-Knoten entsprechend.

int  (**v_op)(void *);  /* vnode operations vector */ 

Dies ist ein Vektor für Funktionszeiger für alle Aktionen, die auf dem Vnode ausgeführt werden können.

Darüber hinaus haben wir die FileOps Struktur, die Teil der Dateideskriptor (fg_global), die beschreiben, eine minimale Teilmenge dieser Funktionen ist:

Hier ist eine typische Definition:

const struct fileops vnops = { 
.fo_type = DTYPE_VNODE, 
.fo_read = vn_read, 
.fo_write = vn_write, 
.fo_ioctl = vn_ioctl, 
.fo_select = vn_select, 
.fo_close = vn_closefile, 
.fo_kqfilter = vn_kqfilt_add, 
.fo_drain = NULL, 
}; 

und wir legen sie es hier:

fp->f_fglob->fg_ops = &vnops; 

ich sah, dass, wenn reguläre Datei unter lokalem Dateisystem (HFS +) zu lesen, ist es die file_descriptor und nicht der V-Knoten ... wirkt durch

* frame #0: 0xffffff801313c67c kernel`vn_read(fp=0xffffff801f004d98, uio=0xffffff807240be70, flags=0, ctx=0xffffff807240bf10) at vfs_vnops.c:978 [opt] 
frame #1: 0xffffff801339cc1a kernel`dofileread [inlined] fo_read(fp=0xffffff801f004d98, uio=0xffffff807240be70, flags=0, ctx=0xffffff807240bf10) at kern_descrip.c:5832 [opt] 
frame #2: 0xffffff801339cbff kernel`dofileread(ctx=0xffffff807240bf10, fp=0xffffff801f004d98, bufp=140222138463456, nbyte=282, offset=<unavailable>, flags=<unavailable>, retval=<unavailable>) at sys_generic.c:365 [opt] 
frame #3: 0xffffff801339c983 kernel`read_nocancel(p=0xffffff801a597658, uap=0xffffff801a553cc0, retval=<unavailable>) at sys_generic.c:215 [opt] 
frame #4: 0xffffff8013425695 kernel`unix_syscall64(state=<unavailable>) at systemcalls.c:376 [opt] 
frame #5: 0xffffff8012e9dd46 kernel`hndl_unix_scall64 + 22 

Meine Frage ist, warum ist diese Dualität benötigt, und in welchen Fällen die Operation funktioniert durch die file_descriptor Vektor (fg_ops) und welche Fälle die Operation funktioniert durch den V-Knoten-Vektor (VP-> v_op).

dank

Antwort

3

[...], in welchen Fällen der Betrieb des file_descriptor Vektor (fg_ops) wirkt durch und die Fälle der Betrieb des V-Knoten Vektor wirkt durch (VP-> v_op).

ich von der Beantwortung dieser zweiten Teil der Frage beginnen werde zuerst: Wenn Sie Ihre Call-Stack weiter verfolgen durch, und suchen Sie in der vn_read Funktion, werden Sie feststellen, dass es diese Zeile enthält:

error = VNOP_READ(vp, uio, ioflag, ctx); 

die VNOP_READ Funktion (kpi_vfs.c) wiederum hat dies:

_err = (*vp->v_op[vnop_read_desc.vdesc_offset])(&a); 

So ist die Antwort auf Ihre Frage ist, dass für typische Datei, Beide Tabellen werden für Dispatching-Operationen verwendet.

, die mit dem Weg aus,

Meine Frage ist, warum diese Dualität benötigt wird [...]

Nicht alles, an das ein Verfahren zur Herstellung eines Dateideskriptors auch in den dargestellten halten kann, ist Dateisystem. Zum Beispiel müssen Pipes nicht unbedingt benannt werden. Ein V-Knoten macht in diesem Zusammenhang keinen Sinn. Also in sys_pipe.c, Sie sehen eine andere Datei Tabelle:

static const struct fileops pipeops = { 
    .fo_type = DTYPE_PIPE, 
    .fo_read = pipe_read, 
    .fo_write = pipe_write, 
    .fo_ioctl = pipe_ioctl, 
    .fo_select = pipe_select, 
    .fo_close = pipe_close, 
    .fo_kqfilter = pipe_kqfilter, 
    .fo_drain = pipe_drain, 
}; 

Ähnliche Angebote für Sockets.

Dateideskriptoren verfolgen den Status einer Prozessansicht einer Datei oder eines Objekts, die dateiähnliche Operationen ermöglicht. Dinge wie die Position in der Datei usw. - Verschiedene Prozesse können die gleiche Datei geöffnet haben, und sie müssen jeweils ihre eigene Lese-/Schreibposition haben - also ist vnode: fileglob eine 1: viele-Beziehung.

Die Verwendung von Vnode-Objekten zum Verfolgen anderer Objekte als Objekte in einem Dateisystem macht ebenfalls keinen Sinn. Darüber hinaus ist die v_op-Tabelle Dateisystem-spezifisch, während vn_read/VNOP_READ Code enthält, der für jede Datei gilt, die in einem Dateisystem dargestellt wird.

Also zusammenfassend sind sie wirklich nur verschiedene Schichten im I/O-Stapel.

+0

Hallo und danke. nur noch eine Sache. Im Anschluss an Ihre Antwort habe ich weitere Untersuchungen durchgeführt und herausgefunden, dass VNOP_READ 'hfs_vop_read' aufruft, was Teil des HFS + -Treibers ist, der selbst die Cluster-Methode' cluster_read' aufruft, die tatsächlich alle Low-Level-Lesevorgänge (aus dem Cache) ausführt oder von der Platte) .. so weit so gut, aber ich konnte das Synonym in 'mmap' nicht finden, das VNOP_MMAP aufruft, das' hfs_vnop_mmap' aufruft, aber in dieser Funktion, die ENOTSUP zurückgibt "weil wir den Cluster-Layer wollen eigentlich die ganze echte Arbeit machen. " (zitiert aus ihrem Kommentar) ... – osxUser

+0

Dies lässt mich mit der Frage, wer für das Lesen der Datei in mmap Fall verantwortlich ist. Natürlich ist es die Cluster-Schicht, aber wer ruft 'cluster_read' oder etwas Ähnliches aus der mmap Call Trace? – osxUser

Verwandte Themen