vmsplice () et TCP

Dans l’ vmsplice() origine de vmsplice() , il a été suggéré que si vous vmsplice() un tampon de données utilisateur double du nombre maximal de pages pouvant tenir dans un tube, une vmsplice () réussie sur la seconde moitié du tampon garantirait que le kernel a été fait en utilisant la première moitié du tampon.

Mais ce n’était pas le cas après tout, et en particulier pour TCP, les pages du kernel seraient conservées jusqu’à la réception de l’ACK de l’autre côté. Corriger cela a été laissé comme travail futur, et donc pour TCP, le kernel devrait toujours copier les pages du tube.

vmsplice() a l’option SPLICE_F_GIFT qui traite ce genre de vmsplice() , mais le problème est que cela expose deux autres problèmes: comment obtenir efficacement de nouvelles pages du kernel et comment réduire la corbeille. Le premier problème est que mmap exige que le kernel efface les pages, et le deuxième problème est que, bien que mmap puisse utiliser la fonctionnalité kscrubd sophistiquée dans le kernel, cela augmente le jeu de travail du processus (mise en cache du cache).

Sur cette base, j’ai ces questions:

  • Quel est l’état actuel de la notification de l’utilisateur sur la réutilisation sécurisée des pages? Je suis particulièrement intéressé par les pages splice () d sur un socket (TCP). Est-ce que quelque chose s’est passé au cours des 5 dernières années?
  • Est-ce que mmap / vmsplice / splice / munmap la meilleure pratique actuelle pour la copie zéro sur un serveur TCP ou avons-nous de meilleures options aujourd’hui?

Oui, du fait que le socket TCP rest sur les pages pour une durée indéterminée, vous ne pouvez pas utiliser le système de double tampon mentionné dans l’exemple de code. De plus, dans mon cas d’utilisation, les pages proviennent d’un tampon circulaire, donc je ne peux pas offrir les pages au kernel et allouer de nouvelles pages. Je peux vérifier que je vois une corruption de données dans les données reçues.

J’ai eu recours à l’interrogation du niveau de la queue d’envoi du socket TCP jusqu’à ce qu’il s’épuise à 0. Cela corrige la corruption des données mais n’est pas optimal car le vidage de la queue d’envoi à 0 affecte le débit.

 n = ::vmsplice(mVmsplicePipe.fd.w, &iov, 1, 0); while (n) { // splice pipe to socket m = ::splice(mVmsplicePipe.fd.r, NULL, mFd, NULL, n, 0); n -= m; } while(1) { int outsize=0; int result; usleep(20000); result = ::ioctl(mFd, SIOCOUTQ, &outsize); if (result == 0) { LOG_NOISE("outsize %d", outsize); } else { LOG_ERR_PERROR("SIOCOUTQ"); break; } //if (outsize <= (bufLen >> 1)) { if (outsize == 0) { LOG("outsize %d <= %u", outsize, bufLen>>1); break; } };