2015-10-10 5 views
5

Ich muss 256 KB Text als ein Argument an die "AWS sqs" -Befehl übergeben, aber bin auf ein Limit in der Befehlszeile bei etwa 140Kb laufen. Dies wurde an vielen Stellen diskutiert, dass it been solved in the Linux kernel as of 2.6.23 kernel.Wie umgehen Sie die Linux "Too Many Arguments" -Grenze

Aber kann es nicht zur Arbeit bringen. Ich bin mit 3.14.48-33.39.amzn1.x86_64

Hier ist ein einfaches Beispiel zu testen:

#!/bin/bash 

SIZE=1000 
while [ $SIZE -lt 300000 ] 
do 
    echo "$SIZE" 
    VAR="`head -c $SIZE < /dev/zero | tr '\0' 'a'`" 
    ./foo "$VAR" 
    let SIZE="($SIZE * 20)/19" 
done 

Und das foo Skript ist einfach:

#!/bin/bash 
echo -n "$1" | wc -c 

Und der Ausgang ist für mich:

117037 
123196 
123196 
129680 
129680 
136505 
./testCL: line 11: ./foo: Argument list too long 
143689 
./testCL: line 11: ./foo: Argument list too long 
151251 
./testCL: line 11: ./foo: Argument list too long 
159211 

Also, die Frage, wie ändere ich das testCL Skript ist es kann 256Kb o übergeben f Daten? Btw, ich habe versucht, ulimit -s 65536 zum Skript hinzuzufügen, und es hat nicht geholfen.

Und wenn diese Ebene nicht möglich ist, kann ich damit umgehen, aber können Sie Licht auf diesem Zitat aus meinem obigen Link

„Während Linux nicht 9 Plan ist, in 2.6.23 Linux ist das Hinzufügen variabler Argumentlänge: Theoretisch sollten Sie die Argumente "argument list too long" nicht häufiger treffen, aber dieser Patch begrenzt auch die maximale Argumentlänge von auf 25% des maximalen Stacklimits (ulimit -s). "

Antwort

3

edit:

I konnte schließlich < = 256 KB als ein einzelnes Befehlszeilenargument übergeben (siehe Edit (4) im Boden). Bitte lesen Sie jedoch sorgfältig, wie ich es gemacht habe und entscheiden Sie selbst, ob Sie auf diese Weise gehen möchten. Zumindest sollten Sie in der Lage sein zu verstehen, warum Sie sonst von dem, was ich herausgefunden habe, 'feststecken'.


mit der Kupplung von ARG_MAX zu ulim -s/4 kam die Einführung von MAX_ARG_STRLEN als max. Länge eines Arguments:

/* 
* linux/fs/exec.c 
* 
* Copyright (C) 1991, 1992 Linus Torvalds 
*/ 

...

#ifdef CONFIG_MMU 
/* 
* The nascent bprm->mm is not visible until exec_mmap() but it can 
* use a lot of memory, account these pages in current->mm temporary 
* for oom_badness()->get_mm_rss(). Once exec succeeds or fails, we 
* change the counter back via acct_arg_size(0). 
*/ 

...

static bool valid_arg_len(struct linux_binprm *bprm, long len) 
{ 
return len <= MAX_ARG_STRLEN; 
} 

...

#else 

...

static bool valid_arg_len(struct linux_binprm *bprm, long len) 
{ 
    return len <= bprm->p; 
} 

#endif /* CONFIG_MMU */ 

...

static int copy_strings(int argc, struct user_arg_ptr argv, 
     struct linux_binprm *bprm) 
{ 

...

str = get_user_arg_ptr(argv, argc); 

...

len = strnlen_user(str, MAX_ARG_STRLEN); 
    if (!len) 
     goto out; 

    ret = -E2BIG; 
    if (!valid_arg_len(bprm, len)) 
     goto out; 

...

} 

...

MAX_ARG_STRLEN ist als das 32-fache der Seitengröße in linux/include/uapi/linux/binfmts.h definiert:

...

/* 
* These are the maximum length and maximum number of strings passed to the 
* execve() system call. MAX_ARG_STRLEN is essentially random but serves to 
* prevent the kernel from being unduly impacted by misaddressed pointers. 
* MAX_ARG_STRINGS is chosen to fit in a signed 32-bit integer. 
*/ 
#define MAX_ARG_STRLEN (PAGE_SIZE * 32) 
#define MAX_ARG_STRINGS 0x7FFFFFFF 

...

Die Standard-Seitengröße von 4 KB, so dass Sie keine Argumente mehr als 128 KB passieren können.

Ich kann es jetzt nicht versuchen, aber möglicherweise zu großen Seitenmodus (Seitengröße 4MB) wechseln, wenn möglich auf Ihrem System löst dieses Problem.

Weitere Informationen und Referenzen finden Sie unter this answer bis a similar question on Unix & Linux SE.


Bearbeitungen:

(1) Nach this answer kann man die Seitengröße von x86_64 Linux zu 1MB von CONFIG_TRANSPARENT_HUGEPAGE und CONFIG_TRANSPARENT_HUGEPAGE_MADVISE im Kernel n Einstellung ermöglicht ändern Konfig.

(2) Nach meinem Kernel mit der obigen Konfiguration neu zu kompilieren ändert getconf PAGESIZE gibt noch 4096. Nach this answerCONFIG_HUGETLB_PAGE auch benötigt wird, was ich über CONFIG_HUGETLBFS zieht in konnte. Ich kompiliere jetzt neu und teste es erneut.

(3) neu kompiliert ich meinen Kernel mit CONFIG_HUGETLBFS aktiviert und nun /proc/meminfo enthält die entsprechenden HugePages_* in the corresponding section of the kernel documentation genannten Einträge. Die Seitengröße nach getconf PAGESIZE ist jedoch unverändert. Während ich jetzt in der Lage sein sollte, große Seiten über mmap Aufrufe anzufordern, ist die Standardseitengröße des Kernels, die MAX_ARG_STRLEN bestimmt, immer noch bei 4KB festgelegt.

(4) I modifizierte linux/include/uapi/linux/binfmts.h-#define MAX_ARG_STRLEN (PAGE_SIZE * 64), neu kompiliert mein Kernel und jetzt Ihr Code erzeugt:

...

117037 
123196 
123196 
129680 
129680 
136505 
143689 
151251 
159211 

...

227982 
227982 
239981 
239981 
252611 
252611 
265906 
./testCL: line 11: ./foo: Argument list too long 
279901 
./testCL: line 11: ./foo: Argument list too long 
294632 
./testCL: line 11: ./foo: Argument list too long 

So bewegte sich jetzt das Limit von 128 KB auf 256 KB wie erwartet. Ich weiß jedoch nicht über mögliche Nebenwirkungen. Soweit ich das beurteilen kann, scheint mein System gut zu laufen.

+1

Danke, das ist genau das, wonach ich gefragt habe. In meinem Fall bedeutet das, dass es unmöglich ist (dh keine benutzerdefinierten Kernel ausführen zu können). Aber es ist sehr nützlich, dass ich weiß, dass ich feststecke und warum ich weiß. Übrigens ist die Fehlermeldung "Argumentliste zu lang" irreführend, zumal dieser Teil tatsächlich behoben ist. Es war die Größe eines einzelnen Arguments. – swdev

2

Fügen Sie einfach die Argumente in eine Datei ein und ändern Sie Ihr Programm, um "Argumente" aus einer Datei zu akzeptieren. Eine gemeinsame Konvention (insbesondere durch GCC und mehrere andere GNU-Programme verwendet wird) besteht darin, dass ein Argument wie @/tmp/arglist.txt Ihr Programm fragt lesen Argumente aus der Datei /tmp/arglist.txt, oft eine Zeile pro Argument

Sie vielleicht einige Daten durch lange Umgebungsvariablen passieren könnte, aber sie sind auch begrenzt (und was wird vom Kernel in der Tat ist die Größe der main ‚s Anfangsstapel, die sowohl Programmargumente und die Umgebung begrenzt)

Alternativ ändern sie Ihr Programm durch einige Konfiguration konfigurierbar zu sein Datei, die die Informationen enthalten würde, die Sie durch Argumente übergeben möchten.

(Wenn Sie Ihren Kernel neu kompilieren können, Sie könnten versuchen, -zu einem größeren Zweierpotenz viel kleiner als Ihre verfügbaren RAM zu erhöhen, zum Beispiel die ARG_MAX 2097152- die vor Neukompilierung des Kernels in linux-4.*/include/uapi/linux/limits.h#define -d ist)

In anderer Hinsicht gibt es keine Möglichkeit, diese Einschränkung zu umgehen (execve(2) Manpage und seine Limits auf einer Größe von Argumenten und Umwelt Abschnitt) - sobald Sie Ihr Stapellimit angehoben haben (unter Verwendung von setrlimit(2) mit RLIMIT_STACK, in der Regel mit ulimit in der Parent-Shell eingebaut). Du musst damit anders umgehen.

+0

Das Programm 'foo' kann nicht geändert werden. Ich rufe tatsächlich das AWS SQS-Befehlszeilentool auf, und die Nachricht muss als Wert übergeben werden. – swdev

+2

Dann bist du fest. –

+0

@swdev: Sie müssen die Einschränkungen in Ihrer Frage angeben. Ein anderer Ansatz wäre es, Argumente mit 'xargs' an sqs zu übergeben. – tuxdna

Verwandte Themen