2015-10-10 5 views
5

Мне нужно передать 256 Кбайт текста в качестве аргумента в команду «aws sqs», но я преувеличиваю лимит в командной строке около 140 КБ. Это обсуждалось во многих местах, что it been solved in the Linux kernel as of 2.6.23 kernel.Как обойти ограничение «Слишком много аргументов» Linux

Но не может заставить его работать. Я использую 3.14.48-33.39.amzn1.x86_64

Вот простой пример теста:

#!/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 

И foo сценарий просто:

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

И выход для меня:

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 

Итак, вопрос, как мне изменить скрипт testCL, может пройти 256 Кб o f данных? Кстати, я попытался добавить ulimit -s 65536 к скрипту, и это не помогло.

И если это ясно, невозможно, я могу справиться с этим, но вы можете пролить свет на эту цитату из моей ссылке выше

«В то время как Linux не Plan 9, в 2.6.23 Linux является добавление переменной длина аргумента. Теоретически вам не следует часто удалять «аргумент слишком длинный список ошибок», но этот патч также ограничивает максимальную длину аргумента до 25% максимального предела стека (ulimit -s) ».

ответ

3

редактировать:

я, наконец, смог пройти < = 256Кб как единый аргумент командной строки (см редактирования (4) в нижней части). Однако, пожалуйста, внимательно прочитайте, как я это сделал, и решите сами, если это так, как вы хотите. По крайней мере, вы должны понимать, почему вы «застреваете» иначе, чем я узнал.


С сцеплением ARG_MAX к ulim -s/4 пришел введение MAX_ARG_STRLEN как макс. длина аргумента:

/* 
* 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 определяется как 32 раз размер страницы в linux/include/uapi/linux/binfmts.h:

...

/* 
* 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 

...

размер страницы по умолчанию 4KB, так что вы не можете передать аргументы больше, чем 128KB.

Я не могу попробовать это сейчас, но, возможно, переключение на огромный режим страницы (размер страницы 4 МБ), если это возможно, на вашей системе решает эту проблему.

Для получения более подробной информации и ссылок см. this answer - a similar question on Unix & Linux SE.


редактирует:

(1) По this answer можно изменить размер страницы x86_64 Linux до 1 МБ, позволяя CONFIG_TRANSPARENT_HUGEPAGE и установка CONFIG_TRANSPARENT_HUGEPAGE_MADVISE в n в ядре конфигурации.

(2) Перекомпилировав мое ядро ​​с выше изменениями конфигурации getconf PAGESIZE еще возвращает 4096. По this answerCONFIG_HUGETLB_PAGE также необходимы, который я мог бы тянуть через CONFIG_HUGETLBFS. Я перекомпиляю сейчас и снова проверю.

(3) Я пересобрал ядро ​​с поддержкой CONFIG_HUGETLBFS и теперь /proc/meminfo содержит соответствующие HugePages_* записей, указанных в the corresponding section of the kernel documentation. Однако размер страницы в соответствии с getconf PAGESIZE по-прежнему не изменился. Поэтому, хотя я могу теперь запросить огромные страницы с помощью вызовов mmap, размер страницы по умолчанию для ядра MAX_ARG_STRLEN по-прежнему фиксирован на уровне 4 КБ.

(4) Я изменил linux/include/uapi/linux/binfmts.h к #define MAX_ARG_STRLEN (PAGE_SIZE * 64), пересобрал ядро ​​и теперь ваш код производит:

...

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 

Так что теперь предел переместился с 128 КБ до 256 КБ, как и ожидалось. Хотя я не знаю о потенциальных побочных эффектах. Насколько я могу судить, моя система работает нормально.

+1

Спасибо, это именно то, о чем я просил. В моем случае это означает, что это невозможно (т. Е. Не может запускать пользовательские ядра). Но очень полезно знать, что я застрял и знаю ** почему **. Кстати, сообщение об ошибке «Список аргументов слишком велико» вводит в заблуждение, особенно потому, что эта часть фактически исправлена. Это вопрос индивидуального аргумента. – swdev

2

Просто поместите аргументы в некоторый файл и измените свою программу, чтобы принять «аргументы» из файла. Общая конвенция (в частности, используется GCC и несколько других программ GNU) является то, что аргумент, как @/tmp/arglist.txt просит ваша программу для чтения аргументов из файла /tmp/arglist.txt, часто по одной строке на аргумент

Вы могли бы, возможно, передать некоторые данные через переменную длиной среды, но они также ограничены (и то, что ограничивается ядром фактически является размер начального стека main «s, содержащая оба аргумента программы и окружающей среды)

в качестве альтернативы, изменить программу, чтобы быть настраиваемым через какой-то конфигурации файл, который будет содержать информацию, которую вы хотите передать через аргументы.

(Если вы можете пересобрать ядро, вы можете попытаться увеличить -в большей степени двойки гораздо меньше доступной оперативной памяти, например, для 2097152- в ARG_MAX, который #define -d в linux-4.*/include/uapi/linux/limits.h до перекомпиляции ядра)

в других отношениях, не существует никакого способа обойти это ограничение (см execve(2) страницу человека и его ограничения на размер аргументов и окружающей среды раздела) - как только вы подняли лимит стека (с помощью setrlimit(2) с RLIMIT_STACK, как правило, с ulimit, встроенным в родительскую оболочку). Вам нужно иметь дело с этим в противном случае.

+0

Невозможно изменить программу 'foo'. Я действительно вызываю инструмент командной строки AWS SQS, и сообщение должно передаваться как значение. – swdev

+2

Тогда вы застряли. –

+0

@swdev: вам нужно указать ограничения в своем вопросе. Другим подходом было бы передать аргументы sqs с помощью 'xargs'. – tuxdna

Смежные вопросы