// Original C++ solution (slower):
#include <iostream>

#include <cstdio>

#include <algorithm>

#include <set>

#include <deque>

#include <stack>

#include <bitset>

#include <cstring>

#include <vector>

#include <map>

#include <cmath>

#include <climits>



//find out the use of the below

#include <list>

#include <functional>

#include <numeric>

#include <utility>

#include <sstream>

#include <iomanip>

#include <cstdio>

#include <cstdlib>

#include <ctime>

#include <memory.h>

#include <cassert>



using namespace std;

//using namespace __gnu_pbds;

//typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> set_t;

#define mp(a,b) make_pair((a),(b))

#define LL long long

#define pii pair<int,int>

#define pll pair<LL,LL>

#define pdd pair<double,double>

#define pb push_back

#define x first

#define y second

#define sqr(x) ((x)*(x))

#define EPS 1e-6

#define MEM(x) memset(x,0,sizeof(x))

#define MEMS(x) memset(x,-1,sizeof(x))

#define pi acos(-1)

vector<int> g[(int)1e5+5];

vector<int> gp[(int)1e5+5];



int pr[(int)1e5+5];

int dfs(int u, vector<int>* g){

    if (pr[u] != 0)

        return pr[u];

    int ans = 0;

    for (int v: g[u]){

        ans = max(dfs(v, g), ans);

    }

    return pr[u] = ans+1;

}



int main(){

    //freopen("input.txt", "r", stdin);

    //freopen("output.txt","w", stdout);

    int n, m;

    scanf("%d %d", &n, &m);

    for (int i = 0; i < m; ++i){

        int x, y;

        scanf("%d%d", &x, &y);

        g[x].pb(y);

        gp[y].pb(x);

    }

    int ans = 0;

    for (int i = 0; i < n; ++i){

        if (pr[i+1] == 0){

            ans = max(ans, dfs(i+1, g));

        }

    }

    MEMS(pr);

    for (int i = 0; i < n; ++i){

        if (pr[i+1] == 0){

            ans = max(ans, dfs(i+1, gp));

        }

    }

    cout << ans-1; 

    return 0;

}

/* BEFORE submitting, check for:

 *  1. Integer overflow

 *  2. Float/Double precision errors

 *  3. Array index out of bounds

 *  4. Edge cases.(n=1, n=max, etc.)

 *  5. Time complexity. No TLEs

 */




// Optimized solution to the same problem (faster):
#include <iostream>

#include <cstdio>

#include <algorithm>

#include <set>

#include <deque>

#include <stack>

#include <bitset>

#include <cstring>

#include <vector>

#include <map>

#include <cmath>

#include <climits>



//find out the use of the below

#include <list>

#include <functional>

#include <numeric>

#include <utility>

#include <sstream>

#include <iomanip>

#include <cstdio>

#include <cstdlib>

#include <ctime>

#include <memory.h>

#include <cassert>



using namespace std;

//using namespace __gnu_pbds;

//typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> set_t;

#define mp(a,b) make_pair((a),(b))

#define LL long long

#define pii pair<int,int>

#define pll pair<LL,LL>

#define pdd pair<double,double>

#define pb push_back

#define x first

#define y second

#define sqr(x) ((x)*(x))

#define EPS 1e-6

#define MEM(x) memset(x,0,sizeof(x))

#define MEMS(x) memset(x,-1,sizeof(x))

#define pi acos(-1)

vector<int> g[(int)1e5+5];

int pr[(int)1e5+5];

int dfs(int u, vector<int>* g){

    if (pr[u] != 0)

        return pr[u];

    int ans = 0;

    for (int v: g[u]){

        ans = max(dfs(v, g), ans);

    }

    return pr[u] = ans+1;

}



int main(){

    //freopen("input.txt", "r", stdin);

    //freopen("output.txt","w", stdout);

    int n, m;

    scanf("%d %d", &n, &m);

    for (int i = 0; i < m; ++i){

        int x, y;

        scanf("%d%d", &x, &y);

        g[x].pb(y);

    }

    int ans = 0;

    for (int i = 0; i < n; ++i){

        if (pr[i+1] == 0){

            ans = max(ans, dfs(i+1, g));

        }

    }

    cout << ans-1; 

    return 0;

}

/* BEFORE submitting, check for:

 *  1. Integer overflow

 *  2. Float/Double precision errors

 *  3. Array index out of bounds

 *  4. Edge cases.(n=1, n=max, etc.)

 *  5. Time complexity. No TLEs

 */


// Fastest known solution for this problem: